From da20281605ae1d13b3cda97dddfd66347e56d998 Mon Sep 17 00:00:00 2001 From: Jan Zerebecki Date: Thu, 23 Aug 2007 11:46:20 +0200 Subject: [PATCH] Changes in crossover-wine-src-6.1.0 except for configure (which can be regenerated with autoconf). --- Make.rules.in | 8 +- Makefile.in | 17 + configure.ac | 208 +++++-- dlls/Makefile.in | 7 +- dlls/advapi32/security.c | 44 +- dlls/cabinet/fdi.c | 1 + dlls/cfgmgr32/main.c | 7 +- dlls/comctl32/imagelist.c | 8 +- dlls/comctl32/listview.c | 2 - dlls/comctl32/monthcal.c | 21 +- dlls/comctl32/progress.c | 1 + dlls/comctl32/propsheet.c | 18 + dlls/comctl32/tests/propsheet.c | 35 ++ dlls/comctl32/theming.c | 10 +- dlls/d3d9/d3d9_private.h | 11 +- dlls/d3d9/device.c | 88 ++- dlls/d3d9/directx.c | 15 +- dlls/d3d9/tests/visual.c | 7 - dlls/d3d9/vertexdeclaration.c | 36 +- dlls/ddraw/ddraw.c | 126 +++- dlls/ddraw/ddraw.spec | 2 + dlls/ddraw/ddraw_private.h | 3 + dlls/ddraw/direct3d.c | 1 + dlls/ddraw/main.c | 11 +- dlls/ddrawex/main.c | 8 +- dlls/dsound/dsound_private.h | 1 + dlls/dsound/primary.c | 32 +- dlls/gdi32/Makefile.in | 2 +- dlls/gdi32/driver.c | 2 + dlls/gdi32/font.c | 56 +- dlls/gdi32/freetype.c | 804 +++++++++++++++++++------ dlls/gdi32/mfdrv/text.c | 66 +-- dlls/gdi32/palette.c | 12 + dlls/hlink/Makefile.in | 5 +- dlls/hlink/hlink.spec | 2 +- dlls/hlink/hlink_main.c | 41 -- dlls/hlink/link.c | 15 +- dlls/imm32/imm.c | 17 + dlls/kernel32/Makefile.in | 1 + dlls/kernel32/file.c | 8 +- dlls/kernel32/kernel32.spec | 28 +- dlls/kernel32/kernel_main.c | 14 +- dlls/kernel32/kernel_private.h | 7 + dlls/kernel32/sync.c | 19 +- dlls/kernel32/tests/time.c | 126 +++- dlls/kernel32/time.c | 819 ++++++++++++++++++++++++++ dlls/kernel32/volume.c | 28 +- dlls/kernel32/vxd.c | 9 + dlls/msdmo/dmoreg.c | 2 +- dlls/mshtml/htmlbody.c | 89 +-- dlls/mshtml/htmltextcont.c | 6 +- dlls/mshtml/install.c | 32 +- dlls/mshtml/mshtml.inf | 9 +- dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/navigate.c | 30 +- dlls/mshtml/nsio.c | 19 +- dlls/mshtml/olecmd.c | 26 + dlls/mshtml/persist.c | 102 ++-- dlls/msi/action.c | 20 + dlls/msi/custom.c | 24 +- dlls/msi/font.c | 4 +- dlls/msi/helpers.c | 19 +- dlls/msi/install.c | 6 +- dlls/msi/msi.c | 47 +- dlls/msi/msi_main.c | 2 + dlls/msi/msipriv.h | 2 + dlls/msi/package.c | 11 + dlls/msnet32/msnet32.spec | 2 +- dlls/msvcrt/math.c | 14 +- dlls/ntdll/directory.c | 224 ++++++- dlls/ntdll/file.c | 20 + dlls/ntdll/nt.c | 41 +- dlls/ntdll/ntdll_misc.h | 14 +- dlls/ntdll/path.c | 50 +- dlls/ntdll/relay.c | 6 + dlls/ntdll/server.c | 17 + dlls/ntdll/signal_i386.c | 20 +- dlls/ntdll/sync.c | 53 +- dlls/ntdll/thread.c | 1 + dlls/ntdll/version.c | 58 +- dlls/ntdll/virtual.c | 163 +++++- dlls/ole32/Makefile.in | 4 + dlls/ole32/compobj.c | 5 +- dlls/ole32/defaulthandler.c | 71 ++- dlls/ole32/ole2.c | 15 +- dlls/ole32/ole32.spec | 2 +- dlls/ole32/oleproxy.c | 40 +- dlls/ole32/rpc.c | 2 +- dlls/ole32/stg_bigblockfile.c | 9 + dlls/ole32/usrmarshal.c | 905 +++++++++++++++++++++++++++++ dlls/oleaut32/Makefile.in | 1 + dlls/oleaut32/oaidl_p.c | 22 + dlls/oleaut32/oleaut.c | 16 +- dlls/oleaut32/regsvr.c | 3 - dlls/oleaut32/typelib.h | 2 + dlls/oleaut32/usrmarshal.c | 187 ++++++ dlls/oleaut32/vartype.c | 41 +- dlls/opengl32/wgl.c | 58 +- dlls/pstorec/pstorec.c | 296 ++++++++-- dlls/riched20/editor.c | 27 +- dlls/riched20/string.c | 2 + dlls/riched20/tests/editor.c | 172 ++++-- dlls/riched20/txtsrv.c | 4 + dlls/rpcrt4/Makefile.in | 7 +- dlls/rpcrt4/epm_towers.h | 14 +- dlls/rpcrt4/ndr_marshall.c | 787 +++++++++++++++++++++++-- dlls/rpcrt4/ndr_stubless.c | 72 ++- dlls/rpcrt4/rpc_binding.c | 38 +- dlls/rpcrt4/rpc_defs.h | 10 + dlls/rpcrt4/rpc_epmap.c | 117 +++- dlls/rpcrt4/rpc_message.c | 370 +++++++++++- dlls/rpcrt4/rpc_message.h | 9 + dlls/rpcrt4/rpc_transport.c | 638 +++++++++++++++++++- dlls/rpcrt4/rpcrt4.spec | 3 +- dlls/rpcrt4/tests/ndr_marshall.c | 279 +++++++++ dlls/sane.ds/capability.c | 11 +- dlls/secur32/dispatcher.c | 2 +- dlls/secur32/ntlm.c | 32 +- dlls/setupapi/Makefile.in | 6 +- dlls/setupapi/devinst.c | 229 ++++---- dlls/setupapi/dirid.c | 1 + dlls/setupapi/setupapi_private.h | 47 ++ dlls/shdocvw/Makefile.in | 2 + dlls/shdocvw/dochost.c | 1 + dlls/shdocvw/navigate.c | 17 +- dlls/shdocvw/regsvr.c | 25 +- dlls/shdocvw/shdocvw.h | 2 + dlls/shdocvw/shdocvw.rc | 3 + dlls/shell32/Makefile.in | 2 + dlls/shell32/debughlp.c | 129 +++- dlls/shell32/pidl.c | 237 +++++--- dlls/shell32/pidl.h | 7 +- dlls/shell32/shell32.spec | 2 + dlls/shell32/shell32_En.rc | 8 +- dlls/shell32/shell32_main.c | 3 + dlls/shell32/shell32_main.h | 2 + dlls/shell32/shelllink.c | 37 +- dlls/shell32/shellole.c | 1 + dlls/shell32/shellord.c | 6 +- dlls/shell32/shellpath.c | 355 ++++++++--- dlls/shell32/shfldr_desktop.c | 61 +- dlls/shell32/shfldr_fs.c | 40 +- dlls/shell32/shfldr_mycomp.c | 122 +++- dlls/shell32/shfldr_unixfs.c | 13 +- dlls/shell32/shlexec.c | 160 ++++- dlls/shell32/shlfileop.c | 35 +- dlls/shell32/shlfolder.c | 22 +- dlls/shell32/shlview.c | 14 +- dlls/shell32/shresdef.h | 4 + dlls/shell32/version.h | 10 +- dlls/shlwapi/shlwapi.spec | 2 +- dlls/user32/button.c | 4 +- dlls/user32/combo.c | 13 + dlls/user32/cursoricon.c | 15 + dlls/user32/edit.c | 80 ++- dlls/user32/menu.c | 32 + dlls/user32/message.c | 41 +- dlls/user32/msgbox.c | 6 + dlls/user32/painting.c | 5 +- dlls/user32/scroll.c | 6 + dlls/user32/tests/msg.c | 30 +- dlls/user32/tests/win.c | 67 ++- dlls/user32/win.c | 43 ++ dlls/user32/winpos.c | 6 +- dlls/user32/winproc.c | 2 +- dlls/usp10/usp10.c | 16 +- dlls/vmm.vxd/vmm.c | 8 +- dlls/wineaudioio.drv/Makefile.in | 1 + dlls/winecoreaudio.drv/audio.c | 9 + dlls/winecoreaudio.drv/audiounit.c | 26 +- dlls/wined3d/context.c | 8 + dlls/wined3d/device.c | 52 +- dlls/wined3d/directx.c | 56 +- dlls/wined3d/drawprim.c | 23 +- dlls/wined3d/indexbuffer.c | 2 +- dlls/wined3d/surface.c | 125 +++- dlls/wined3d/surface_gdi.c | 50 ++ dlls/wined3d/swapchain.c | 12 +- dlls/wined3d/vertexshader.c | 6 + dlls/wined3d/volume.c | 6 +- dlls/wined3d/wined3d_main.c | 60 ++ dlls/wined3d/wined3d_private.h | 14 +- dlls/wineoss.drv/Makefile.in | 2 +- dlls/wineoss.drv/audio.c | 64 ++ dlls/wineps.drv/generic.ppd | 2 +- dlls/wineps.drv/init.c | 6 +- dlls/wineps.drv/ppd.c | 74 ++- dlls/wineps.drv/truetype.c | 16 +- dlls/winex11.drv/Makefile.in | 4 +- dlls/winex11.drv/bitblt.c | 5 + dlls/winex11.drv/dce.c | 26 +- dlls/winex11.drv/dib.c | 110 ++-- dlls/winex11.drv/event.c | 48 +- dlls/winex11.drv/keyboard.c | 34 +- dlls/winex11.drv/mouse.c | 56 +- dlls/winex11.drv/opengl.c | 48 +- dlls/winex11.drv/window.c | 527 +++++++++++++++-- dlls/winex11.drv/winex11.drv.spec | 3 + dlls/winex11.drv/winpos.c | 346 ++++++++++- dlls/winex11.drv/x11drv.h | 61 +- dlls/winex11.drv/x11drv_main.c | 118 +++- dlls/winex11.drv/xfont.c | 30 +- dlls/winex11.drv/xim.c | 30 +- dlls/winex11.drv/xrender.c | 81 ++- dlls/wininet/Makefile.in | 2 +- dlls/wininet/http.c | 328 ++++++++++- dlls/wininet/internet.c | 8 + dlls/wininet/internet.h | 4 + dlls/wininet/netconnection.c | 36 +- dlls/wininet/utility.c | 23 +- dlls/winspool.drv/info.c | 74 ++- dlls/winspool.drv/wspool.c | 6 + include/Makefile.in | 2 + include/config.h.in | 9 + include/wine/server_protocol.h | 6 +- include/wine/wined3d_caps.h | 6 + include/wine/wined3d_gl.h | 7 +- libs/wine/collation.c | 60 +- libs/wine/ldt.c | 4 + loader/Makefile.in | 4 +- loader/main.c | 7 +- loader/preloader.c | 2 +- programs/Makefile.in | 23 +- programs/explorer/systray.c | 26 +- programs/regedit/Pt.rc | 38 ++ programs/regedit/regedit.c | 14 + programs/regedit/regproc.c | 21 +- programs/taskmgr/taskmgr.c | 10 +- programs/taskmgr/taskmgr.rc | 1 + programs/uninstaller/Makefile.in | 3 +- programs/wineboot/shutdown.c | 7 + programs/wineboot/wineboot.c | 25 +- programs/winebrowser/main.c | 5 + programs/winecfg/Pt.rc | 65 +++ programs/wineconsole/wineconsole_Pt.rc | 2 +- programs/winemenubuilder/winemenubuilder.c | 675 +++++++++++++++------ 236 files changed, 11990 insertions(+), 1849 deletions(-) diff --git a/Make.rules.in b/Make.rules.in index 02df1711656..173e6c1bb76 100644 --- a/Make.rules.in +++ b/Make.rules.in @@ -125,7 +125,7 @@ LINTS = $(C_SRCS:.c=.ln) # Implicit rules -.SUFFIXES: .mc .rc .mc.rc .res .res.o .spec .spec.o .idl .tlb .h .y .l .tab.c .tab.h .yy.c .ok .sfd .ttf .man.in .man _c.c _i.c _p.c _s.c +.SUFFIXES: .mc .rc .mc.rc .res .res.o .spec .spec.o .idl .tlb .h .y .l .tab.c .tab.h .yy.c .ok .sfd .ttf .man.in .man _i.c _s.c .c.o: $(CC) -c $(ALLCFLAGS) -o $@ $< @@ -157,15 +157,9 @@ LINTS = $(C_SRCS:.c=.ln) .idl.h: $(WIDL) $(IDLFLAGS) -h -H $@ $< -.idl_c.c: - $(WIDL) $(IDLFLAGS) -c -C $@ $< - .idl_i.c: $(WIDL) $(IDLFLAGS) -u -U $@ $< -.idl_p.c: - $(WIDL) $(IDLFLAGS) -p -P $@ $< - .idl_s.c: $(WIDL) $(IDLFLAGS) -s -S $@ $< diff --git a/Makefile.in b/Makefile.in index 5c581630085..d31e08a4f8c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -87,6 +87,11 @@ install install-lib:: $(INSTALLLIBSUBDIRS:%=%/__install__) $(INSTALLBOTHSUBDIRS: install install-dev:: $(INSTALLDEVSUBDIRS:%=%/__install__) $(INSTALLBOTHSUBDIRS:%=%/__install-dev__) +install-image: install-lib +# Get rid of the files we don't want in the image + $(RM) $(DESTDIR)$(bindir)/wineprefixcreate $(DESTDIR)$(bindir)/winelauncher + $(RM) -r $(DESTDIR)$(mandir) $(DESTDIR)$(datadir)/applications + uninstall:: $(INSTALLBOTHSUBDIRS:%=%/__uninstall__) $(RM) $(DESTDIR)$(datadir)/aclocal/wine.m4 -rmdir $(DESTDIR)$(datadir)/wine $(DESTDIR)$(datadir)/aclocal @@ -158,6 +163,7 @@ ALL_MAKEFILES = \ programs/Makeprog.rules \ dlls/Makefile \ dlls/activeds/Makefile \ + dlls/actxprxy/Makefile \ dlls/advapi32/Makefile \ dlls/advapi32/tests/Makefile \ dlls/advpack/Makefile \ @@ -197,6 +203,7 @@ ALL_MAKEFILES = \ dlls/d3dx8/Makefile \ dlls/d3dxof/Makefile \ dlls/dbghelp/Makefile \ + dlls/dcapvxd.vxd/Makefile \ dlls/dciman32/Makefile \ dlls/ddraw/Makefile \ dlls/ddraw/tests/Makefile \ @@ -239,10 +246,13 @@ ALL_MAKEFILES = \ dlls/hlink/tests/Makefile \ dlls/iccvid/Makefile \ dlls/icmp/Makefile \ + dlls/ieinfo5.ocx/Makefile \ + dlls/iernonce/Makefile \ dlls/ifsmgr.vxd/Makefile \ dlls/imaadp32.acm/Makefile \ dlls/imagehlp/Makefile \ dlls/imm32/Makefile \ + dlls/inetcomm/Makefile \ dlls/infosoft/Makefile \ dlls/infosoft/tests/Makefile \ dlls/inseng/Makefile \ @@ -287,6 +297,7 @@ ALL_MAKEFILES = \ dlls/msisys.ocx/Makefile \ dlls/msnet32/Makefile \ dlls/msrle32/Makefile \ + dlls/msvcirt/Makefile \ dlls/msvcrt/Makefile \ dlls/msvcrt/tests/Makefile \ dlls/msvcrt20/Makefile \ @@ -498,6 +509,7 @@ programs/Makeprog.rules: programs/Makeprog.rules.in Make.rules Makefile: Makefile.in Make.rules dlls/Makefile: dlls/Makefile.in Make.rules dlls/activeds/Makefile: dlls/activeds/Makefile.in dlls/Makedll.rules +dlls/actxprxy/Makefile: dlls/actxprxy/Makefile.in dlls/Makedll.rules dlls/advapi32/Makefile: dlls/advapi32/Makefile.in dlls/Makedll.rules dlls/advapi32/tests/Makefile: dlls/advapi32/tests/Makefile.in dlls/Maketest.rules dlls/advpack/Makefile: dlls/advpack/Makefile.in dlls/Makedll.rules @@ -537,6 +549,7 @@ dlls/d3drm/Makefile: dlls/d3drm/Makefile.in dlls/Makedll.rules dlls/d3dx8/Makefile: dlls/d3dx8/Makefile.in dlls/Makedll.rules dlls/d3dxof/Makefile: dlls/d3dxof/Makefile.in dlls/Makedll.rules dlls/dbghelp/Makefile: dlls/dbghelp/Makefile.in dlls/Makedll.rules +dlls/dcapvxd.vxd/Makefile: dlls/dcapvxd.vxd/Makefile.in dlls/Makedll.rules dlls/dciman32/Makefile: dlls/dciman32/Makefile.in dlls/Makedll.rules dlls/ddraw/Makefile: dlls/ddraw/Makefile.in dlls/Makedll.rules dlls/ddraw/tests/Makefile: dlls/ddraw/tests/Makefile.in dlls/Maketest.rules @@ -579,10 +592,13 @@ dlls/hlink/Makefile: dlls/hlink/Makefile.in dlls/Makedll.rules dlls/hlink/tests/Makefile: dlls/hlink/tests/Makefile.in dlls/Maketest.rules dlls/iccvid/Makefile: dlls/iccvid/Makefile.in dlls/Makedll.rules dlls/icmp/Makefile: dlls/icmp/Makefile.in dlls/Makedll.rules +dlls/ieinfo5.ocx/Makefile: dlls/ieinfo5.ocx/Makefile.in dlls/Makedll.rules +dlls/iernonce/Makefile: dlls/iernonce/Makefile.in dlls/Makedll.rules dlls/ifsmgr.vxd/Makefile: dlls/ifsmgr.vxd/Makefile.in dlls/Makedll.rules dlls/imaadp32.acm/Makefile: dlls/imaadp32.acm/Makefile.in dlls/Makedll.rules dlls/imagehlp/Makefile: dlls/imagehlp/Makefile.in dlls/Makedll.rules dlls/imm32/Makefile: dlls/imm32/Makefile.in dlls/Makedll.rules +dlls/inetcomm/Makefile: dlls/inetcomm/Makefile.in dlls/Makedll.rules dlls/infosoft/Makefile: dlls/infosoft/Makefile.in dlls/Makedll.rules dlls/infosoft/tests/Makefile: dlls/infosoft/tests/Makefile.in dlls/Maketest.rules dlls/inseng/Makefile: dlls/inseng/Makefile.in dlls/Makedll.rules @@ -627,6 +643,7 @@ dlls/msimg32/Makefile: dlls/msimg32/Makefile.in dlls/Makedll.rules dlls/msisys.ocx/Makefile: dlls/msisys.ocx/Makefile.in dlls/Makedll.rules dlls/msnet32/Makefile: dlls/msnet32/Makefile.in dlls/Makedll.rules dlls/msrle32/Makefile: dlls/msrle32/Makefile.in dlls/Makedll.rules +dlls/msvcirt/Makefile: dlls/msvcirt/Makefile.in dlls/Makedll.rules dlls/msvcrt/Makefile: dlls/msvcrt/Makefile.in dlls/Makedll.rules dlls/msvcrt/tests/Makefile: dlls/msvcrt/tests/Makefile.in dlls/Maketest.rules dlls/msvcrt20/Makefile: dlls/msvcrt20/Makefile.in dlls/Makedll.rules diff --git a/configure.ac b/configure.ac index 066a2890142..5f3290454fe 100644 --- a/configure.ac +++ b/configure.ac @@ -12,13 +12,26 @@ AC_CONFIG_AUX_DIR(tools) dnl **** Command-line arguments **** +AC_CANONICAL_HOST + AC_ARG_ENABLE(win16, AC_HELP_STRING([--disable-win16],[do not include Win16 support])) AC_ARG_ENABLE(win64, AC_HELP_STRING([--enable-win64], [build a Win64 emulator on AMD64 (won't run Win32 binaries)])) AC_ARG_WITH(opengl, AC_HELP_STRING([--without-opengl],[do not use OpenGL])) AC_ARG_WITH(wine-tools,AC_HELP_STRING([--with-wine-tools=],[use Wine tools from directory ])) -AC_CANONICAL_HOST +case $host_os in + darwin*|macosx*) default_with_xml="native" ;; + *) default_with_xml="builtin" ;; +esac + +AC_ARG_WITH(xml,AC_HELP_STRING([--with-xml=],[builtin or native (default is builtin, except on Mac OS X)]), + [ if test "$with_xml" != "native" -a "$with_xml" != "builtin" ; then + with_xml="$default_with_xml" + fi + ], + [with_xml="$default_with_xml"]) + case $host in x86_64*linux*) if test "x$enable_win64" != "xyes" @@ -128,7 +141,12 @@ AC_SUBST(LINTFLAGS) dnl Check for various programs AC_CHECK_PROGS(FONTFORGE, fontforge, false) -AC_CHECK_PROGS(PKG_CONFIG, pkg-config, false) + +# pkg-config is of no help and some harm on Mac OS X +case $host_os in + darwin*|macosx*) PKG_CONFIG="false" ;; + *) AC_CHECK_PROGS(PKG_CONFIG, pkg-config, false) ;; +esac case $host_cpu in *i[[3456789]]86*) @@ -173,7 +191,6 @@ AC_CHECK_HEADERS(\ dlfcn.h \ elf.h \ float.h \ - fontconfig/fontconfig.h \ getopt.h \ ieeefp.h \ io.h \ @@ -264,6 +281,7 @@ AC_CHECK_HEADERS(\ termios.h \ unicode/ubidi.h \ unistd.h \ + usb.h \ utime.h \ valgrind/memcheck.h ) @@ -325,6 +343,8 @@ AC_CHECK_HEADERS([linux/capi.h],,,[#define __user]) dnl **** Check for X11 **** +AC_SUBST(FONTCONFIGINCL, "") + if test "$have_x" = "yes" then XLIB="-lXext -lX11" @@ -336,6 +356,7 @@ then X11/XKBlib.h \ X11/Xutil.h \ X11/Xcursor/Xcursor.h \ + X11/extensions/applewm.h \ X11/extensions/shape.h \ X11/extensions/XInput.h \ X11/extensions/XShm.h \ @@ -358,6 +379,15 @@ then $X_LIBS -lXext -lX11 $X_EXTRA_LIBS) fi + dnl *** Check for X AppleWM extension + if test "$ac_cv_header_X11_extensions_applewm_h" = "yes" + then + AC_CHECK_LIB(AppleWM, XAppleWMQueryExtension, + [AC_DEFINE(HAVE_LIBAPPLEWM, 1, [Define if you have the X AppleWM extension]) + X_EXTRA_LIBS="$X_EXTRA_LIBS -lAppleWM"],, + $X_LIBS -lXext -lX11 $X_EXTRA_LIBS) + fi + dnl *** Check for X Shm extension if test "$ac_cv_header_X11_extensions_XShm_h" = "yes" then @@ -473,42 +503,84 @@ else X_LIBS="" fi +dnl **** Check for fontconfig header using X CFLAGS in case it's in the X include dir **** +ac_save_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS $X_CFLAGS" +AC_CHECK_HEADERS(fontconfig/fontconfig.h) +CPPFLAGS="$ac_save_CPPFLAGS" + +if test "$ac_cv_header_fontconfig_fontconfig_h" = "yes" -a "x$x_includes" != "x" +then + FONTCONFIGINCL=-I$x_includes +fi + dnl **** Check for libxml2 **** AC_SUBST(XML2LIBS,"") AC_SUBST(XML2INCL,"") AC_SUBST(XSLTLIBS,"") AC_SUBST(XSLTINCL,"") -if test "$PKG_CONFIG" != "false" +if test "$with_xml" = "builtin" then - ac_save_CPPFLAGS="$CPPFLAGS" + if test -d ../xml/libxml2 -a -d ../xml/libxslt + then + # libxml2 1.1.14 included in the cxoffice + XML2LIBS="-L\$(TOPOBJDIR)/../xml/libxml2/.libs -lxml2" + XML2INCL="-I\$(TOPSRCDIR)/../xml/libxml2/include" + AC_DEFINE(HAVE_LIBXML_PARSER_H,1) + AC_DEFINE(HAVE_LIBXML2,1) + AC_DEFINE(HAVE_XMLREADMEMORY,1) + + # libxslt 1.1.14 included in the cxoffice + XSLTLIBS="-L\$(TOPOBJDIR)/../xml/libxslt/libxslt/.libs -lxslt" + XSLTINCL="-I\$(TOPSRCDIR)/../xml/libxslt" + AC_DEFINE(HAVE_LIBXSLT_PATTERN_H,1) + AC_DEFINE(HAVE_LIBXSLT_TRANSFORM_H,1) + AC_DEFINE(HAVE_LIBXSLT,1) + fi +else + ac_save_CPPFLAGS="$CPPFLAGS" + if test "$PKG_CONFIG" != "false" ; then ac_xml_libs="`$PKG_CONFIG --libs libxml-2.0 2>/dev/null`" ac_xml_cflags="`$PKG_CONFIG --cflags libxml-2.0 2>/dev/null`" - CPPFLAGS="$CPPFLAGS $ac_xml_cflags" - AC_CHECK_HEADERS(libxml/parser.h, - [AC_CHECK_LIB(xml2, xmlParseMemory, - [AC_DEFINE(HAVE_LIBXML2, 1, [Define if you have the libxml2 library]) - XML2LIBS="$ac_xml_libs" - XML2INCL="$ac_xml_cflags"],,$ac_xml_libs) - AC_CHECK_LIB(xml2, xmlReadMemory, - [AC_DEFINE(HAVE_XMLREADMEMORY,1,[Define if libxml2 has the xmlReadMemory function])],,$ac_xml_libs) - AC_CHECK_LIB(xml2, xmlNewDocPI, - [AC_DEFINE(HAVE_XMLNEWDOCPI,1,[Define if libxml2 has the xmlNewDocPI function])],,$ac_xml_libs) - ]) - CPPFLAGS="$ac_save_CPPFLAGS" + fi + if test -z "$ac_xml_libs"; then + # FIXME: Hard-coded values appropriate for Mac OS X + ac_xml_libs="-lxml2 -lpthread -lz -liconv -lm" + ac_xml_cflags="-I/usr/include/libxml2" + fi + CPPFLAGS="$CPPFLAGS $ac_xml_cflags" + AC_CHECK_HEADERS(libxml/parser.h, + [AC_CHECK_LIB(xml2, xmlParseMemory, + [AC_DEFINE(HAVE_LIBXML2, 1, [Define if you have the libxml2 library]) + XML2LIBS="$ac_xml_libs" + XML2INCL="$ac_xml_cflags"],,$ac_xml_libs) + AC_CHECK_LIB(xml2, xmlReadMemory, + [AC_DEFINE(HAVE_XMLREADMEMORY,1,[Define if libxml2 has the xmlReadMemory function])],,$ac_xml_libs) + AC_CHECK_LIB(xml2, xmlNewDocPI, + [AC_DEFINE(HAVE_XMLNEWDOCPI,1,[Define if libxml2 has the xmlNewDocPI function])],,$ac_xml_libs) + ]) + CPPFLAGS="$ac_save_CPPFLAGS" + if test "$PKG_CONFIG" != "false" ; then ac_xslt_libs="`$PKG_CONFIG --libs libxslt 2>/dev/null`" ac_xslt_cflags="`$PKG_CONFIG --cflags libxslt 2>/dev/null`" - CPPFLAGS="$CPPFLAGS $ac_xslt_cflags" - AC_CHECK_HEADERS([libxslt/pattern.h libxslt/transform.h], - [AC_CHECK_LIB(xslt, xsltCompilePattern, - [AC_DEFINE(HAVE_LIBXSLT, 1, [Define if you have the libxslt library]) - XSLTLIBS="$ac_xslt_libs" - XSLTINCL="$ac_xslt_cflags"],,$ac_xslt_libs) - ],, + fi + if test -z "$ac_xslt_libs"; then + # FIXME: Hard-coded values appropriate for Mac OS X + ac_xslt_libs="-lxslt -lxml2 -lpthread -lz -liconv -lm" + ac_xslt_cflags="-I/usr/include/libxml2" + fi + CPPFLAGS="$CPPFLAGS $ac_xslt_cflags" + AC_CHECK_HEADERS([libxslt/pattern.h libxslt/transform.h], + [AC_CHECK_LIB(xslt, xsltCompilePattern, + [AC_DEFINE(HAVE_LIBXSLT, 1, [Define if you have the libxslt library]) + XSLTLIBS="$ac_xslt_libs" + XSLTINCL="$ac_xslt_cflags"],,$ac_xslt_libs) + ],, [#ifdef HAVE_LIBXSLT_PATTERN_H # include #endif]) - CPPFLAGS="$ac_save_CPPFLAGS" + CPPFLAGS="$ac_save_CPPFLAGS" fi dnl **** Check for libhal **** @@ -597,11 +669,12 @@ then do TEST_ICUUC_LIB="${ICUUC_LIB-${i}uc.a}" TEST_ICUDATA_LIB="${ICUDATA_LIB-${i}data.a}" + STDCXX_LIB="${STDCXX_LIB--lstdc++}" AC_MSG_CHECKING(whether can link with ICU libraries $TEST_ICUUC_LIB and $TEST_ICUDATA_LIB) - LIBS="$saved_libs $TEST_ICUUC_LIB $TEST_ICUDATA_LIB -lstdc++ -lgcc_s" + LIBS="$saved_libs $TEST_ICUUC_LIB $TEST_ICUDATA_LIB $STDCXX_LIB" AC_TRY_LINK([#include ],[ubidi_open()], [AC_DEFINE(HAVE_ICU,1,[Define to 1 if the ICU libraries are installed]) - AC_SUBST(ICULIBS,"$TEST_ICUUC_LIB $TEST_ICUDATA_LIB -lstdc++ -lgcc_s") + AC_SUBST(ICULIBS,"$TEST_ICUUC_LIB $TEST_ICUDATA_LIB $STDCXX_LIB") AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no)]) done @@ -630,12 +703,14 @@ dnl **** Check for OpenLDAP *** AC_SUBST(LDAPLIBS,"") if test "$ac_cv_header_ldap_h" = "yes" -a "$ac_cv_header_lber_h" = "yes" then - AC_CHECK_LIB(ldap_r, ldap_initialize, - [AC_CHECK_LIB(lber, ber_init, - [AC_DEFINE(HAVE_LDAP, 1, [Define if you have the OpenLDAP development environment]) - LDAPLIBS="-lldap_r -llber"],, - [$LIBPTHREAD])],, - [$LIBPTHREAD]) + AC_CHECK_TYPE(LDAPSortKey, + [AC_CHECK_LIB(ldap_r, ldap_initialize, + [AC_CHECK_LIB(lber, ber_init, + [AC_DEFINE(HAVE_LDAP, 1, [Define if you have the OpenLDAP development environment]) + LDAPLIBS="-lldap_r -llber"],, + [$LIBPTHREAD])],, + [$LIBPTHREAD])],, + [#include ]) WINE_CHECK_LIB_FUNCS(\ ldap_count_references \ ldap_first_reference \ @@ -644,6 +719,40 @@ then [$LDAPLIBS $LIBPTHREAD]) fi +dnl *** Use CrossOver's in-tree FreeType sources if available +dnl *** and the regular one if not +AC_MSG_CHECKING([for CrossOver's in-tree FreeType sources]) +if test -d "$srcdir/../freetype" +then + AC_MSG_RESULT(yes) + ac_save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="-I../freetype/include $CPPFLAGS " + AC_CHECK_HEADERS(ft2build.h \ + freetype/freetype.h \ + freetype/ftglyph.h \ + freetype/tttables.h \ + freetype/ftnames.h \ + freetype/ftsnames.h \ + freetype/ttnameid.h \ + freetype/ftoutln.h \ + freetype/ftwinfnt.h \ + freetype/internal/sfnt.h,,, + [#if HAVE_FT2BUILD_H + #include + #endif]) + AC_TRY_CPP([#include + #include ], + [AC_DEFINE(HAVE_FREETYPE_FTTRIGON_H, 1, + [Define if you have the header file.]) + wine_cv_fttrigon=yes], + wine_cv_fttrigon=no) + CPPFLAGS="$ac_save_CPPFLAGS" + AC_DEFINE(HAVE_FREETYPE, 1, [Define if FreeType 2 is installed]) + wine_cv_msg_freetype=no + FREETYPEINCL="-I\$(TOPSRCDIR)/../freetype/include" + FREETYPELIBS="-L\$(TOPOBJDIR)/../freetype/patentobjs/.libs -L\$(TOPOBJDIR)/../freetype/objs/.libs -lcxfreetype" +else + AC_MSG_RESULT(no) dnl **** Check for FreeType 2 **** AC_SUBST(FREETYPELIBS,"") AC_SUBST(FREETYPEINCL,"") @@ -710,6 +819,9 @@ else fi fi fi +fi +AC_SUBST(FREETYPELIBS) +AC_SUBST(FREETYPEINCL) dnl Only build the fonts dir if we have both freetype and fontforge if test "$FONTFORGE" != "false" -a -n "$FREETYPELIBS" @@ -1005,11 +1117,13 @@ case $host_os in LDDLLFLAGS="-bundle -multiply_defined suppress" LIBWINE_LDFLAGS="-multiply_defined suppress" LDSHARED="\$(CC) -dynamiclib -install_name @executable_path/\`\$(RELPATH) \$(bindir) \$(libdir)\`/\$(DYNAME)" - STRIP="$STRIP -u -r" + STRIP="$STRIP -x" + dnl Work around Apple's broken strip + INSTALL="STRIPPROG=\\\"$STRIP\\\" \\\$(TOPSRCDIR)/tools/install-sh -c" dnl declare needed frameworks AC_SUBST(COREFOUNDATIONLIB,"-framework CoreFoundation") AC_SUBST(IOKITLIB,"-framework IOKit -framework CoreFoundation") - AC_SUBST(LDEXECFLAGS,["-image_base 0x7bf00000 -Wl,-segaddr,WINE_DOS,0x00000000,-segaddr,WINE_SHARED_HEAP,0x7f000000"]) + AC_SUBST(LDEXECFLAGS,["-image_base 0x7bf00000 -Wl,-segaddr,WINE_DOS,0x00000000,-segaddr,WINE_OLE32,0x65f00000,-segaddr,WINE_SHARED_HEAP,0x7f000000"]) if test "$ac_cv_header_DiskArbitration_DiskArbitration_h" = "yes" then dnl DiskArbitration API is not public on Darwin < 8.0, use it only if header found @@ -1063,6 +1177,15 @@ case $host_os in WINE_TRY_CFLAGS([-fPIC -Wl,--rpath,\$ORIGIN/../lib], [LIBWINE_LDFLAGS="-Wl,--rpath,\\\$\$ORIGIN/\`\$(RELPATH) \$(bindir) \$(libdir)\`"]) + AC_CACHE_CHECK([whether gcc accepts -static-libgcc], ac_cv_c_dll_static_libgcc, + [WINE_TRY_CFLAGS([-shared -static-libgcc], + ac_cv_c_dll_static_libgcc="yes",ac_cv_c_dll_static_libgcc="no")]) + if test "$ac_cv_c_dll_static_libgcc" = "yes" + then + LDSHARED="$LDSHARED -static-libgcc" + LDDLLFLAGS="$LDDLLFLAGS -static-libgcc" + fi + case $host_cpu in *i[[3456789]]86* | x86_64) WINE_TRY_CFLAGS([-Wl,--section-start,.interp=0x7bf00400], @@ -1116,11 +1239,11 @@ fi case $build_os in cygwin*|mingw32*) - AC_SUBST(LDPATH,"PATH=\"\$(TOOLSDIR)/libs/wine:\$\$PATH\"") ;; + AC_SUBST(LDPATH,"PATH=\"\$(TOOLSDIR)/libs/wine:\$(TOPOBJDIR)/../freetype/patentobjs/.libs:\$(TOPOBJDIR)/../freetype/objs/.libs:\$\$PATH\"") ;; darwin*|macosx*) - AC_SUBST(LDPATH,"DYLD_LIBRARY_PATH=\"\$(TOOLSDIR)/libs/wine:\$\$DYLD_LIBRARY_PATH\"") ;; + AC_SUBST(LDPATH,"DYLD_LIBRARY_PATH=\"\$(TOOLSDIR)/libs/wine:\$(TOPOBJDIR)/../freetype/patentobjs/.libs:\$(TOPOBJDIR)/../freetype/objs/.libs:\$\$DYLD_LIBRARY_PATH\"") ;; *) - AC_SUBST(LDPATH,"LD_LIBRARY_PATH=\"\$(TOOLSDIR)/libs/wine:\$\$LD_LIBRARY_PATH\"") ;; + AC_SUBST(LDPATH,"LD_LIBRARY_PATH=\"\$(TOOLSDIR)/libs/wine:\$(TOPOBJDIR)/../freetype/patentobjs/.libs:\$(TOPOBJDIR)/../freetype/objs/.libs:\$\$LD_LIBRARY_PATH\"") ;; esac dnl Mingw needs explicit msvcrt for linking libwine and winsock for wininet @@ -1522,6 +1645,7 @@ AC_CONFIG_FILES([programs/Makeprog.rules]) AC_CONFIG_FILES([Makefile]) AC_CONFIG_FILES([dlls/Makefile]) AC_CONFIG_FILES([dlls/activeds/Makefile]) +AC_CONFIG_FILES([dlls/actxprxy/Makefile]) AC_CONFIG_FILES([dlls/advapi32/Makefile]) AC_CONFIG_FILES([dlls/advapi32/tests/Makefile]) AC_CONFIG_FILES([dlls/advpack/Makefile]) @@ -1561,6 +1685,7 @@ AC_CONFIG_FILES([dlls/d3drm/Makefile]) AC_CONFIG_FILES([dlls/d3dx8/Makefile]) AC_CONFIG_FILES([dlls/d3dxof/Makefile]) AC_CONFIG_FILES([dlls/dbghelp/Makefile]) +AC_CONFIG_FILES([dlls/dcapvxd.vxd/Makefile]) AC_CONFIG_FILES([dlls/dciman32/Makefile]) AC_CONFIG_FILES([dlls/ddraw/Makefile]) AC_CONFIG_FILES([dlls/ddraw/tests/Makefile]) @@ -1603,10 +1728,13 @@ AC_CONFIG_FILES([dlls/hlink/Makefile]) AC_CONFIG_FILES([dlls/hlink/tests/Makefile]) AC_CONFIG_FILES([dlls/iccvid/Makefile]) AC_CONFIG_FILES([dlls/icmp/Makefile]) +AC_CONFIG_FILES([dlls/ieinfo5.ocx/Makefile]) +AC_CONFIG_FILES([dlls/iernonce/Makefile]) AC_CONFIG_FILES([dlls/ifsmgr.vxd/Makefile]) AC_CONFIG_FILES([dlls/imaadp32.acm/Makefile]) AC_CONFIG_FILES([dlls/imagehlp/Makefile]) AC_CONFIG_FILES([dlls/imm32/Makefile]) +AC_CONFIG_FILES([dlls/inetcomm/Makefile]) AC_CONFIG_FILES([dlls/infosoft/Makefile]) AC_CONFIG_FILES([dlls/infosoft/tests/Makefile]) AC_CONFIG_FILES([dlls/inseng/Makefile]) @@ -1651,6 +1779,7 @@ AC_CONFIG_FILES([dlls/msimg32/Makefile]) AC_CONFIG_FILES([dlls/msisys.ocx/Makefile]) AC_CONFIG_FILES([dlls/msnet32/Makefile]) AC_CONFIG_FILES([dlls/msrle32/Makefile]) +AC_CONFIG_FILES([dlls/msvcirt/Makefile]) AC_CONFIG_FILES([dlls/msvcrt/Makefile]) AC_CONFIG_FILES([dlls/msvcrt/tests/Makefile]) AC_CONFIG_FILES([dlls/msvcrt20/Makefile]) @@ -2052,6 +2181,7 @@ if test -z "$ALSALIBS" -a \ -z "$AUDIOIOLIBS" -a \ -z "$NASLIBS" -a \ -z "$ESD_LIBS" -a \ + -z "$COREAUDIO" -a \ -z "$ac_cv_lib_soname_jack" -a \ "$ac_cv_header_sys_soundcard_h" != "yes" -a \ "$ac_cv_header_machine_soundcard_h" != "yes" -a \ @@ -2060,7 +2190,7 @@ then echo >&2 AC_MSG_WARN([No sound system was found. Windows applications will be silent.]) AC_MSG_WARN([The currently supported sound systems are:]) - AC_MSG_WARN([ALSA, ARTS, EsounD, AudioIO, Jack, NAS and OSS]) + AC_MSG_WARN([ALSA, ARTS, EsounD, AudioIO, Jack, NAS, CoreAudio and OSS]) fi echo diff --git a/dlls/Makefile.in b/dlls/Makefile.in index b88cde38717..5b0df787dc5 100644 --- a/dlls/Makefile.in +++ b/dlls/Makefile.in @@ -17,6 +17,7 @@ EXTRADIRS = @GLU32FILES@ @OPENGLFILES@ @QUARTZFILES@ @XFILES@ BASEDIRS = \ activeds \ + actxprxy \ advapi32 \ advpack \ amstream \ @@ -46,6 +47,7 @@ BASEDIRS = \ d3dx8 \ d3dxof \ dbghelp \ + dcapvxd.vxd \ dciman32 \ ddraw \ ddrawex \ @@ -77,10 +79,13 @@ BASEDIRS = \ hlink \ iccvid \ icmp \ + ieinfo5.ocx \ + iernonce \ ifsmgr.vxd \ imaadp32.acm \ imagehlp \ imm32 \ + inetcomm \ infosoft \ inseng \ iphlpapi \ @@ -113,6 +118,7 @@ BASEDIRS = \ msisys.ocx \ msnet32 \ msrle32 \ + msvcirt \ msvcrt \ msvcrt20 \ msvcrt40 \ @@ -189,7 +195,6 @@ BASEDIRS = \ w32skrnl \ winealsa.drv \ winearts.drv \ - wineaudioio.drv \ winecoreaudio.drv \ winedos \ wineesd.drv \ diff --git a/dlls/advapi32/security.c b/dlls/advapi32/security.c index 1dbc5e32edf..eb677e43625 100644 --- a/dlls/advapi32/security.c +++ b/dlls/advapi32/security.c @@ -2921,7 +2921,8 @@ DWORD WINAPI SetEntriesInAclW( ULONG count, PEXPLICIT_ACCESSW pEntries, PACL OldAcl, PACL* NewAcl ) { FIXME("%d %p %p %p\n",count,pEntries,OldAcl,NewAcl); - *NewAcl = NULL; + *NewAcl = LocalAlloc( 0, 0x100 ); + RtlCreateAcl( *NewAcl, 6, 2 ); return ERROR_SUCCESS; } @@ -3647,16 +3648,53 @@ BOOL WINAPI CreatePrivateObjectSecurity( HANDLE Token, PGENERIC_MAPPING GenericMapping ) { - FIXME("%p %p %p %d %p %p - stub\n", ParentDescriptor, CreatorDescriptor, + DWORD nNeeded; + LPBYTE pBuffer; + DWORD iLocNow; + SECURITY_DESCRIPTOR_RELATIVE *pSDRelative; + + FIXME("%p %p %p %d %p %p - returns fake SECURITY_DESCRIPTOR\n", ParentDescriptor, CreatorDescriptor, NewDescriptor, IsDirectoryObject, Token, GenericMapping); - return FALSE; + nNeeded = sizeof(SECURITY_DESCRIPTOR_RELATIVE); + nNeeded += sizeof(sidWorld); + nNeeded += sizeof(sidWorld); + nNeeded += WINE_SIZE_OF_WORLD_ACCESS_ACL; + nNeeded += WINE_SIZE_OF_WORLD_ACCESS_ACL; + + *NewDescriptor = pBuffer = HeapAlloc(GetProcessHeap(), 0, nNeeded); + if (!InitializeSecurityDescriptor(*NewDescriptor, SECURITY_DESCRIPTOR_REVISION)) + return FALSE; + + pSDRelative = (SECURITY_DESCRIPTOR_RELATIVE *)pBuffer; + pSDRelative->Control |= SE_SELF_RELATIVE; + iLocNow = sizeof(SECURITY_DESCRIPTOR_RELATIVE); + + memcpy(pBuffer + iLocNow, &sidWorld, sizeof(sidWorld)); + pSDRelative->Owner = iLocNow; + iLocNow += sizeof(sidWorld); + + memcpy(pBuffer + iLocNow, &sidWorld, sizeof(sidWorld)); + pSDRelative->Group = iLocNow; + iLocNow += sizeof(sidWorld); + + GetWorldAccessACL((PACL) (pBuffer + iLocNow)); + pSDRelative->Dacl = iLocNow; + iLocNow += WINE_SIZE_OF_WORLD_ACCESS_ACL; + + GetWorldAccessACL((PACL) (pBuffer + iLocNow)); + pSDRelative->Sacl = iLocNow; + /* iLocNow += WINE_SIZE_OF_WORLD_ACCESS_ACL; */ + + return TRUE; } BOOL WINAPI DestroyPrivateObjectSecurity( PSECURITY_DESCRIPTOR* ObjectDescriptor ) { FIXME("%p - stub\n", ObjectDescriptor); + HeapFree(GetProcessHeap(), 0, *ObjectDescriptor); + return TRUE; } diff --git a/dlls/cabinet/fdi.c b/dlls/cabinet/fdi.c index cb589491d51..c4278de711f 100644 --- a/dlls/cabinet/fdi.c +++ b/dlls/cabinet/fdi.c @@ -2690,6 +2690,7 @@ BOOL __cdecl FDICopy( PFDI_INT(hfdi)->perf->erfOper = FDIERROR_USER_ABORT; PFDI_INT(hfdi)->perf->erfType = 0; PFDI_INT(hfdi)->perf->fError = TRUE; + filehf = 0; goto bail_and_fail; } } diff --git a/dlls/cfgmgr32/main.c b/dlls/cfgmgr32/main.c index 9f27a299469..6f4c2ecf9eb 100644 --- a/dlls/cfgmgr32/main.c +++ b/dlls/cfgmgr32/main.c @@ -24,7 +24,7 @@ #include "winbase.h" #include "winnt.h" #include "cfgmgr32.h" - +#include "wine/unicode.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(cfgmgr32); @@ -63,7 +63,7 @@ CONFIGRET WINAPI CM_Get_Device_ID_Size( ULONG* pulLen, LPVOID dnDevInst, ULONG ulFlags) { FIXME("%p %p %u\n",pulLen, dnDevInst, ulFlags); - *pulLen = 1; + *pulLen = strlenW((LPWSTR)dnDevInst)+1; return CR_SUCCESS; } @@ -74,6 +74,7 @@ CONFIGRET WINAPI CM_Get_Device_IDA( LPVOID dnDevInst, LPSTR Buffer, ULONG BufferLen, ULONG ulFlags) { FIXME("%p, %p, %u %u\n",dnDevInst, Buffer, BufferLen, ulFlags); - Buffer[0] = 0; + WideCharToMultiByte(CP_ACP,0,(LPWSTR)dnDevInst,-1,Buffer,BufferLen,0,0); + TRACE("returning %s\n",Buffer); return CR_SUCCESS; } diff --git a/dlls/comctl32/imagelist.c b/dlls/comctl32/imagelist.c index 0e314ddf9bf..df1f920c3de 100644 --- a/dlls/comctl32/imagelist.c +++ b/dlls/comctl32/imagelist.c @@ -2126,13 +2126,13 @@ ImageList_Remove (HIMAGELIST himl, INT i) TRACE("Post image copy!\n"); SelectObject (hdcBmp, hbmNewImage); - imagelist_copy_images( himl, himl->hdcImage, hdcBmp, i, - (himl->cCurImage - i - 1), i - 1 ); + imagelist_copy_images( himl, himl->hdcImage, hdcBmp, i + 1, + (himl->cCurImage - i), i ); if (himl->hbmMask) { SelectObject (hdcBmp, hbmNewMask); - imagelist_copy_images( himl, himl->hdcMask, hdcBmp, i, - (himl->cCurImage - i - 1), i - 1 ); + imagelist_copy_images( himl, himl->hdcMask, hdcBmp, i + 1, + (himl->cCurImage - i), i ); } } diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c index 68a1ddbf695..dbea54c44f0 100644 --- a/dlls/comctl32/listview.c +++ b/dlls/comctl32/listview.c @@ -8861,8 +8861,6 @@ static LRESULT LISTVIEW_Paint(LISTVIEW_INFO *infoPtr, HDC hdc) LISTVIEW_UpdateScroll(infoPtr); } - UpdateWindow(infoPtr->hwndHeader); - if (hdc) LISTVIEW_Refresh(infoPtr, hdc, NULL); else diff --git a/dlls/comctl32/monthcal.c b/dlls/comctl32/monthcal.c index 6fe62833a12..33416262a24 100644 --- a/dlls/comctl32/monthcal.c +++ b/dlls/comctl32/monthcal.c @@ -94,6 +94,7 @@ typedef struct /* control moves when user clicks a scroll button */ int visible; /* # of months visible */ int firstDay; /* Start month calendar with firstDay's day */ + int firstDayHighWord; /* High word only used externally */ int monthRange; MONTHDAYSTATE *monthdayState; SYSTEMTIME todaysDate; @@ -885,7 +886,7 @@ MONTHCAL_SetMonthDelta(MONTHCAL_INFO *infoPtr, WPARAM wParam) static LRESULT MONTHCAL_GetFirstDayOfWeek(const MONTHCAL_INFO *infoPtr) { - return infoPtr->firstDay; + return MAKELONG(infoPtr->firstDay, infoPtr->firstDayHighWord); } @@ -896,7 +897,7 @@ MONTHCAL_GetFirstDayOfWeek(const MONTHCAL_INFO *infoPtr) static LRESULT MONTHCAL_SetFirstDayOfWeek(MONTHCAL_INFO *infoPtr, LPARAM lParam) { - int prev = infoPtr->firstDay; + int prev = MAKELONG(infoPtr->firstDay, infoPtr->firstDayHighWord); int localFirstDay; WCHAR buf[40]; @@ -908,11 +909,20 @@ MONTHCAL_SetFirstDayOfWeek(MONTHCAL_INFO *infoPtr, LPARAM lParam) localFirstDay = atoiW(buf); if(lParam == -1) - infoPtr->firstDay = MAKELONG(localFirstDay, FALSE); + { + infoPtr->firstDay = localFirstDay; + infoPtr->firstDayHighWord = FALSE; + } else if(lParam >= 7) - infoPtr->firstDay = MAKELONG(localFirstDay, TRUE); + { + infoPtr->firstDay = localFirstDay; + infoPtr->firstDayHighWord = TRUE; + } else - infoPtr->firstDay = MAKELONG(lParam, TRUE); + { + infoPtr->firstDay = lParam; + infoPtr->firstDayHighWord = TRUE; + } return prev; } @@ -1879,6 +1889,7 @@ MONTHCAL_Create(HWND hwnd, WPARAM wParam, LPARAM lParam) /* FIXME: calculate systemtime ->> localtime(substract timezoneinfo) */ GetLocalTime(&infoPtr->todaysDate); + infoPtr->firstDayHighWord = FALSE; MONTHCAL_SetFirstDayOfWeek(infoPtr, (LPARAM)-1); infoPtr->currentMonth = infoPtr->todaysDate.wMonth; infoPtr->currentYear = infoPtr->todaysDate.wYear; diff --git a/dlls/comctl32/progress.c b/dlls/comctl32/progress.c index 7acf71b66f3..ca09ec957e5 100644 --- a/dlls/comctl32/progress.c +++ b/dlls/comctl32/progress.c @@ -744,6 +744,7 @@ void PROGRESS_Register (void) wndClass.cbClsExtra = 0; wndClass.cbWndExtra = sizeof (PROGRESS_INFO *); wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); + wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); wndClass.lpszClassName = PROGRESS_CLASSW; RegisterClassW (&wndClass); diff --git a/dlls/comctl32/propsheet.c b/dlls/comctl32/propsheet.c index 06ce33972d1..7a29a126cb4 100644 --- a/dlls/comctl32/propsheet.c +++ b/dlls/comctl32/propsheet.c @@ -1969,6 +1969,8 @@ static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg) HWND hwndPage; PSHNOTIFY psn; BOOL res = FALSE; + HWND hwndTabControl; + RECT rect; TRACE("active_page %d\n", psInfo->active_page); if (!psInfo) @@ -1994,6 +1996,16 @@ static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg) res = !SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); + /* + * Re-adjust the tab control's contents + */ + hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL); + memset( &rect, 0, sizeof rect ); + GetClientRect( hwndTabControl, &rect ); + SendMessageW( hwndTabControl, TCM_ADJUSTRECT, 0, (LPARAM) &rect ); + SetWindowPos( hwndPage, NULL, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, 0 ); + end: TRACE("<-- %d\n", res); return res; @@ -2023,6 +2035,11 @@ static BOOL PROPSHEET_SetCurSel(HWND hwndDlg, return FALSE; } + /* unset active page while doing this transition. */ + if (psInfo->active_page != -1) + ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE); + psInfo->active_page = -1; + while (1) { int result; PSHNOTIFY psn; @@ -3224,6 +3241,7 @@ static LRESULT PROPSHEET_Paint(HWND hwnd, HDC hdcParam) WCHAR szBuffer[256]; int nLength; + if (psInfo->active_page < 0) return 1; hdc = hdcParam ? hdcParam : BeginPaint(hwnd, &ps); if (!hdc) return 1; diff --git a/dlls/comctl32/tests/propsheet.c b/dlls/comctl32/tests/propsheet.c index db71bfe6caf..8627351b7fc 100644 --- a/dlls/comctl32/tests/propsheet.c +++ b/dlls/comctl32/tests/propsheet.c @@ -98,7 +98,42 @@ static void test_title(void) DestroyWindow(hdlg); } +static void test_nopage(void) +{ + HPROPSHEETPAGE hpsp[1]; + PROPSHEETPAGEA psp; + PROPSHEETHEADERA psh; + HWND hdlg; + + memset(&psp, 0, sizeof(psp)); + psp.dwSize = sizeof(psp); + psp.dwFlags = 0; + psp.hInstance = GetModuleHandleW(NULL); + U(psp).pszTemplate = "prop_page1"; + U2(psp).pszIcon = NULL; + psp.pfnDlgProc = page_dlg_proc; + psp.lParam = 0; + + hpsp[0] = CreatePropertySheetPageA(&psp); + + memset(&psh, 0, sizeof(psh)); + psh.dwSize = sizeof(psh); + psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK; + psh.pszCaption = "test caption"; + psh.nPages = 1; + psh.hwndParent = GetDesktopWindow(); + U3(psh).phpage = hpsp; + psh.pfnCallback = sheet_callback; + + hdlg = (HWND)PropertySheetA(&psh); + ShowWindow(hdlg,SW_NORMAL); + SendMessage(hdlg, PSM_REMOVEPAGE, 0, 0); + RedrawWindow(hdlg,NULL,NULL,RDW_UPDATENOW|RDW_ERASENOW); + DestroyWindow(hdlg); +} + START_TEST(propsheet) { test_title(); + test_nopage(); } diff --git a/dlls/comctl32/theming.c b/dlls/comctl32/theming.c index a4be617644f..a4654fc2646 100644 --- a/dlls/comctl32/theming.c +++ b/dlls/comctl32/theming.c @@ -114,7 +114,15 @@ void THEMING_Initialize (void) static const WCHAR refDataPropName[] = { 'C','C','3','2','T','h','e','m','i','n','g','D','a','t','a',0 }; - if (!IsThemeActive()) return; + /* CrossOver only HACK - Theming subclassing is disabled + * It confuses Delphi programs (such as the DVD Pro installer) and is + * generally bad because it removes the A/W duality of the builtin USER + * classes like edit controls and list boxes. These probably need to depend + * on a manifest resource being present in the executable or maybe need to + * use hooks into user32 instead. + */ + + if (1 || !IsThemeActive()) return; atSubclassProp = GlobalAddAtomW (subclassPropName); atRefDataProp = GlobalAddAtomW (refDataPropName); diff --git a/dlls/d3d9/d3d9_private.h b/dlls/d3d9/d3d9_private.h index 972945d1e45..c6dcd1688d2 100644 --- a/dlls/d3d9/d3d9_private.h +++ b/dlls/d3d9/d3d9_private.h @@ -179,10 +179,8 @@ typedef struct IDirect3DDevice9Impl /* Avoids recursion with nested ReleaseRef to 0 */ BOOL inDestruction; - /* A vertex declaration was converted from setFVF. - * Keep track of it, so it can be properly freed - */ - IDirect3DVertexDeclaration9 *convertedDecl; + IDirect3DVertexDeclaration9 **convertedDecls; + unsigned int numConvertedDecls, declArraySize; } IDirect3DDevice9Impl; @@ -486,11 +484,14 @@ typedef struct IDirect3DVertexDeclaration9Impl { /* IDirect3DVertexDeclaration9 fields */ IWineD3DVertexDeclaration *wineD3DVertexDeclaration; - + DWORD convFVF; + /* Parent reference */ LPDIRECT3DDEVICE9 parentDevice; } IDirect3DVertexDeclaration9Impl; +void IDirect3DVertexDeclaration9Impl_Destroy(LPDIRECT3DVERTEXDECLARATION9 iface); + /* ---------------------- */ /* IDirect3DVertexShader9 */ /* ---------------------- */ diff --git a/dlls/d3d9/device.c b/dlls/d3d9/device.c index 4dd16e06d54..40b5e6aee47 100644 --- a/dlls/d3d9/device.c +++ b/dlls/d3d9/device.c @@ -61,9 +61,17 @@ static ULONG WINAPI IDirect3DDevice9Impl_Release(LPDIRECT3DDEVICE9 iface) { TRACE("(%p) : ReleaseRef to %d\n", This, ref); if (ref == 0) { + int i; This->inDestruction = TRUE; - if (This->convertedDecl != NULL) - IUnknown_Release(This->convertedDecl); + + for(i = 0; i < This->numConvertedDecls; i++) { + /* Unless Wine is buggy or the app has a bug the refcount will be 0, because decls hold a reference to the + * device + */ + IDirect3DVertexDeclaration9Impl_Destroy(This->convertedDecls[i]); + } + HeapFree(GetProcessHeap(), 0, This->convertedDecls); + IWineD3DDevice_Uninit3D(This->WineD3DDevice, D3D9CB_DestroyDepthStencilSurface, D3D9CB_DestroySwapChain); IWineD3DDevice_Release(This->WineD3DDevice); HeapFree(GetProcessHeap(), 0, This); @@ -771,29 +779,77 @@ static HRESULT WINAPI IDirect3DDevice9Impl_ProcessVertices(LPDIRECT3DDEVICE9 i return IWineD3DDevice_ProcessVertices(This->WineD3DDevice,SrcStartIndex, DestIndex, VertexCount, ((IDirect3DVertexBuffer9Impl *)pDestBuffer)->wineD3DVertexBuffer, ((IDirect3DVertexBuffer9Impl *)pVertexDecl)->wineD3DVertexBuffer, Flags); } +IDirect3DVertexDeclaration9 *getConvertedDecl(IDirect3DDevice9Impl *This, DWORD fvf) { + HRESULT hr; + D3DVERTEXELEMENT9* elements = NULL; + IDirect3DVertexDeclaration9* pDecl = NULL; + int p, low, high; /* deliberately signed */ + IDirect3DVertexDeclaration9 **convertedDecls = This->convertedDecls; + + TRACE("Searching for declaration for fvf %08x... ", fvf); + + low = 0; + high = This->numConvertedDecls - 1; + while(low <= high) { + p = (low + high) >> 1; + TRACE("%d ", p); + if(((IDirect3DVertexDeclaration9Impl *) convertedDecls[p])->convFVF == fvf) { + TRACE("found %p\n", convertedDecls[p]); + return convertedDecls[p]; + } else if(((IDirect3DVertexDeclaration9Impl *) convertedDecls[p])->convFVF < fvf) { + low = p + 1; + } else { + high = p - 1; + } + } + TRACE("not found. Creating and inserting at position %d.\n", low); + + hr = vdecl_convert_fvf(fvf, &elements); + if (hr != S_OK) return NULL; + + hr = IDirect3DDevice9Impl_CreateVertexDeclaration((IDirect3DDevice9 *) This, elements, &pDecl); + if (hr != S_OK) return NULL; + + if(This->declArraySize == This->numConvertedDecls) { + int grow = max(This->declArraySize * 0.5, 1); + convertedDecls = HeapReAlloc(GetProcessHeap(), 0, convertedDecls, + sizeof(convertedDecls[0]) * (This->numConvertedDecls + grow)); + if(!convertedDecls) { + /* This will destroy it */ + IDirect3DVertexDeclaration9_Release(pDecl); + return NULL; + } + This->convertedDecls = convertedDecls; + This->declArraySize += grow; + } + + memmove(convertedDecls + low + 1, convertedDecls + low, sizeof(IDirect3DVertexDeclaration9Impl *) * (This->numConvertedDecls - low)); + convertedDecls[low] = pDecl; + This->numConvertedDecls++; + + /* Will prevent the decl from beeing destroyed */ + ((IDirect3DVertexDeclaration9Impl *) pDecl)->convFVF = fvf; + IDirect3DVertexDeclaration9_Release(pDecl); /* Does not destroy now */ + + TRACE("Returning %p. %d decls in array\n", pDecl, This->numConvertedDecls); + return pDecl; +} + HRESULT WINAPI IDirect3DDevice9Impl_SetFVF(LPDIRECT3DDEVICE9 iface, DWORD FVF) { IDirect3DDevice9Impl *This = (IDirect3DDevice9Impl *)iface; TRACE("(%p) Relay\n" , This); if (0 != FVF) { HRESULT hr; - D3DVERTEXELEMENT9* elements = NULL; - IDirect3DVertexDeclaration9* pDecl = NULL; + IDirect3DVertexDeclaration9* pDecl = getConvertedDecl(This, FVF); - hr = vdecl_convert_fvf(FVF, &elements); - if (hr != S_OK) goto exit; + if(!pDecl) { + /* Any situation when this should happen, except out of memory? */ + ERR("Failed to create a converted vertex declaration\n"); + return D3DERR_DRIVERINTERNALERROR; + } - hr = IDirect3DDevice9Impl_CreateVertexDeclaration(iface, elements, &pDecl); - if (hr != S_OK) goto exit; - hr = IDirect3DDevice9Impl_SetVertexDeclaration(iface, pDecl); - if (hr != S_OK) goto exit; - This->convertedDecl = pDecl; - pDecl = NULL; - - exit: - HeapFree(GetProcessHeap(), 0, elements); - if (pDecl) IUnknown_Release(pDecl); if (hr != S_OK) return hr; } diff --git a/dlls/d3d9/directx.c b/dlls/d3d9/directx.c index f15aa4dd112..f88115b3d22 100644 --- a/dlls/d3d9/directx.c +++ b/dlls/d3d9/directx.c @@ -98,14 +98,20 @@ static HRESULT WINAPI IDirect3D9Impl_GetAdapterIdentifier(LPDIRECT3D9 iface, UIN static UINT WINAPI IDirect3D9Impl_GetAdapterModeCount(LPDIRECT3D9 iface, UINT Adapter, D3DFORMAT Format) { IDirect3D9Impl *This = (IDirect3D9Impl *)iface; + + /* Others than that not supported by d3d9, but reported by wined3d for ddraw. Filter them out */ + if(Format != D3DFMT_X8R8G8B8 && Format != D3DFMT_R5G6B5 && Format != D3DFMT_UNKNOWN) { + return 0; + } + return IWineD3D_GetAdapterModeCount(This->WineD3D, Adapter, Format); } static HRESULT WINAPI IDirect3D9Impl_EnumAdapterModes(LPDIRECT3D9 iface, UINT Adapter, D3DFORMAT Format, UINT Mode, D3DDISPLAYMODE* pMode) { IDirect3D9Impl *This = (IDirect3D9Impl *)iface; - /* We can't pass this to WineD3D, otherwise it'll think it came from D3D8. + /* We can't pass this to WineD3D, otherwise it'll think it came from D3D8 or DDraw. It's supposed to fail anyway, so no harm returning failure. */ - if(Format == D3DFMT_UNKNOWN) + if(Format != WINED3DFMT_X8R8G8B8 && Format != WINED3DFMT_R5G6B5) return D3DERR_INVALIDCALL; return IWineD3D_EnumAdapterModes(This->WineD3D, Adapter, Format, Mode, (WINED3DDISPLAYMODE *) pMode); } @@ -394,6 +400,11 @@ static HRESULT WINAPI IDirect3D9Impl_CreateDevice(LPDIRECT3D9 iface, UINT Adapte *ppReturnedDeviceInterface = NULL; } + /* Initialize the converted declaration array. This creates a valid pointer and when adding decls HeapReAlloc + * can be used without further checking + */ + object->convertedDecls = HeapAlloc(GetProcessHeap(), 0, 0); + return hr; } diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c index 33c4231e9e1..bde2a5b1fe8 100644 --- a/dlls/d3d9/tests/visual.c +++ b/dlls/d3d9/tests/visual.c @@ -259,11 +259,6 @@ static void lighting_test(IDirect3DDevice9 *device) hr = IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE); ok(hr == D3D_OK, "IDirect3DDevice9_SetRenderState returned %s\n", DXGetErrorString9(hr)); - - /* Hack for a bug in d3d9: SetFVF creates a converted vertex declaration, with a circular refcount. - * This prevents the screen resolution from being restored correctly on device release. Unset the vdecl - */ - IDirect3DDevice9_SetVertexDeclaration(device, NULL); } static void clear_test(IDirect3DDevice9 *device) @@ -547,8 +542,6 @@ static void fog_test(IDirect3DDevice9 *device) /* Turn off the fog master switch to avoid confusing other tests */ hr = IDirect3DDevice9_SetRenderState(device, D3DRS_FOGENABLE, FALSE); ok(hr == D3D_OK, "Turning off fog calculations returned %s\n", DXGetErrorString9(hr)); - - IDirect3DDevice9_SetVertexDeclaration(device, NULL); } /* This test verifies the behaviour of cube maps wrt. texture wrapping. diff --git a/dlls/d3d9/vertexdeclaration.c b/dlls/d3d9/vertexdeclaration.c index 315107e5db5..ab7d484a78e 100644 --- a/dlls/d3d9/vertexdeclaration.c +++ b/dlls/d3d9/vertexdeclaration.c @@ -202,9 +202,25 @@ static ULONG WINAPI IDirect3DVertexDeclaration9Impl_AddRef(LPDIRECT3DVERTEXDECLA TRACE("(%p) : AddRef from %d\n", This, ref - 1); + if(ref == 1) { + IUnknown_AddRef(This->parentDevice); + } + return ref; } +void IDirect3DVertexDeclaration9Impl_Destroy(LPDIRECT3DVERTEXDECLARATION9 iface) { + IDirect3DVertexDeclaration9Impl *This = (IDirect3DVertexDeclaration9Impl *)iface; + + if(This->ref != 0) { + /* Should not happen unless wine has a bug or the application releases references it does not own */ + ERR("Destroying vdecl with ref != 0\n"); + } + IWineD3DVertexDeclaration_Release(This->wineD3DVertexDeclaration); + HeapFree(GetProcessHeap(), 0, This->elements); + HeapFree(GetProcessHeap(), 0, This); +} + static ULONG WINAPI IDirect3DVertexDeclaration9Impl_Release(LPDIRECT3DVERTEXDECLARATION9 iface) { IDirect3DVertexDeclaration9Impl *This = (IDirect3DVertexDeclaration9Impl *)iface; ULONG ref = InterlockedDecrement(&This->ref); @@ -212,10 +228,12 @@ static ULONG WINAPI IDirect3DVertexDeclaration9Impl_Release(LPDIRECT3DVERTEXDECL TRACE("(%p) : ReleaseRef to %d\n", This, ref); if (ref == 0) { - IWineD3DVertexDeclaration_Release(This->wineD3DVertexDeclaration); - IUnknown_Release(This->parentDevice); - HeapFree(GetProcessHeap(), 0, This->elements); - HeapFree(GetProcessHeap(), 0, This); + IDirect3DDevice9 *parentDevice = This->parentDevice; + + if(!This->convFVF) { + IDirect3DVertexDeclaration9Impl_Release(iface); + } + IUnknown_Release(parentDevice); } return ref; } @@ -324,7 +342,7 @@ HRESULT WINAPI IDirect3DDevice9Impl_CreateVertexDeclaration(LPDIRECT3DDEVICE9 } object->lpVtbl = &Direct3DVertexDeclaration9_Vtbl; - object->ref = 1; + object->ref = 0; object->elements = HeapAlloc(GetProcessHeap(), 0, element_count * sizeof(D3DVERTEXELEMENT9)); if (!object->elements) { @@ -347,9 +365,9 @@ HRESULT WINAPI IDirect3DDevice9Impl_CreateVertexDeclaration(LPDIRECT3DDEVICE9 HeapFree(GetProcessHeap(), 0, object->elements); HeapFree(GetProcessHeap(), 0, object); } else { - IUnknown_AddRef(iface); object->parentDevice = iface; *ppDecl = (LPDIRECT3DVERTEXDECLARATION9) object; + IUnknown_AddRef(*ppDecl); TRACE("(%p) : Created vertex declaration %p\n", This, object); } return hr; @@ -362,13 +380,7 @@ HRESULT WINAPI IDirect3DDevice9Impl_SetVertexDeclaration(LPDIRECT3DDEVICE9 ifa TRACE("(%p) : Relay\n", iface); - if (This->convertedDecl && This->convertedDecl != pDecl) { - IUnknown_Release(This->convertedDecl); - This->convertedDecl = NULL; - } - hr = IWineD3DDevice_SetVertexDeclaration(This->WineD3DDevice, pDeclImpl == NULL ? NULL : pDeclImpl->wineD3DVertexDeclaration); - return hr; } diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c index ac95ddfe14c..568f56be87e 100644 --- a/dlls/ddraw/ddraw.c +++ b/dlls/ddraw/ddraw.c @@ -251,6 +251,12 @@ IDirectDrawImpl_Destroy(IDirectDrawImpl *This) NULL, DDSCL_NORMAL); + /* Restore the display mode if the hl1 hack is active, because SetCooperativeLevel + * doesn't do it. Needs some more test cases... + */ + if(hl1hack) + IDirectDraw7_RestoreDisplayMode(ICOM_INTERFACE(This, IDirectDraw7)); + /* Destroy the device window if we created one */ if(This->devicewindow != 0) { @@ -423,8 +429,13 @@ IDirectDrawImpl_SetCooperativeLevel(IDirectDraw7 *iface, /* Switching from fullscreen? */ if(This->cooperative_level & DDSCL_FULLSCREEN) { - /* Restore the display mode */ - IDirectDraw7_RestoreDisplayMode(iface); + /* Restore the display mode, + * except if the hl1 hack is activated. This prevents the display mode set with one of + * the 3 ddraw objects from beeing restored to the starting value when the 2nd ddraw object + * goes back to DDSCL_NORMAL + */ + if(!hl1hack) + IDirectDraw7_RestoreDisplayMode(iface); This->cooperative_level &= ~DDSCL_FULLSCREEN; This->cooperative_level &= ~DDSCL_EXCLUSIVE; @@ -559,6 +570,23 @@ IDirectDrawImpl_SetDisplayMode(IDirectDraw7 *iface, WINED3DDISPLAYMODE Mode; TRACE("(%p)->(%d,%d,%d,%d,%x: Relay!\n", This, Width, Height, BPP, RefreshRate, Flags); + /* Hack for Half-Life 1: + * When run in d3d mode it sets the display mode to the desired mode, + * and then calls SetDisplayMode again with 640x480. The 2nd call is either not + * supposed to happen(caps issue) or to fail somehow. + * This hack doesn't change the display mode after DDSCL_CREATEDEVICEWINDOW + * has been passed. This isn't correct, but allows hl1 to run at other resulutions than + * 640x480 in d3d mode. + * + * This hack is for the non-steam version only, the steamish version needs a different hack + */ + if(This->cooperative_level & (DDSCL_CREATEDEVICEWINDOW | DDSCL_SETDEVICEWINDOW) + && hl1hack) + { + WARN("Not doing anything, Half-Life 1 display mode hack\n"); + return DD_OK; + } + if( !Width || !Height ) { ERR("Width=%d, Height=%d, what to do?\n", Width, Height); @@ -1166,11 +1194,31 @@ IDirectDrawImpl_EnumDisplayModes(IDirectDraw7 *iface, LPDDENUMMODESCALLBACK2 cb) { ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface); - unsigned int modenum = 0; + unsigned int modenum, fmt; WINED3DFORMAT pixelformat = WINED3DFMT_UNKNOWN; WINED3DDISPLAYMODE mode; DDSURFACEDESC2 callback_sd; + WINED3DFORMAT checkFormatList[] = + { + WINED3DFMT_R8G8B8, + WINED3DFMT_A8R8G8B8, + WINED3DFMT_X8R8G8B8, + WINED3DFMT_R5G6B5, + WINED3DFMT_X1R5G5B5, + WINED3DFMT_A1R5G5B5, + WINED3DFMT_A4R4G4B4, + WINED3DFMT_R3G3B2, + WINED3DFMT_A8R3G3B2, + WINED3DFMT_X4R4G4B4, + WINED3DFMT_A2B10G10R10, + WINED3DFMT_A8B8G8R8, + WINED3DFMT_X8B8G8R8, + WINED3DFMT_A2R10G10B10, + WINED3DFMT_A8P8, + WINED3DFMT_P8 + }; + TRACE("(%p)->(%p,%p,%p): Relay\n", This, DDSD, Context, cb); /* This looks sane */ @@ -1182,41 +1230,52 @@ IDirectDrawImpl_EnumDisplayModes(IDirectDraw7 *iface, pixelformat = PixelFormat_DD2WineD3D(&DDSD->u4.ddpfPixelFormat); } - while(IWineD3D_EnumAdapterModes(This->wineD3D, - WINED3DADAPTER_DEFAULT, - pixelformat, - modenum++, - &mode) == WINED3D_OK) { - if(DDSD) + for(fmt = 0; fmt < (sizeof(checkFormatList) / sizeof(checkFormatList[0])); fmt++) + { + if(pixelformat != WINED3DFMT_UNKNOWN && checkFormatList[fmt] != pixelformat) { - if(DDSD->dwFlags & DDSD_WIDTH && mode.Width != DDSD->dwWidth) continue; - if(DDSD->dwFlags & DDSD_HEIGHT && mode.Height != DDSD->dwHeight) continue; + continue; } - memset(&callback_sd, 0, sizeof(callback_sd)); - callback_sd.dwSize = sizeof(callback_sd); - callback_sd.u4.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); - - callback_sd.dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|DDSD_PITCH; - if(Flags & DDEDM_REFRESHRATES) + modenum = 0; + while(IWineD3D_EnumAdapterModes(This->wineD3D, + WINED3DADAPTER_DEFAULT, + checkFormatList[fmt], + modenum++, + &mode) == WINED3D_OK) { - callback_sd.dwFlags |= DDSD_REFRESHRATE; - callback_sd.u2.dwRefreshRate = mode.RefreshRate; - } + if(DDSD) + { + if(DDSD->dwFlags & DDSD_WIDTH && mode.Width != DDSD->dwWidth) continue; + if(DDSD->dwFlags & DDSD_HEIGHT && mode.Height != DDSD->dwHeight) continue; + } - callback_sd.dwWidth = mode.Width; - callback_sd.dwHeight = mode.Height; + memset(&callback_sd, 0, sizeof(callback_sd)); + callback_sd.dwSize = sizeof(callback_sd); + callback_sd.u4.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); - PixelFormat_WineD3DtoDD(&callback_sd.u4.ddpfPixelFormat, mode.Format); + callback_sd.dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|DDSD_PITCH; + if(Flags & DDEDM_REFRESHRATES) + { + callback_sd.dwFlags |= DDSD_REFRESHRATE; + callback_sd.u2.dwRefreshRate = mode.RefreshRate; + } - TRACE("Enumerating %dx%d@%d\n", callback_sd.dwWidth, callback_sd.dwHeight, callback_sd.u4.ddpfPixelFormat.u1.dwRGBBitCount); + callback_sd.dwWidth = mode.Width; + callback_sd.dwHeight = mode.Height; - if(cb(&callback_sd, Context) == DDENUMRET_CANCEL) - { - TRACE("Application asked to terminate the enumeration\n"); - return DD_OK; + PixelFormat_WineD3DtoDD(&callback_sd.u4.ddpfPixelFormat, mode.Format); + + TRACE("Enumerating %dx%d@%d\n", callback_sd.dwWidth, callback_sd.dwHeight, callback_sd.u4.ddpfPixelFormat.u1.dwRGBBitCount); + + if(cb(&callback_sd, Context) == DDENUMRET_CANCEL) + { + TRACE("Application asked to terminate the enumeration\n"); + return DD_OK; + } } } + TRACE("End of enumeration\n"); return DD_OK; } @@ -2978,3 +3037,14 @@ const IDirectDraw7Vtbl IDirectDraw7_Vtbl = IDirectDrawImpl_StartModeTest, IDirectDrawImpl_EvaluateMode }; + + +void WINAPI AcquireDDThreadLock() +{ + FIXME("Stb\n"); +} + +void WINAPI ReleaseDDThreadLock() +{ + FIXME("Stb\n"); +} diff --git a/dlls/ddraw/ddraw.spec b/dlls/ddraw/ddraw.spec index 0cd1d0f305b..ae0108e6055 100644 --- a/dlls/ddraw/ddraw.spec +++ b/dlls/ddraw/ddraw.spec @@ -1,3 +1,4 @@ +@ stdcall AcquireDDThreadLock() @ stub DDHAL32_VidMemAlloc @ stub DDHAL32_VidMemFree @ stub DDInternalLock @@ -20,6 +21,7 @@ @ stub InternalLock @ stub InternalUnlock @ stub LateAllocateSurfaceMem +@ stdcall ReleaseDDThreadLock() @ stub VidMemAlloc @ stub VidMemAmountFree @ stub VidMemFini diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h index 85f8ab244e6..cf48a0606e3 100644 --- a/dlls/ddraw/ddraw_private.h +++ b/dlls/ddraw/ddraw_private.h @@ -650,3 +650,6 @@ typedef struct #endif HRESULT hr_ddraw_from_wined3d(HRESULT hr); + +/* hack global vars, read from the registry */ +BOOL hl1hack; /* Half-Life 1 */ diff --git a/dlls/ddraw/direct3d.c b/dlls/ddraw/direct3d.c index 3047f1db69c..bcfde47c6ac 100644 --- a/dlls/ddraw/direct3d.c +++ b/dlls/ddraw/direct3d.c @@ -1015,6 +1015,7 @@ IDirect3DImpl_7_CreateVertexBuffer(IDirect3D7 *iface, { ERR("(%p) IWineD3DDevice::CreateVertexBuffer failed with hr=%08x\n", This, hr); HeapFree(GetProcessHeap(), 0, object); + *VertexBuffer = NULL; if (hr == WINED3DERR_INVALIDCALL) return DDERR_INVALIDPARAMS; else diff --git a/dlls/ddraw/main.c b/dlls/ddraw/main.c index 4e3d3a6a430..14f5aa6dd7d 100644 --- a/dlls/ddraw/main.c +++ b/dlls/ddraw/main.c @@ -57,6 +57,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(ddraw); /* The configured default surface */ WINED3DSURFTYPE DefaultSurfaceType = SURFACE_UNKNOWN; +BOOL hl1hack = FALSE; /* DDraw list and critical section */ static struct list global_ddraw_list = LIST_INIT(global_ddraw_list); @@ -863,7 +864,15 @@ DllMain(HINSTANCE hInstDLL, ERR("Unknown default surface type. Supported are:\n gdi, opengl\n"); } } - } + if ( !get_config_key( hkey, appkey, "hl1hack", buffer, size) ) + { + if (!strcmp(buffer,"enable")) + { + TRACE("Enabling the Half-Life 1 video mode hack\n"); + hl1hack = TRUE; + } + } + } DisableThreadLibraryCalls(hInstDLL); } diff --git a/dlls/ddrawex/main.c b/dlls/ddrawex/main.c index 27c5b7f6bbd..b3d4b2656e8 100644 --- a/dlls/ddrawex/main.c +++ b/dlls/ddrawex/main.c @@ -208,14 +208,20 @@ IDirectDrawFactoryImpl_CreateDirectDraw(IDirectDrawFactory* iface, IDirectDraw **ppDirectDraw) { HRESULT hr; + IDirectDraw *pddraw7; TRACE("\n"); - hr = DirectDrawCreateEx(pGUID, (void**)ppDirectDraw, &IID_IDirectDraw3, pUnkOuter); + hr = DirectDrawCreateEx(pGUID, (void**)&pddraw7, &IID_IDirectDraw7, pUnkOuter); if (FAILED(hr)) return hr; + hr = IDirectDraw_QueryInterface(pddraw7, &IID_IDirectDraw3, (void**)ppDirectDraw); + IDirectDraw_Release(pddraw7); + if (FAILED(hr)) + return hr; + hr = IDirectDraw_SetCooperativeLevel(*ppDirectDraw, hWnd, dwCoopLevelFlags); if (FAILED(hr)) IDirectDraw_Release(*ppDirectDraw); diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h index cb14457ea98..568b6fcd0dc 100644 --- a/dlls/dsound/dsound_private.h +++ b/dlls/dsound/dsound_private.h @@ -84,6 +84,7 @@ struct DirectSoundDevice DSDRIVERCAPS drvcaps; DWORD priolevel; PWAVEFORMATEX pwfx; + int no_reformat; HWAVEOUT hwo; LPWAVEHDR pwave[DS_HEL_FRAGS]; UINT timerID, pwplay, pwwrite, pwqueue, prebuf, precount; diff --git a/dlls/dsound/primary.c b/dlls/dsound/primary.c index 9a3498d85d1..8a7df1b68a1 100644 --- a/dlls/dsound/primary.c +++ b/dlls/dsound/primary.c @@ -273,7 +273,31 @@ HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device) &(device->buflen),&(device->buffer), (LPVOID)&(device->hwbuf)); if (err != DS_OK) - WARN("IDsDriver_CreateSoundBuffer failed\n"); + { + unsigned c; + WARN("IDsDriver_CreateSoundBuffer failed\n"); + /* We had a HW buffer and now we do not. This could cause + * problems in the future with pwave being uncreated and + * crashing + */ + device->buffer = NULL; + device->buflen = device->pwfx->nAvgBytesPerSec; + /* Allocate memory for HEL buffer headers */ + for (c=0; cpwave[c] = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY,sizeof(WAVEHDR)); + if (!device->pwave[c]) { + /* Argh, out of memory */ + while (c--) { + HeapFree(GetProcessHeap(),0,device->pwave[c]); + } + WARN("out of memory\n"); + err = DSERR_OUTOFMEMORY; + } + } + } + else + memset(device->buffer, (device->pwfx->wBitsPerSample == 16) ? 0 : 128, device->buflen); } else { WARN("waveOutOpen failed\n"); } @@ -341,6 +365,12 @@ HRESULT DSOUND_PrimarySetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex) wfex->nAvgBytesPerSec, wfex->nBlockAlign, wfex->wBitsPerSample, wfex->cbSize); + if (device->no_reformat) + { + TRACE("no_reformat set, not changing the format\n"); + return DS_OK; + } + /* **** */ RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE); EnterCriticalSection(&(device->mixlock)); diff --git a/dlls/gdi32/Makefile.in b/dlls/gdi32/Makefile.in index e3b2d67a7f1..1ebbad11177 100644 --- a/dlls/gdi32/Makefile.in +++ b/dlls/gdi32/Makefile.in @@ -6,7 +6,7 @@ VPATH = @srcdir@ MODULE = gdi32.dll IMPORTLIB = libgdi32.$(IMPLIBEXT) IMPORTS = advapi32 kernel32 ntdll -EXTRAINCL = @FREETYPEINCL@ +EXTRAINCL = @FREETYPEINCL@ @FONTCONFIGINCL@ EXTRALIBS = @ICULIBS@ @CARBONLIB@ SPEC_SRCS16 = \ diff --git a/dlls/gdi32/driver.c b/dlls/gdi32/driver.c index 9d472ef6ad9..859f4626476 100644 --- a/dlls/gdi32/driver.c +++ b/dlls/gdi32/driver.c @@ -300,6 +300,8 @@ const DC_FUNCTIONS *DRIVER_load_driver( LPCWSTR name ) } } + /* Big nasty hack tm */ + LoadLibraryA("winspool.drv"); if (!(module = LoadLibraryW( name ))) { LeaveCriticalSection( &driver_section ); diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c index ea2e66c266f..120dca3642d 100644 --- a/dlls/gdi32/font.c +++ b/dlls/gdi32/font.c @@ -592,11 +592,8 @@ static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, void *obj, HDC hdc ) if (!dc) return 0; - if (dc->hFont != handle || dc->gdiFont == NULL) - { - if(GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_VA_ABLE) - dc->gdiFont = WineEngCreateFontInstance(dc, handle); - } + if(GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_VA_ABLE) + dc->gdiFont = WineEngCreateFontInstance(dc, handle); if (dc->funcs->pSelectFont) ret = dc->funcs->pSelectFont( dc->physDev, handle, dc->gdiFont ); @@ -1094,8 +1091,11 @@ BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count, { BOOL ret = FALSE; INT wlen; - LPWSTR p = FONT_mbtowc(hdc, str, count, &wlen, NULL); + LPWSTR p; + + if(count < 0) return FALSE; + p = FONT_mbtowc(hdc, str, count, &wlen, NULL); if (p) { ret = GetTextExtentPoint32W( hdc, p, wlen, size ); HeapFree( GetProcessHeap(), 0, p ); @@ -1143,7 +1143,11 @@ BOOL WINAPI GetTextExtentPointI( LPSIZE size) /* [out] Address of structure for string size */ { BOOL ret = FALSE; - DC * dc = DC_GetDCPtr( hdc ); + DC *dc; + + if (count < 0) return FALSE; + + dc = DC_GetDCPtr( hdc ); if (!dc) return FALSE; if(dc->gdiFont) { @@ -1263,6 +1267,8 @@ BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count, BOOL ret = FALSE; TEXTMETRICW tm; + if (count < 0) return FALSE; + TRACE("(%p, %s, %d)\n",hdc,debugstr_wn(str,count),maxExt); dc = DC_GetDCPtr(hdc); @@ -1801,25 +1807,39 @@ BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags, LPWSTR p; BOOL ret; LPINT lpDxW = NULL; + unsigned int i; if (flags & ETO_GLYPH_INDEX) return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx ); - p = FONT_mbtowc(hdc, str, count, &wlen, &codepage); + if(GetObjectType(hdc) != OBJ_METADC) { + p = FONT_mbtowc(hdc, str, count, &wlen, &codepage); - if (lpDx) { - unsigned int i = 0, j = 0; + if (lpDx) { + unsigned int i = 0, j = 0; - lpDxW = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(INT)); - while(i < count) { - if(IsDBCSLeadByteEx(codepage, str[i])) { - lpDxW[j++] = lpDx[i] + lpDx[i+1]; - i = i + 2; - } else { - lpDxW[j++] = lpDx[i]; - i = i + 1; + lpDxW = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(INT)); + while(i < count) { + if(IsDBCSLeadByteEx(codepage, str[i])) { + lpDxW[j++] = lpDx[i] + lpDx[i+1]; + i = i + 2; + } else { + lpDxW[j++] = lpDx[i]; + i = i + 1; + } } } + } else { /* Special case for metafiles. Just do a straight copy */ + p = HeapAlloc(GetProcessHeap(), 0, (count + 1) * sizeof(WCHAR)); + for(i = 0; i < count; i++) + p[i] = (BYTE)str[i]; + p[count] = '\0'; + wlen = count; + if(lpDx) { + lpDxW = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT)); + for(i = 0; i < count; i++) + lpDxW[i] = lpDx[i]; + } } ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW ); diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index f7b1220a2b1..bdcf8d6fc92 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -253,11 +253,17 @@ typedef struct tagFace { Bitmap_Size size; /* set if face is a bitmap */ BOOL external; /* TRUE if we should manually add this font to the registry */ struct tagFamily *family; + /* Cached data for Enum */ + BOOL cache_valid; + ENUMLOGFONTEXW elf; + NEWTEXTMETRICEXW ntm; + DWORD type; } Face; typedef struct tagFamily { struct list entry; const WCHAR *FamilyName; + const WCHAR *EnglishName; struct list faces; } Family; @@ -423,6 +429,25 @@ typedef struct tagFontSubst { NameCs to; } FontSubst; +/* Registry font cache key and value names */ +static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\', + 'F','o','n','t','s',0}; +static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0}; +static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0}; +static const WCHAR face_index_value[] = {'I','n','d','e','x',0}; +static const WCHAR face_italic_value[] = {'I','t','a','l','i','c',0}; +static const WCHAR face_bold_value[] = {'B','o','l','d',0}; +static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0}; +static const WCHAR face_external_value[] = {'E','x','t','e','r','n','a','l',0}; +static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0}; +static const WCHAR face_width_value[] = {'W','i','d','t','h',0}; +static const WCHAR face_size_value[] = {'S','i','z','e',0}; +static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0}; +static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0}; +static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0}; +static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0}; + + struct font_mapping { struct list entry; @@ -438,6 +463,7 @@ static struct list mappings_list = LIST_INIT( mappings_list ); static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */ static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'}; +static HANDLE font_mutex; /**************************************** @@ -949,9 +975,247 @@ static WCHAR *get_familyname(FT_Face ft_face) return NULL; } +static HRESULT reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data) +{ + DWORD type, needed; + HRESULT r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed); + if(FAILED(r)) return r; + if(type != REG_DWORD || needed != sizeof(DWORD)) return E_FAIL; + return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed); +} + +static inline HRESULT reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data) +{ + return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD)); +} + +static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family) +{ + DWORD needed; + DWORD num_strikes, max_strike_key_len; + + /* If we have a File Name key then this is a real font, not just the parent + key of a bunch of non-scalable strikes */ + if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS) + { + Face *face; + face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face)); + + face->file = HeapAlloc(GetProcessHeap(), 0, needed); + RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed); + + face->StyleName = strdupW(face_name); + face->family = family; + face->cache_valid = FALSE; + + reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index); + reg_load_dword(hkey_face, face_italic_value, (DWORD*)&face->Italic); + reg_load_dword(hkey_face, face_bold_value, (DWORD*)&face->Bold); + reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version); + reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external); + + needed = sizeof(face->fs); + RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed); + memset(&face->fs_links, 0, sizeof(face->fs_links)); + + if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS) + { + face->scalable = TRUE; + memset(&face->size, 0, sizeof(face->size)); + } + else + { + face->scalable = FALSE; + reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width); + reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size); + reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem); + reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem); + reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading); + + TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n", + face->size.height, face->size.width, face->size.size >> 6, + face->size.x_ppem >> 6, face->size.y_ppem >> 6); + } + + TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n", + face->fs.fsCsb[0], face->fs.fsCsb[1], + face->fs.fsUsb[0], face->fs.fsUsb[1], + face->fs.fsUsb[2], face->fs.fsUsb[3]); + + if(!face->Italic && !face->Bold) + list_add_head(&family->faces, &face->entry); + else + list_add_tail(&family->faces, &face->entry); + + if(face->fs.fsCsb[0] & ~(1L << 31)) + have_installed_roman_font = TRUE; + + TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName)); + } + + /* do we have any bitmap strikes? */ + RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL, + NULL, NULL, NULL, NULL); + if(num_strikes != 0) + { + WCHAR strike_name[10]; + DWORD strike_index = 0; + + needed = sizeof(strike_name) / sizeof(WCHAR); + while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed, + NULL, NULL, NULL, NULL) == ERROR_SUCCESS) + { + HKEY hkey_strike; + RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike); + load_face(hkey_strike, face_name, family); + RegCloseKey(hkey_strike); + needed = sizeof(strike_name) / sizeof(WCHAR); + } + } +} + +static void load_font_list_from_cache(HKEY hkey_font_cache) +{ + DWORD max_family_key_len, size; + WCHAR *family_name; + DWORD family_index = 0; + Family *family; + HKEY hkey_family; + + RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL, + NULL, NULL, NULL, NULL); + family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR)); + + size = max_family_key_len + 1; + while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size, + NULL, NULL, NULL, NULL) == ERROR_SUCCESS) + { + WCHAR *english_family = NULL; + DWORD face_index = 0; + WCHAR *face_name; + DWORD max_face_key_len; + + RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family); + TRACE("opened family key %s\n", debugstr_w(family_name)); + if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS) + { + english_family = HeapAlloc(GetProcessHeap(), 0, size); + RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size); + } + + family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family)); + family->FamilyName = strdupW(family_name); + family->EnglishName = english_family; + list_init(&family->faces); + list_add_tail(&font_list, &family->entry); + + if(english_family) + { + FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst)); + subst->from.name = strdupW(english_family); + subst->from.charset = -1; + subst->to.name = strdupW(family_name); + subst->to.charset = -1; + add_font_subst(&font_subst_list, subst, 0); + } + + RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL, + NULL, NULL, NULL, NULL); + + face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR)); + size = max_face_key_len + 1; + while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size, + NULL, NULL, NULL, NULL) == ERROR_SUCCESS) + { + HKEY hkey_face; + + RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face); + load_face(hkey_face, face_name, family); + RegCloseKey(hkey_face); + size = max_face_key_len + 1; + } + HeapFree(GetProcessHeap(), 0, face_name); + RegCloseKey(hkey_family); + size = max_family_key_len + 1; + } + + HeapFree(GetProcessHeap(), 0, family_name); + +} + +static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition) +{ + LONG ret; + HKEY hkey_wine_fonts; + + /* We don't want to create the fonts key as volatile, so open this first */ + ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0, + KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL); + if(ret != ERROR_SUCCESS) + { + WARN("Can't create %s\n", debugstr_w(wine_fonts_key)); + return ret; + } + + ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE, + KEY_ALL_ACCESS, NULL, hkey, disposition); + RegCloseKey(hkey_wine_fonts); + return ret; +} + +static void add_face_to_cache(Face *face) +{ + HKEY hkey_font_cache, hkey_family, hkey_face; + WCHAR *face_key_name; + + create_font_cache_key(&hkey_font_cache, NULL); + + RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0, + NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL); + if(face->family->EnglishName) + RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName, + (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR)); + + if(face->scalable) + face_key_name = face->StyleName; + else + { + static const WCHAR fmtW[] = {'%','s','\\','%','d',0}; + face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR)); + sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem); + } + RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, + &hkey_face, NULL); + if(!face->scalable) + HeapFree(GetProcessHeap(), 0, face_key_name); + + RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1); + + reg_save_dword(hkey_face, face_index_value, face->face_index); + reg_save_dword(hkey_face, face_italic_value, face->Italic); + reg_save_dword(hkey_face, face_bold_value, face->Bold); + reg_save_dword(hkey_face, face_version_value, face->font_version); + reg_save_dword(hkey_face, face_external_value, face->external); + + RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs)); + + if(!face->scalable) + { + reg_save_dword(hkey_face, face_height_value, face->size.height); + reg_save_dword(hkey_face, face_width_value, face->size.width); + reg_save_dword(hkey_face, face_size_value, face->size.size); + reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem); + reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem); + reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading); + } + RegCloseKey(hkey_face); + RegCloseKey(hkey_family); + RegCloseKey(hkey_font_cache); +} #define ADDFONT_EXTERNAL_FONT 0x01 #define ADDFONT_FORCE_BITMAP 0x02 +#define ADDFONT_ADD_TO_CACHE 0x04 static BOOL AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags) { FT_Face ft_face; @@ -1028,10 +1292,17 @@ static BOOL AddFontFileToList(const char *file, char *fake_family, const WCHAR * return FALSE; } + if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */ + { + TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file)); + pFT_Done_Face(ft_face); + return FALSE; + } + if (target_family) { localised_family = get_familyname(ft_face); - if (localised_family && lstrcmpW(localised_family,target_family)!=0) + if (localised_family && strcmpiW(localised_family,target_family)!=0) { TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index); HeapFree(GetProcessHeap(), 0, localised_family); @@ -1075,6 +1346,8 @@ static BOOL AddFontFileToList(const char *file, char *fake_family, const WCHAR * if(!family) { family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family)); family->FamilyName = strdupW(localised_family ? localised_family : english_family); + family->EnglishName = localised_family ? strdupW(english_family) : NULL; + list_init(&family->faces); list_add_tail(&font_list, &family->entry); @@ -1157,7 +1430,7 @@ static BOOL AddFontFileToList(const char *file, char *fake_family, const WCHAR * } } face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face)); - list_add_tail(&family->faces, &face->entry); + face->cache_valid = FALSE; face->StyleName = StyleW; face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1); strcpy(face->file, file); @@ -1208,6 +1481,14 @@ static BOOL AddFontFileToList(const char *file, char *fake_family, const WCHAR * } } + if(!face->Italic && !face->Bold) + list_add_head(&family->faces, &face->entry); + else + list_add_tail(&family->faces, &face->entry); + + if(flags & ADDFONT_ADD_TO_CACHE) + add_face_to_cache(face); + if(face->fs.fsCsb[0] & ~(1L << 31)) have_installed_roman_font = TRUE; } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes); @@ -1281,19 +1562,22 @@ static void LoadReplaceList(void) /* "NewName"="Oldname" */ WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL); - /* Find the old family and hence all of the font files - in that family */ - LIST_FOR_EACH(family_elem_ptr, &font_list) { - family = LIST_ENTRY(family_elem_ptr, Family, entry); - if(!strcmpiW(family->FamilyName, data)) { - LIST_FOR_EACH(face_elem_ptr, &family->faces) { - face = LIST_ENTRY(face_elem_ptr, Face, entry); - TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName), - debugstr_w(face->StyleName), familyA); - /* Now add a new entry with the new family name */ - AddFontFileToList(face->file, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0)); + if(!find_family_from_name(value)) + { + /* Find the old family and hence all of the font files + in that family */ + LIST_FOR_EACH(family_elem_ptr, &font_list) { + family = LIST_ENTRY(family_elem_ptr, Family, entry); + if(!strcmpiW(family->FamilyName, data)) { + LIST_FOR_EACH(face_elem_ptr, &family->faces) { + face = LIST_ENTRY(face_elem_ptr, Face, entry); + TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName), + debugstr_w(face->StyleName), familyA); + /* Now add a new entry with the new family name */ + AddFontFileToList(face->file, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0)); + } + break; } - break; } } /* reset dlen and vlen */ @@ -1470,7 +1754,7 @@ static BOOL ReadFontDir(const char *dirname, BOOL external_fonts) if(S_ISDIR(statbuf.st_mode)) ReadFontDir(path, external_fonts); else - AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0); + AddFontFileToList(path, NULL, NULL, (external_fonts ? ADDFONT_EXTERNAL_FONT : 0) | ADDFONT_ADD_TO_CACHE); } closedir(dir); return TRUE; @@ -1538,7 +1822,7 @@ LOAD_FUNCPTR(FcPatternGetString); if(len < 4) continue; ext = &file[ len - 3 ]; if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb")) - AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT); + AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE); } pFcFontSetDestroy(fontset); pFcObjectSetDestroy(os); @@ -1569,7 +1853,7 @@ static BOOL load_font_from_data_dir(LPCWSTR file) WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL); - ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP); + ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE); HeapFree(GetProcessHeap(), 0, unix_name); } return ret; @@ -1595,7 +1879,7 @@ static void load_system_fonts(void) sprintfW(pathW, fmtW, windowsdir, data); if((unixname = wine_get_unix_file_name(pathW))) { - added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP); + added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE); HeapFree(GetProcessHeap(), 0, unixname); } if (!added) @@ -1615,10 +1899,9 @@ static void load_system_fonts(void) */ static void update_reg_entries(void) { - HKEY winkey = 0, externalkey = 0; + HKEY winnt_key = 0, win9x_key, external_key = 0; LPWSTR valueW; - LPVOID data; - DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam; + DWORD len, len_fam; Family *family; Face *face; struct list *family_elem_ptr, *face_elem_ptr; @@ -1627,47 +1910,22 @@ static void update_reg_entries(void) static const WCHAR spaceW[] = {' ', '\0'}; char *path; - if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key, - 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) { + if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, + 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) { ERR("Can't create Windows font reg key\n"); goto end; } - /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */ - if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) { - ERR("Can't create external font reg key\n"); - goto end; - } - - /* Delete all external fonts added last time */ - - RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - &valuelen, &datalen, NULL, NULL); - valuelen++; /* returned value doesn't include room for '\0' */ - valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR)); - data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR)); - - dlen = datalen * sizeof(WCHAR); - vlen = valuelen; - i = 0; - while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data, - &dlen) == ERROR_SUCCESS) { - RegDeleteValueW(winkey, valueW); - /* reset dlen and vlen */ - dlen = datalen; - vlen = valuelen; + if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, + 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) { + ERR("Can't create Windows font reg key\n"); + goto end; } - HeapFree(GetProcessHeap(), 0, data); - HeapFree(GetProcessHeap(), 0, valueW); - /* Delete the old external fonts key */ - RegCloseKey(externalkey); - externalkey = 0; - RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key); /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */ if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key, - 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) { + 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) { ERR("Can't create external font reg key\n"); goto end; } @@ -1690,29 +1948,92 @@ static void update_reg_entries(void) strcatW(valueW, face->StyleName); } strcatW(valueW, TrueType); - if((path = strrchr(face->file, '/')) == NULL) - path = face->file; + + file = wine_get_dos_file_name(face->file); + if(file) + len = strlenW(file) + 1; else - path++; - len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0); + { + if((path = strrchr(face->file, '/')) == NULL) + path = face->file; + else + path++; + len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0); - file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, path, -1, file, len); - RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR)); - RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR)); + file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, path, -1, file, len); + } + RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR)); + RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR)); + RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR)); HeapFree(GetProcessHeap(), 0, file); HeapFree(GetProcessHeap(), 0, valueW); } } end: - if(externalkey) - RegCloseKey(externalkey); - if(winkey) - RegCloseKey(winkey); + if(external_key) RegCloseKey(external_key); + if(win9x_key) RegCloseKey(win9x_key); + if(winnt_key) RegCloseKey(winnt_key); return; } +static void delete_external_font_keys(void) +{ + HKEY winnt_key = 0, win9x_key = 0, external_key = 0; + DWORD dlen, vlen, datalen, valuelen, i, type; + LPWSTR valueW; + LPVOID data; + + if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, + 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) { + ERR("Can't create Windows font reg key\n"); + goto end; + } + + if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, + 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) { + ERR("Can't create Windows font reg key\n"); + goto end; + } + + /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */ + if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) { + ERR("Can't create external font reg key\n"); + goto end; + } + + /* Delete all external fonts added last time */ + + RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + &valuelen, &datalen, NULL, NULL); + valuelen++; /* returned value doesn't include room for '\0' */ + valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR)); + data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR)); + + dlen = datalen * sizeof(WCHAR); + vlen = valuelen; + i = 0; + while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data, + &dlen) == ERROR_SUCCESS) { + + RegDeleteValueW(winnt_key, valueW); + RegDeleteValueW(win9x_key, valueW); + /* reset dlen and vlen */ + dlen = datalen; + vlen = valuelen; + } + HeapFree(GetProcessHeap(), 0, data); + HeapFree(GetProcessHeap(), 0, valueW); + + /* Delete the old external fonts key */ + RegCloseKey(external_key); + RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key); + + end: + if(win9x_key) RegCloseKey(win9x_key); + if(winnt_key) RegCloseKey(winnt_key); +} /************************************************************* * WineEngAddFontResourceEx @@ -1724,12 +2045,14 @@ INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv) { char *unixname; - if(flags) - FIXME("Ignoring flags %x\n", flags); - if((unixname = wine_get_unix_file_name(file))) { - AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP); + DWORD flags = ADDFONT_FORCE_BITMAP; + + if(!(flags & FR_PRIVATE)) flags |= ADDFONT_ADD_TO_CACHE; + WaitForSingleObject(font_mutex, INFINITE); + AddFontFileToList(unixname, NULL, NULL, flags); + ReleaseMutex(font_mutex); HeapFree(GetProcessHeap(), 0, unixname); } } @@ -1933,105 +2256,17 @@ static void update_font_info(void) FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp); } -/************************************************************* - * WineEngInit - * - * Initialize FreeType library and create a list of available faces - */ -BOOL WineEngInit(void) +static void init_font_list(void) { static const WCHAR dot_fonW[] = {'.','f','o','n','\0'}; static const WCHAR pathW[] = {'P','a','t','h',0}; HKEY hkey; - DWORD valuelen, datalen, i = 0, type, dlen, vlen; - LPVOID data; WCHAR windowsdir[MAX_PATH]; char *unixname; - HANDLE font_mutex; + DWORD valuelen, datalen, i = 0, type, dlen, vlen; + LPVOID data; const char *data_dir; - TRACE("\n"); - - /* update locale dependent font info in registry */ - update_font_info(); - - ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0); - if(!ft_handle) { - WINE_MESSAGE( - "Wine cannot find the FreeType font library. To enable Wine to\n" - "use TrueType fonts please install a version of FreeType greater than\n" - "or equal to 2.0.5.\n" - "http://www.freetype.org\n"); - return FALSE; - } - -#define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(ft_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;} - - LOAD_FUNCPTR(FT_Vector_Unit) - LOAD_FUNCPTR(FT_Done_Face) - LOAD_FUNCPTR(FT_Get_Char_Index) - LOAD_FUNCPTR(FT_Get_Module) - LOAD_FUNCPTR(FT_Get_Sfnt_Name) - LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count) - LOAD_FUNCPTR(FT_Get_Sfnt_Table) - LOAD_FUNCPTR(FT_Init_FreeType) - LOAD_FUNCPTR(FT_Load_Glyph) - LOAD_FUNCPTR(FT_Matrix_Multiply) - LOAD_FUNCPTR(FT_MulFix) - LOAD_FUNCPTR(FT_New_Face) - LOAD_FUNCPTR(FT_New_Memory_Face) - LOAD_FUNCPTR(FT_Outline_Get_Bitmap) - LOAD_FUNCPTR(FT_Outline_Transform) - LOAD_FUNCPTR(FT_Outline_Translate) - LOAD_FUNCPTR(FT_Select_Charmap) - LOAD_FUNCPTR(FT_Set_Pixel_Sizes) - LOAD_FUNCPTR(FT_Vector_Transform) - -#undef LOAD_FUNCPTR - /* Don't warn if this one is missing */ - pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0); - pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0); - pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0); - pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0); - pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0); -#ifdef HAVE_FREETYPE_FTWINFNT_H - pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0); -#endif - if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) && - !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) { - /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and - <= 2.0.3 has FT_Sqrt64 */ - goto sym_not_found; - } - - if(pFT_Init_FreeType(&library) != 0) { - ERR("Can't init FreeType library\n"); - wine_dlclose(ft_handle, NULL, 0); - ft_handle = NULL; - return FALSE; - } - FT_Version.major=FT_Version.minor=FT_Version.patch=-1; - if (pFT_Library_Version) - { - pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch); - } - if (FT_Version.major<=0) - { - FT_Version.major=2; - FT_Version.minor=0; - FT_Version.patch=5; - } - TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch); - FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) | - ((FT_Version.minor << 8) & 0x00ff00) | - ((FT_Version.patch ) & 0x0000ff); - - if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) { - ERR("Failed to create font mutex\n"); - return FALSE; - } - WaitForSingleObject(font_mutex, INFINITE); - /* load the system bitmap fonts */ load_system_fonts(); @@ -2077,7 +2312,7 @@ BOOL WineEngInit(void) { if((unixname = wine_get_unix_file_name((LPWSTR)data))) { - AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP); + AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE); HeapFree(GetProcessHeap(), 0, unixname); } } @@ -2090,7 +2325,7 @@ BOOL WineEngInit(void) sprintfW(pathW, fmtW, windowsdir, data); if((unixname = wine_get_unix_file_name(pathW))) { - added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP); + added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE); HeapFree(GetProcessHeap(), 0, unixname); } if (!added) @@ -2140,12 +2375,185 @@ BOOL WineEngInit(void) } RegCloseKey(hkey); } +} + +static BOOL move_to_front(const WCHAR *name) +{ + Family *family, *cursor2; + LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry) + { + if(!strcmpiW(family->FamilyName, name)) + { + list_remove(&family->entry); + list_add_head(&font_list, &family->entry); + return TRUE; + } + } + return FALSE; +} + +static const WCHAR arial[] = {'A','r','i','a','l',0}; +static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0}; +static const WCHAR bitstream_vera_sans_mono[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',' ','M','o','n','o',0}; +static const WCHAR bitstream_vera_serif[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','e','r','i','f',0}; +static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0}; +static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0}; + +static void reorder_font_list(void) +{ + if(!move_to_front(times_new_roman)) + move_to_front(bitstream_vera_serif); + + if(!move_to_front(courier_new)) + move_to_front(bitstream_vera_sans_mono); + + if(!move_to_front(arial)) + move_to_front(bitstream_vera_sans); + +} + +/************************************************************* + * WineEngInit + * + * Initialize FreeType library and create a list of available faces + */ +BOOL WineEngInit(void) +{ + static const WCHAR cx_hack_var[] = {'C','X','_','T','U','R','N','_','O','F','F','_','F','O','N','T','_', + 'R','E','P','L','A','C','E','M','E','N','T','S',0}; + WCHAR env_buf[20]; + HKEY hkey_font_cache; + DWORD disposition; + const char *ftname = "libcxfreetype.so"; + char freetypelib[MAX_PATH]; + LONG r; + HKEY hkey; + DWORD vlen, type; + + /* check if the config file specifies a freetype library */ + /* @@ Wine registry key: HKCU\Software\Wine\Fonts */ + r = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", + &hkey); + if( r == ERROR_SUCCESS ) + { + vlen = sizeof freetypelib; + r = RegQueryValueExA( hkey, "FreeTypeLib", 0, &type, + (LPBYTE)freetypelib, &vlen ); + if( ( ERROR_SUCCESS == r ) && ( type == REG_SZ ) ) + { + ftname = freetypelib; + } + RegCloseKey( hkey ); + } + + /* update locale dependent font info in registry */ + update_font_info(); + + TRACE("Using freetype library %s\n",ftname); + ft_handle = wine_dlopen(ftname, RTLD_NOW, NULL, 0); + if(!ft_handle) { + TRACE("Can't find freetype library %s, trying %s instead\n", ftname, SONAME_LIBFREETYPE); + ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0); + if(!ft_handle) { + WINE_MESSAGE( + "Wine cannot find the FreeType font library. To enable Wine to\n" + "use TrueType fonts please install a version of FreeType greater than\n" + "or equal to 2.0.5.\n" + "http://www.freetype.org\n"); + return FALSE; + } + } + +#define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(ft_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;} + + LOAD_FUNCPTR(FT_Vector_Unit) + LOAD_FUNCPTR(FT_Done_Face) + LOAD_FUNCPTR(FT_Get_Char_Index) + LOAD_FUNCPTR(FT_Get_Module) + LOAD_FUNCPTR(FT_Get_Sfnt_Name) + LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count) + LOAD_FUNCPTR(FT_Get_Sfnt_Table) + LOAD_FUNCPTR(FT_Init_FreeType) + LOAD_FUNCPTR(FT_Load_Glyph) + LOAD_FUNCPTR(FT_Matrix_Multiply) + LOAD_FUNCPTR(FT_MulFix) + LOAD_FUNCPTR(FT_New_Face) + LOAD_FUNCPTR(FT_New_Memory_Face) + LOAD_FUNCPTR(FT_Outline_Get_Bitmap) + LOAD_FUNCPTR(FT_Outline_Transform) + LOAD_FUNCPTR(FT_Outline_Translate) + LOAD_FUNCPTR(FT_Select_Charmap) + LOAD_FUNCPTR(FT_Set_Pixel_Sizes) + LOAD_FUNCPTR(FT_Vector_Transform) + +#undef LOAD_FUNCPTR + /* Don't warn if this one is missing */ + pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0); + pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0); + pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0); + pFT_Get_Next_Char = wine_dlsym(ft_handle,"FT_Get_Next_Char", NULL, 0); + pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0); +#ifdef HAVE_FREETYPE_FTWINFNT_H + pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0); +#endif + if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) && + !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) { + /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and + <= 2.0.3 has FT_Sqrt64 */ + goto sym_not_found; + } + + if(pFT_Init_FreeType(&library) != 0) { + ERR("Can't init FreeType library\n"); + wine_dlclose(ft_handle, NULL, 0); + ft_handle = NULL; + return FALSE; + } + FT_Version.major=FT_Version.minor=FT_Version.patch=-1; + if (pFT_Library_Version) + { + pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch); + } + if (FT_Version.major<=0) + { + FT_Version.major=2; + FT_Version.minor=0; + FT_Version.patch=5; + } + TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch); + FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) | + ((FT_Version.minor << 8) & 0x00ff00) | + ((FT_Version.patch ) & 0x0000ff); + + if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) { + ERR("Failed to create font mutex\n"); + return FALSE; + } + WaitForSingleObject(font_mutex, INFINITE); + + create_font_cache_key(&hkey_font_cache, &disposition); + + if(disposition == REG_CREATED_NEW_KEY) + { + delete_external_font_keys(); + init_font_list(); + } + else + load_font_list_from_cache(hkey_font_cache); + + RegCloseKey(hkey_font_cache); + + reorder_font_list(); DumpFontList(); LoadSubstList(); DumpSubstList(); - LoadReplaceList(); - update_reg_entries(); + + if(!GetEnvironmentVariableW(cx_hack_var, env_buf, sizeof(env_buf)/sizeof(WCHAR))) + LoadReplaceList(); + + if(disposition == REG_CREATED_NEW_KEY) + update_reg_entries(); init_system_links(); @@ -2767,7 +3175,7 @@ GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont) */ LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry) { - if(!strcmpW(font_link->font_name, lf.lfFaceName)) + if(!strcmpiW(font_link->font_name, lf.lfFaceName)) { TRACE("found entry in system list\n"); LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry) @@ -2778,7 +3186,7 @@ GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont) { family = face->family; if(csi.fs.fsCsb[0] & - (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) + (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0]) { if(face->scalable || can_use_bitmap) goto found; @@ -3053,6 +3461,15 @@ static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf, GdiFont *font = alloc_font(); LONG width, height; + if (face->cache_valid) + { + TRACE("Cached\n"); + memcpy(pelf,&face->elf,sizeof(ENUMLOGFONTEXW)); + memcpy(pntm,&face->ntm,sizeof(NEWTEXTMETRICEXW)); + *ptype = face->type; + return; + } + if(face->scalable) { height = 100; width = 0; @@ -3142,6 +3559,11 @@ static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf, pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */ + memcpy(&face->elf,pelf,sizeof(ENUMLOGFONTEXW)); + memcpy(&face->ntm,pntm,sizeof(NEWTEXTMETRICEXW)); + face->type = *ptype; + face->cache_valid = TRUE; + free_font(font); } @@ -3366,7 +3788,8 @@ DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format, FT_Error err; INT left, right, top = 0, bottom = 0; FT_Angle angle = 0; - FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; + FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | + FT_LOAD_NO_AUTOHINT; float widthRatio = 1.0; FT_Matrix transMat = identityMat; BOOL needsTransform = FALSE; @@ -3575,6 +3998,32 @@ DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format, unsigned int mult, row, col; BYTE *start, *ptr; + /****************** CodeWeavers hack to fix HL2 crash ************************** + * + * Both glyphs 0x2e and 0x39 of this font get rendered to a larger + * size with FreeType than under Windows, and HL2 uses a fixed size + * buffer on the stack to copy the data into. For now we'll clip glyphs + * from that font into a rather smaller BBox + * + ******************************************************************************/ + if(!strcmp(ft_face->family_name, "HL2MP") || + !strcmp(ft_face->family_name, "csd")) + { + int i; + if(lpgm->gmBlackBoxX) + lpgm->gmBlackBoxX--; + + for(i = 0; i < 2; i++) + { + if(lpgm->gmBlackBoxY) + { + lpgm->gmBlackBoxY--; + lpgm->gmptGlyphOrigin.y--; + } + } + } + /*********************************** End CW's hack ****************************/ + width = lpgm->gmBlackBoxX; height = lpgm->gmBlackBoxY; pitch = (width + 3) / 4 * 4; @@ -4153,6 +4602,10 @@ end: static BOOL load_child_font(GdiFont *font, CHILD_FONT *child) { HFONTLIST *hfontlist; + LOGFONTW lf; + static DWORD child_font_no = 0; + static const WCHAR fmt[] = {'c','h','i','l','d','%','0','8','x',0}; + child->font = alloc_font(); child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem); if(!child->font->ft_face) @@ -4164,7 +4617,10 @@ static BOOL load_child_font(GdiFont *font, CHILD_FONT *child) child->font->orientation = font->orientation; hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist)); - hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf); + memcpy(&lf, &font->font_desc.lf, sizeof(lf)); + sprintfW(lf.lfFaceName, fmt, child_font_no++); + hfontlist->hfont = CreateFontIndirectW(&lf); + child->font->name = strdupW(lf.lfFaceName); list_add_head(&child->font->hfontlist, &hfontlist->entry); child->font->base_font = font; list_add_head(&child_font_list, &child->font->entry); @@ -4185,6 +4641,18 @@ static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, if((*glyph = get_glyph_index(font, c))) return TRUE; + /* Codeweavers Hack. + * Counterstrike: Source is being greedy with memory and allocates + * about 70 versions of tahoma and then looks for glyphs in the whole + * 0 to 127 range. This causes us to load our Japanese font links for + * every dc, which causes us to use up all our memory. + * + * This is a range, given to me by Huw that we can resonably expect that + * an app would not be relying on system links to provide a glyph for. + * This allows CS to load and not load all the system links and thus. + * not use up all its memory for Japanese fonts. + */ + if (c > 31 && c != 127) LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry) { if(!child_font->font) diff --git a/dlls/gdi32/mfdrv/text.c b/dlls/gdi32/mfdrv/text.c index 8154e391673..b97bf713f17 100644 --- a/dlls/gdi32/mfdrv/text.c +++ b/dlls/gdi32/mfdrv/text.c @@ -79,56 +79,18 @@ MFDRV_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, RECT16 rect16; LPINT16 lpdx16 = NULL; BOOL ret; - unsigned int i, j; + unsigned int i; LPSTR ascii; - DWORD len; - CHARSETINFO csi; - METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev; - int charset = GetTextCharset(physDev->hdc); - UINT cp = CP_ACP; - - if(TranslateCharsetInfo((DWORD*)charset, &csi, TCI_SRCCHARSET)) - cp = csi.ciACP; - else { - switch(charset) { - case OEM_CHARSET: - cp = GetOEMCP(); - break; - case DEFAULT_CHARSET: - cp = GetACP(); - break; - - case VISCII_CHARSET: - case TCVN_CHARSET: - case KOI8_CHARSET: - case ISO3_CHARSET: - case ISO4_CHARSET: - case ISO10_CHARSET: - case CELTIC_CHARSET: - /* FIXME: These have no place here, but because x11drv - enumerates fonts with these (made up) charsets some apps - might use them and then the FIXME below would become - annoying. Now we could pick the intended codepage for - each of these, but since it's broken anyway we'll just - use CP_ACP and hope it'll go away... - */ - cp = CP_ACP; - break; - - default: - FIXME("Can't find codepage for charset %d\n", charset); - break; - } + ascii = HeapAlloc(GetProcessHeap(), 0, count); + for(i = 0; i < count; i++) { + if(str[i] > 0xff) + ascii[i] = '?'; + else + ascii[i] = (BYTE)(str[i] & 0xff); } - - TRACE("cp == %d\n", cp); - len = WideCharToMultiByte(cp, 0, str, count, NULL, 0, NULL, NULL); - ascii = HeapAlloc(GetProcessHeap(), 0, len); - WideCharToMultiByte(cp, 0, str, count, ascii, len, NULL, NULL); - TRACE("mapped %s -> %s\n", debugstr_wn(str, count), debugstr_an(ascii, len)); - + TRACE("mapped %s -> %s\n", debugstr_wn(str, count), debugstr_an(ascii, count)); if (lprect) { @@ -139,16 +101,12 @@ MFDRV_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, } if(lpDx) { - lpdx16 = HeapAlloc( GetProcessHeap(), 0, sizeof(INT16)*len ); - for(i = j = 0; i < len; ) - if(IsDBCSLeadByteEx(cp, ascii[i])) { - lpdx16[i++] = lpDx[j++]; - lpdx16[i++] = 0; - } else - lpdx16[i++] = lpDx[j++]; + lpdx16 = HeapAlloc( GetProcessHeap(), 0, sizeof(INT16)*count ); + for(i = 0; i < count; i++) + lpdx16[i] = lpDx[i]; } - ret = MFDRV_MetaExtTextOut(dev,x,y,flags,lprect?&rect16:NULL,ascii,len,lpdx16); + ret = MFDRV_MetaExtTextOut(dev,x,y,flags,lprect?&rect16:NULL,ascii,count,lpdx16); HeapFree( GetProcessHeap(), 0, ascii ); HeapFree( GetProcessHeap(), 0, lpdx16 ); return ret; diff --git a/dlls/gdi32/palette.c b/dlls/gdi32/palette.c index b4918475d03..13e755fcf09 100644 --- a/dlls/gdi32/palette.c +++ b/dlls/gdi32/palette.c @@ -192,6 +192,18 @@ HPALETTE WINAPI CreateHalftonePalette( Palette.NumberOfEntries = 20; + /* + * CODEWEAVERS HACK - Huw says: + * + * Go back to using a 256 colour halftone palette, which is what my + * version of win2k returns. + * + * This fixes display of word drawings on 8bpp displays. However it + * reverts a patch by Aric which supposedly fixed some colour issues with + * office 97, so we need to watch out for these again. + */ + return CreatePalette((LOGPALETTE *)&Palette); + for (i = 0; i < Palette.NumberOfEntries; i++) { Palette.aEntries[i].peRed=0xff; diff --git a/dlls/hlink/Makefile.in b/dlls/hlink/Makefile.in index d7ceff2f83d..5b3f10fbe18 100644 --- a/dlls/hlink/Makefile.in +++ b/dlls/hlink/Makefile.in @@ -3,7 +3,7 @@ TOPOBJDIR = ../.. SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = hlink.dll -IMPORTS = shell32 ole32 advapi32 kernel32 +IMPORTS = shell32 ole32 user32 advapi32 kernel32 IMPORTLIB = libhlink.$(IMPLIBEXT) DELAYIMPORTS = urlmon EXTRALIBS = -luuid @@ -11,7 +11,8 @@ EXTRALIBS = -luuid C_SRCS = \ browse_ctx.c \ hlink_main.c \ - link.c + link.c \ + regsvr.c @MAKE_DLL_RULES@ diff --git a/dlls/hlink/hlink.spec b/dlls/hlink/hlink.spec index 65ffd97d55a..9c7a31ae510 100644 --- a/dlls/hlink/hlink.spec +++ b/dlls/hlink/hlink.spec @@ -30,4 +30,4 @@ @ stdcall -private DllCanUnloadNow() @ stdcall -private DllGetClassObject(ptr ptr ptr) @ stdcall -private DllRegisterServer() -# @ stub -private DllUnregisterServer +@ stdcall -private DllUnregisterServer() diff --git a/dlls/hlink/hlink_main.c b/dlls/hlink/hlink_main.c index 1a595ae4bc1..723acfeeb3f 100644 --- a/dlls/hlink/hlink_main.c +++ b/dlls/hlink/hlink_main.c @@ -361,44 +361,3 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv) return IClassFactory_QueryInterface(pcf, iid, ppv); } - -static HRESULT register_clsid(LPCGUID guid) -{ - static const WCHAR clsid[] = - {'C','L','S','I','D','\\',0}; - static const WCHAR ips[] = - {'\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2',0}; - static const WCHAR hlink[] = - {'h','l','i','n','k','.','d','l','l',0}; - static const WCHAR threading_model[] = - {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0}; - static const WCHAR apartment[] = - {'A','p','a','r','t','m','e','n','t',0}; - WCHAR path[80]; - HKEY key = NULL; - LONG r; - - lstrcpyW(path, clsid); - StringFromGUID2(guid, &path[6], 80); - lstrcatW(path, ips); - r = RegCreateKeyW(HKEY_CLASSES_ROOT, path, &key); - if (r != ERROR_SUCCESS) - return E_FAIL; - - RegSetValueExW(key, NULL, 0, REG_SZ, (const BYTE *)hlink, sizeof hlink); - RegSetValueExW(key, threading_model, 0, REG_SZ, (const BYTE *)apartment, sizeof apartment); - RegCloseKey(key); - - return S_OK; -} - -HRESULT WINAPI DllRegisterServer(void) -{ - HRESULT r; - - r = register_clsid(&CLSID_StdHlink); - if (SUCCEEDED(r)) - r = register_clsid(&CLSID_StdHlinkBrowseContext); - - return S_OK; -} diff --git a/dlls/hlink/link.c b/dlls/hlink/link.c index 4d86764a977..ba554ca40af 100644 --- a/dlls/hlink/link.c +++ b/dlls/hlink/link.c @@ -655,7 +655,6 @@ static HRESULT WINAPI IPersistStream_fnSave(IPersistStream* iface, { HRESULT r = E_FAIL; HlinkImpl *This = HlinkImpl_from_IPersistStream(iface); - DWORD hdr[2]; IMoniker *moniker; FIXME("(%p) Moniker(%p)\n", This, This->Moniker); @@ -664,6 +663,8 @@ static HRESULT WINAPI IPersistStream_fnSave(IPersistStream* iface, if (moniker) { IPersistStream* monstream; + DWORD hdr[2]; + /* FIXME: Unknown values in the header */ hdr[0] = 2; hdr[1] = 2; @@ -680,6 +681,18 @@ static HRESULT WINAPI IPersistStream_fnSave(IPersistStream* iface, } IMoniker_Release(moniker); } + else if (This->Location) + { + DWORD hdr[3], len = lstrlenW(This->Location) + 1; + + /* FIXME: Unknown values in the header */ + hdr[0] = 2; + hdr[1] = 8; + hdr[2] = len; + r = IStream_Write(pStm, &hdr, sizeof(hdr), NULL); + if (SUCCEEDED(r)) r = IStream_Write(pStm, This->Location, len*sizeof(WCHAR), NULL); + } + TRACE("Save Result 0x%x\n", r); return r; diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 0aa28f0a8f1..87ff687321d 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -1446,11 +1446,28 @@ BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen) if (hIMC == (HIMC)FROM_IME) { +/* ImmInternalSetOpenStatus(fOpen); +*/ ImmInternalSendIMENotify(IMN_SETOPENSTATUS, 0); return TRUE; } + /* HACK HACK HACK + * Having this implementation cause Project 2003 to fail miserably + * The issue is that i think something is comming out of order or + * unexpetedly. + * + * Stubbing this function will have the effect that programs will be unable + * to programaticly open the IME. This should not be a large issue + * as it did not properly work anyway. + */ + if (fOpen == TRUE) + { + FIXME("IMM hack for Project 2003\n"); + return FALSE; + } + if (!data) return FALSE; diff --git a/dlls/kernel32/Makefile.in b/dlls/kernel32/Makefile.in index 09105be6615..58141b944b2 100644 --- a/dlls/kernel32/Makefile.in +++ b/dlls/kernel32/Makefile.in @@ -27,6 +27,7 @@ C_SRCS = \ console.c \ cpu.c \ debugger.c \ + device.c \ dosmem.c \ editline.c \ environ.c \ diff --git a/dlls/kernel32/file.c b/dlls/kernel32/file.c index d0b84cf2c54..09ae968a807 100644 --- a/dlls/kernel32/file.c +++ b/dlls/kernel32/file.c @@ -1339,7 +1339,11 @@ HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing, } else if (filename[4]) { - ret = VXD_Open( filename+4, access, sa ); + if (!(GetVersion() & 0x80000000)) /* there are no VxDs on NT */ + ret = Device_Open( filename+4, access, sa ); + else + ret = VXD_Open( filename+4, access, sa ); + goto done; } else @@ -1372,6 +1376,8 @@ HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing, } } + if (!creation) creation = OPEN_EXISTING; + if (creation < CREATE_NEW || creation > TRUNCATE_EXISTING) { SetLastError( ERROR_INVALID_PARAMETER ); diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index a675386e0c1..cc5b6f15060 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -133,14 +133,14 @@ # functions exported by name, ordinal doesn't matter -@ stdcall ActivateActCtx(ptr ptr) +# @ stdcall ActivateActCtx(ptr ptr) @ stdcall AddAtomA(str) @ stdcall AddAtomW(wstr) @ stub AddConsoleAliasA @ stub AddConsoleAliasW # @ stub AddLocalAlternateComputerNameA # @ stub AddLocalAlternateComputerNameW -@ stdcall AddRefActCtx(ptr) +# @ stdcall AddRefActCtx(ptr) @ stdcall AddVectoredExceptionHandler(long ptr) ntdll.RtlAddVectoredExceptionHandler @ stdcall AllocConsole() @ stub AllocLSCallback @@ -209,8 +209,8 @@ @ stdcall CopyFileExW (wstr wstr ptr ptr ptr long) @ stdcall CopyFileW(wstr wstr long) @ stdcall CopyLZFile(long long) LZCopy -@ stdcall CreateActCtxA(ptr) -@ stdcall CreateActCtxW(ptr) +# @ stdcall CreateActCtxA(ptr) +# @ stdcall CreateActCtxW(ptr) @ stdcall CreateConsoleScreenBuffer(long long ptr long ptr) @ stdcall CreateDirectoryA(str ptr) @ stdcall CreateDirectoryExA(str str ptr) @@ -257,7 +257,7 @@ @ stub CreateVirtualBuffer @ stdcall CreateWaitableTimerA(ptr long str) @ stdcall CreateWaitableTimerW(ptr long wstr) -@ stdcall DeactivateActCtx(long ptr) +# @ stdcall DeactivateActCtx(long ptr) @ stdcall DebugActiveProcess(long) @ stdcall DebugActiveProcessStop(long) @ stdcall DebugBreak() @@ -358,9 +358,9 @@ @ stdcall FillConsoleOutputAttribute(long long long long ptr) @ stdcall FillConsoleOutputCharacterA(long long long long ptr) @ stdcall FillConsoleOutputCharacterW(long long long long ptr) -@ stdcall FindActCtxSectionGuid(long ptr long ptr ptr) -@ stdcall FindActCtxSectionStringA(long ptr long str ptr) -@ stdcall FindActCtxSectionStringW(long ptr long wstr ptr) +# @ stdcall FindActCtxSectionGuid(long ptr long ptr ptr) +# @ stdcall FindActCtxSectionStringA(long ptr long str ptr) +# @ stdcall FindActCtxSectionStringW(long ptr long wstr ptr) @ stdcall FindAtomA(str) @ stdcall FindAtomW(wstr) @ stdcall FindClose(long) @@ -473,7 +473,7 @@ @ stdcall GetConsoleWindow() @ stdcall GetCurrencyFormatA(long long str ptr str long) @ stdcall GetCurrencyFormatW(long long str ptr str long) -@ stdcall GetCurrentActCtx(ptr) +# @ stdcall GetCurrentActCtx(ptr) @ stub GetCurrentConsoleFont @ stdcall GetCurrentDirectoryA(long ptr) @ stdcall GetCurrentDirectoryW(long ptr) @@ -842,7 +842,7 @@ @ stdcall PulseEvent(long) @ stdcall PurgeComm(long long) @ stdcall -i386 -register QT_Thunk() -@ stdcall QueryActCtxW(long ptr ptr long ptr long ptr) +# @ stdcall QueryActCtxW(long ptr ptr long ptr long ptr) @ stdcall QueryDepthSList(ptr) ntdll.RtlQueryDepthSList @ stdcall QueryDosDeviceA(str ptr long) @ stdcall QueryDosDeviceW(wstr ptr long) @@ -878,12 +878,12 @@ @ stdcall RegisterServiceProcess(long long) @ stub RegisterSysMsgHandler @ stub RegisterWaitForInputIdle -@ stdcall RegisterWaitForSingleObject(ptr long ptr ptr long long) -@ stdcall RegisterWaitForSingleObjectEx(long ptr ptr long long) +#@ stdcall RegisterWaitForSingleObject(ptr long ptr ptr long long) +#@ stdcall RegisterWaitForSingleObjectEx(long ptr ptr long long) @ stub RegisterWowBaseHandlers @ stub RegisterWowExec @ stdcall ReinitializeCriticalSection(ptr) -@ stdcall ReleaseActCtx(ptr) +# @ stdcall ReleaseActCtx(ptr) @ stdcall ReleaseMutex(long) @ stdcall ReleaseSemaphore(long long ptr) @ stdcall RemoveDirectoryA(str) @@ -1145,7 +1145,7 @@ @ stdcall WriteProfileStringA(str str str) @ stdcall WriteProfileStringW(wstr wstr wstr) @ stdcall WriteTapemark(ptr long long long) -@ stdcall ZombifyActCtx(ptr) +# @ stdcall ZombifyActCtx(ptr) @ stub _DebugOut @ stub _DebugPrintf @ stdcall _hread(long ptr long) diff --git a/dlls/kernel32/kernel_main.c b/dlls/kernel32/kernel_main.c index 9f6b3114687..f37a6e7ee8a 100644 --- a/dlls/kernel32/kernel_main.c +++ b/dlls/kernel32/kernel_main.c @@ -67,6 +67,7 @@ static void thread_detach(void) if (NtCurrentTeb()->Tib.SubSystemTib) TASK_ExitTask(); } +BOOL o2ksr1hack; /*********************************************************************** * KERNEL process initialisation routine @@ -109,10 +110,14 @@ static BOOL process_attach(void) ENV_CopyStartupInformation(); #ifdef __i386__ + /* Bit of a CodeWeavers Hack, winehq made it so that win2k mode + * no longer did this. We need it for native dcom95. So until our + * ole implementation works right we need the shared heap*/ + /* create the shared heap for broken win95 native dlls */ + HeapCreate( HEAP_SHARED, 0, 0 ); + if (GetVersion() & 0x80000000) { - /* create the shared heap for broken win95 native dlls */ - HeapCreate( HEAP_SHARED, 0, 0 ); /* setup emulation of protected instructions from 32-bit code */ RtlAddVectoredExceptionHandler( TRUE, INSTR_vectored_handler ); } @@ -137,6 +142,11 @@ static BOOL process_attach(void) LoadLibrary16( "krnl386.exe" ); thread_attach(); TASK_CreateMainTask(); + + { + const WCHAR hack_var_name[] = {'C','X','_','O','2','K','_','S','R','1',0}; + o2ksr1hack = GetEnvironmentVariableW(hack_var_name, NULL, 0); + } return TRUE; } diff --git a/dlls/kernel32/kernel_private.h b/dlls/kernel32/kernel_private.h index 4796e62ce07..976ee4bd2d9 100644 --- a/dlls/kernel32/kernel_private.h +++ b/dlls/kernel32/kernel_private.h @@ -103,6 +103,13 @@ extern enum binary_type MODULE_GetBinaryType( HANDLE hfile, void **res_start, vo extern BOOL NLS_IsUnicodeOnlyLcid(LCID); extern HANDLE VXD_Open( LPCWSTR filename, DWORD access, LPSECURITY_ATTRIBUTES sa ); +extern HANDLE Device_Open( LPCWSTR filename, DWORD access, LPSECURITY_ATTRIBUTES sa ); + +extern BOOL Device_DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, + LPVOID lpvInBuffer, DWORD cbInBuffer, + LPVOID lpvOutBuffer, DWORD cbOutBuffer, + LPDWORD lpcbBytesReturned, + LPOVERLAPPED lpOverlapped); extern WORD DOSMEM_0000H; extern WORD DOSMEM_BiosDataSeg; diff --git a/dlls/kernel32/sync.c b/dlls/kernel32/sync.c index 8ee0e718c0b..4c301210b7d 100644 --- a/dlls/kernel32/sync.c +++ b/dlls/kernel32/sync.c @@ -110,6 +110,7 @@ DWORD WINAPI SleepEx( DWORD timeout, BOOL alertable ) return status; } +extern BOOL o2ksr1hack; /*********************************************************************** * SwitchToThread (KERNEL32.@) @@ -125,6 +126,14 @@ BOOL WINAPI SwitchToThread(void) */ DWORD WINAPI WaitForSingleObject( HANDLE handle, DWORD timeout ) { + if(o2ksr1hack && handle == (HANDLE)0xffffffff) { + DWORD ret; + FIXME("invoking WaitForSingleObject hack\n"); + handle = OpenEventA(0x001f0003,0,"MsiFDIInterface"); + ret = WaitForMultipleObjectsEx( 1, &handle, FALSE, timeout, FALSE ); + CloseHandle(handle); + return ret; + } return WaitForMultipleObjectsEx( 1, &handle, FALSE, timeout, FALSE ); } @@ -549,7 +558,6 @@ BOOL WINAPI PulseEvent( HANDLE handle ) return !status; } - /*********************************************************************** * SetW32Event (KERNEL.458) * SetEvent (KERNEL32.@) @@ -557,7 +565,14 @@ BOOL WINAPI PulseEvent( HANDLE handle ) BOOL WINAPI SetEvent( HANDLE handle ) { NTSTATUS status; - + if(o2ksr1hack && handle == (HANDLE)0xffffffff) { + FIXME("invoking SetEvent hack\n"); + handle = OpenEventA(0x001f0003,0,"MsiFDIServer"); + if ((status = NtSetEvent( handle, NULL ))) + SetLastError( RtlNtStatusToDosError(status) ); + CloseHandle(handle); + return !status; + } if ((status = NtSetEvent( handle, NULL ))) SetLastError( RtlNtStatusToDosError(status) ); return !status; diff --git a/dlls/kernel32/tests/time.c b/dlls/kernel32/tests/time.c index 4ce3851b0fd..b702759047e 100644 --- a/dlls/kernel32/tests/time.c +++ b/dlls/kernel32/tests/time.c @@ -20,6 +20,7 @@ #include "wine/test.h" #include "winbase.h" +#include "winnls.h" #define SECSPERMIN 60 #define SECSPERDAY 86400 @@ -153,11 +154,104 @@ static void test_invalid_arg(void) ok( !SystemTimeToFileTime(&st, &ft), "bad minute\n"); } - + +typedef struct { + const char *env; + const char *windows_name; +} tztestinfo; + +static tztestinfo timezones[]= +{ + {"Kwajalein", "Dateline Standard Time"}, + {"Pacific/Samoa", "Samoa Standard Time"}, + {"US/Hawaii", "Hawaiian Standard Time"}, + {"US/Alaska", "Alaskan Standard Time"}, + {"America/Tijuana", "Pacific Standard Time"}, + {"America/Chihuahua", "Mexico Standard Time 2"}, + {"US/Mountain", "Mountain Standard Time"}, + {"US/Arizona", "US Mountain Standard Time"}, + {"US/Central", "Central Standard Time"}, + {"America/Mexico_City", "Mexico Standard Time"}, + {"Canada/Saskatchewan", "Canada Central Standard Time"}, + {"America/El_Salvador", "Central America Standard Time"}, + {"US/Eastern", "Eastern Standard Time"}, + {"US/Indiana-Starke", "US Eastern Standard Time"}, + {"America/Bogota", "SA Pacific Standard Time"}, + {"America/Lima", "SA Pacific Standard Time"}, + {"Canada/Atlantic", "Atlantic Standard Time"}, + {"America/Caracas", "SA Western Standard Time"}, + {"America/Santiago", "Pacific SA Standard Time"}, + {"Canada/Newfoundland", "Newfoundland Standard Time"}, + {"America/Buenos_Aires","SA Eastern Standard Time"}, + {"Brazil/East", "E. South America Standard Time"}, + /* Greenland Standard Time */ + /* Mid-Atlantic Standard Time */ + {"Atlantic/Azores", "Azores Standard Time"}, + {"Atlantic/Cape_Verde", "Cape Verde Standard Time"}, + {"Africa/Casablanca", "Greenwich Standard Time"}, + {"Europe/London", "GMT Standard Time"}, + {"Europe/Paris", "Romance Standard Time"}, + /* W. Central Africa Standard Time */ + {"Europe/Belgrade", "Central Europe Standard Time"}, + {"Africa/Cairo", "Egypt Standard Time"}, + {"Africa/Johannesburg", "South Africa Standard Time"}, + {"Israel", "Israel Standard Time"}, + {"Europe/Bucharest", "E. Europe Standard Time"}, + {"Europe/Helsinki", "FLE Standard Time"}, + {"Europe/Athens", "GTB Standard Time"}, + {"Asia/Kuwait", "Arab Standard Time"}, + {"Africa/Nairobi", "E. Africa Standard Time"}, + {"Asia/Baghdad", "Arabic Standard Time"}, + {"Europe/Moscow", "Russian Standard Time"}, + {"Asia/Tehran", "Iran Standard Time"}, + {"Asia/Muscat", "Arabian Standard Time"}, + {"Asia/Baku", "Caucasus Standard Time"}, + {"Asia/Kabul", "Afghanistan Standard Time"}, + {"Asia/Karachi", "West Asia Standard Time"}, + /* Ekaterinburg Standard Time */ + {"Asia/Calcutta", "India Standard Time"}, + /* Nepal Standard Time */ + {"Asia/Dhaka", "Central Asia Standard Time"}, + /* Sri Lanka Standard Time */ + {"Asia/Novosibirsk", "N. Central Asia Standard Time"}, + {"Asia/Rangoon", "Myanmar Standard Time"}, + {"Asia/Bangkok", "SE Asia Standard Time"}, + {"Asia/Krasnoyarsk", "North Asia Standard Time"}, + {"Asia/Shanghai", "China Standard Time"}, + {"Australia/Perth", "W. Australia Standard Time"}, + {"Asia/Singapore", "Singapore Standard Time"}, + {"Asia/Taipei", "Taipei Standard Time"}, + {"Asia/Irkutsk", "North Asia East Standard Time"}, + {"Japan", "Tokyo Standard Time"}, + {"Asia/Seoul", "Korea Standard Time"}, + {"Asia/Yakutsk", "Yakutsk Standard Time"}, + {"Australia/Darwin", "AUS Central Standard Time"}, + {"Australia/Adelaide", "Cen. Australia Standard Time"}, + {"Australia/Brisbane", "E. Australia Standard Time"}, + {"Pacific/Guam", "West Pacific Standard Time"}, + {"Asia/Vladivostok", "Vladivostok Standard Time"}, + {"Asia/Magadan", "Central Pacific Standard Time"}, + {"Pacific/Fiji", "Fiji Standard Time"}, + {"Pacific/Auckland", "New Zealand Standard Time"}, + {"Pacific/Tongatapu", "Tonga Standard Time"} +}; + +static tztestinfo todo_timezones[]= +{ + {"Europe/Berlin", "W. Europe Standard Time"}, + {"Europe/Budapest", "Central European Standard Time"}, + {"Australia/Melbourne", "AUS Eastern Standard Time"}, + {"Australia/Hobart", "Tasmania Standard Time"}, +}; + static void test_GetTimeZoneInformation(void) { TIME_ZONE_INFORMATION tzinfo, tzinfo1; DWORD res = GetTimeZoneInformation(&tzinfo); + CHAR tzname[32]; + const char *originaltz; + int i; + ok(res != TIME_ZONE_ID_INVALID, "GetTimeZoneInformation failed\n"); ok(SetEnvironmentVariableA("TZ","GMT0") != 0, "SetEnvironmentVariableA failed\n"); @@ -170,7 +264,35 @@ static void test_GetTimeZoneInformation(void) "Bias influenced by TZ variable\n"); ok(SetEnvironmentVariableA("TZ",NULL) != 0, "SetEnvironmentVariableA failed\n"); - + + /* Check handling of timezones around the world*/ + originaltz = getenv("TZ"); + for (i = 0; i < sizeof(timezones)/sizeof(tztestinfo); i++) + { + setenv("TZ",timezones[i].env,1); + res = GetTimeZoneInformation(&tzinfo1); + WideCharToMultiByte(CP_ACP,0,tzinfo1.StandardName,-1,tzname,32,0,0); + ok(strcmp(tzname,timezones[i].windows_name)==0,"%s failed, result %s\n" + ,timezones[i].windows_name,tzname); + } + + for (i = 0; i < sizeof(todo_timezones)/sizeof(tztestinfo); i++) + { + setenv("TZ",todo_timezones[i].env,1); + res = GetTimeZoneInformation(&tzinfo1); + WideCharToMultiByte(CP_ACP,0,tzinfo1.StandardName,-1,tzname,32,0,0); + todo_wine { + ok(strcmp(tzname,todo_timezones[i].windows_name)==0, + "%s failed, result %s\n" ,todo_timezones[i].windows_name,tzname); + } + } + + + if (originaltz) + setenv("TZ",originaltz,1); + else + unsetenv("TZ"); + } static void test_FileTimeToSystemTime(void) diff --git a/dlls/kernel32/time.c b/dlls/kernel32/time.c index 08002afb132..7ee6f1d38ce 100644 --- a/dlls/kernel32/time.c +++ b/dlls/kernel32/time.c @@ -2,6 +2,7 @@ * Win32 kernel time functions * * Copyright 1995 Martin von Loewis and Cameron Heide + * Copyright 2002,2005 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 @@ -24,6 +25,7 @@ #ifdef HAVE_UNISTD_H # include #endif +#include #include #include #include @@ -37,6 +39,14 @@ #include #elif defined(HAVE_MACHINE_LIMITS_H) #include +#else +#include +#endif + +#ifdef linux +#include +#include +#include "tzfile.h" #endif #define NONAMELESSUNION @@ -69,6 +79,760 @@ static const int MonthLengths[2][12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } }; +/* + * This structure is used to store strings that represent all of the time zones + * in the world. (This is used to help GetTimeZoneInformation) + */ +struct tagTZ_INFO +{ + /* + * These two are from the unix /usr/share/zoneinfo files + */ + const char *psTZFromUnix0; + const char *psTZFromUnix1; + /* + * this is the windows registry key for this timezone + */ + CHAR psTZWindows[32]; + /* + * these are also from the return zoneinfo are are use to help find a + * difinitive match + */ + int bias; + int dst; + /* 0 if no possiblility for dups, otherwise set based on number of + * transisionts this timezone has seen. This should help with things like + * Central American vs Central Time US vs Mexico Standard Time + */ + int types; + const char *psTZFromUnixFirst; +}; + +/* + * These are searched top to bottom with the first match being returned + * There are a number of duplicates which we will need to work harder + * To identify uniquly. + * Please feel free to add more if you find windows registry values for more + * time zones. */ + +static const struct tagTZ_INFO TZ_INFO[] = +{ + {"MHT","MHT","Dateline Standard Time",-43200,0,0,""}, + {"SST","SST","Samoa Standard Time",39600,0,0,""}, + {"HST","HPT","Hawaiian Standard Time",36000,1,0,""}, + {"AKST","AKDT","Alaskan Standard Time", 32400,1,0,""}, + {"PST","PDT","Pacific Standard Time",28800,1,0,""}, + {"MST","MDT","Mountain Standard Time",25200,1,4,""}, + {"MST","MDT","Mexico Standard Time 2",25200,1,5,""}, + {"MST","MDT","US Mountain Standard Time",25200,1,3,""}, + /*catch*/{"MST","MDT","Mountain Standard Time",25200,1,0,""}, + {"CST","CDT","Central Standard Time",21600,1,5,"CDT"}, + {"CST","MDT","Canada Central Standard Time",21600,0,0,""}, + {"CST","CDT","Mexico Standard Time",21600,1,5,"LMT"}, + {"CST","CDT","Central America Standard Time",21600,1,3,""}, + /*catch*/{"CST","CDT","Central Standard Time",21600,1,0,""}, + {"EST","EDT","Eastern Standard Time",18000,1,0,""}, + {"EST","CDT","US Eastern Standard Time",18000,0,0,""}, + {"COT","COST","SA Pacific Standard Time",18000,1,0,""},/*Bogota*/ + {"PET","PEST","SA Pacific Standard Time",18000,1,0,""}, + {"AST","ADT","Atlantic Standard Time",14400,1,0,""}, + {"VET","VET","SA Western Standard Time",14400,0,0,""}, + {"CLT","CLST","Pacific SA Standard Time",14400,1,0,""}, + {"NST","NDT","Newfoundland Standard Time",12600,1,0,""}, + {"BRT","BRST","E. South America Standard Time",10800,1,0,""}, + {"ART","ARST","SA Eastern Standard Time",10800,0,0,""}, + /*Greenland Standard Time*/ + /* Mid-Atlantic Standard Time */ + {"AZOT","AZOST","Azores Standard Time",3600,1,0,""}, + {"CVT","CVST","Cape Verde Standard Time",3600,0,0,""}, + {"GMT","BST","GMT Standard Time",0,1,0,""}, + {"WET","WEST","Greenwich Standard Time",0,1,0,""}, + {"CET","CEST","Central Europe Standard Time",-3600,1,6,""}, + {"CET","CEST","Central European Standard Time",-3600,1,10,""}, + {"CET","CEST","Romance Standard Time",-3600,1,12,""}, + /*catch*/ {"CET","CEST","Central Europe Standard Time",-3600,1,0,""}, + {"WET","WEST","W. Europe Standard Time",-3600,1,0,""}, + /* W. Central Africa Standard Time */ + {"EET","EEST","E. Europe Standard Time",-7200,1,7,""}, + {"EET","EEST","Egypt Standard Time",-7200,1,4,""}, + {"EET","EEST","FLE Standard Time",-7200,1,5,""}, + {"EET","EEST","GTB Standard Time",-7200,1,9,""}, + /*catch*/{"EET","EEST","E. Europe Standard Time",-7200,1,0,""}, + {"IST","IDT","Israel Standard Time",-7200,1,0,""}, + {"SAST","SAST","South Africa Standard Time",-7200,1,0,""}, + {"MSK","MSD","Russian Standard Time",-10800,1,0,""}, + {"AST","AST","Arab Standard Time",-10800,0,0,""}, + {"EAT","EAT","E. Africa Standard Time",-10800,0,0,""}, + {"AST","ADT","Arabic Standard Time",-10800,1,0,""}, + {"IRST","IRDT","Iran Standard Time",-12600,1,0,""}, + {"GST","GST","Arabian Standard Time",-14400,0,0,""}, + {"AZT","AZST","Caucasus Standard Time",-14400,1,0,""}, + {"AFT","AFT", "Afghanistan Standard Time", -16200,0,0,""}, + /* Ekaterinburg Standard Time */ + {"PKT","PKST","West Asia Standard Time",-18000,1,0,""}, + {"IST","IST","India Standard Time",-19800,1,0,""}, + /* Nepal Standard Time */ + {"BDT","BDT","Central Asia Standard Time",-21600,0,0,""}, + /* Sri Lanka Standard Time */ + {"NOVT","NOVST","N. Central Asia Standard Time", -21600,1,0,""}, + {"MMT","MMT","Myanmar Standard Time",-23400,0,0,""}, + {"ICT","ICT","SE Asia Standard Time",-25200,0,0,""}, + {"KRAT","KRAST","North Asia Standard Time",-25200,1,0,""}, + {"CST","CDT","China Standard Time",-28800,1,4,""}, + {"SGT","MALST","Singapore Standard Time",-28800,1,0,""}, + {"CST","CDT","Taipei Standard Time",-28800,1,2,""}, + /*catch*/{"CST","CDT","China Standard Time",-28800,1,0,""}, + {"WST","WST","W. Australia Standard Time",-28800,1,0,""}, + {"IRKT","IRKST","North Asia East Standard Time",-28800,1,0,""}, + {"KST","KDT","Korea Standard Time",-32400,1,0,""}, + {"JST","JST","Tokyo Standard Time",-32400,0,0,""}, + {"YAKT","YAKST","Yakutsk Standard Time",-32400,1,0,""}, + {"CST","CST","AUS Central Standard Time",-34200,1,2,""}, + /*catch*/{"CST","CST","Cen. Australia Standard Time",-34200,1,0,""}, + /*AUS Eastern Standard Time*/ + {"EST","EST","E. Australia Standard Time",-36000,1,0,""}, + /*Tasmania Standard Time*/ + {"VLAT","VLAST","Vladivostok Standard Time",-36000,1,0,""}, + {"ChST","ChST","West Pacific Standard Time", -36000,0,0,""}, + {"MAGT","MAGST","Central Pacific Standard Time",-39600,1,0,""}, + {"FJT","FJST","Fiji Standard Time",-43200,1,0,""}, + {"NZST","NZDT","New Zealand Standard Time",-43200,1,0,""}, + {"TOT","TOST","Tonga Standard Time",-46800,1,0,""}, +}; + + +/**************************************************************************** + * The following code was lifted from glibc under the LGPL and modified to do + * what we need it to do. + ****************************************************************************/ + +/* Here are the main values! */ +static char *wine__tzname[2]; +static char *wine__tzcode; +static int wine__daylight; +static long int wine__timezone; + +#ifdef linux +/****** + * STRUCTS + ******/ +struct ttinfo + { + long int offset; /* Seconds east of GMT. */ + unsigned char isdst; /* Used to set tm_isdst. */ + unsigned char idx; /* Index into `zone_names'. */ + unsigned char isstd; /* Transition times are in standard time. */ + unsigned char isgmt; /* Transition times are in GMT. */ + }; + +struct leap + { + time_t transition; /* Time the transition takes effect. */ + long int change; /* Seconds of correction to apply. */ + }; + +/* List of buffers containing time zone strings. */ +struct tzstring_l +{ + struct tzstring_l *next; + size_t len; /* strlen(data) - doesn't count terminating NUL! */ + char data[0]; +}; + +/********* + * GLOBALS + *********/ + +struct tzstring_l *tzstring_list; +static size_t num_transitions=0; +static time_t *transitions=NULL; +static unsigned char *type_idxs=NULL; +static size_t num_types=0; +static struct ttinfo *types=NULL; +static char *zone_names=NULL; +static long int rule_stdoff=0; +static long int rule_dstoff=0; +static size_t num_leaps=0; +static struct leap *leaps=NULL; +static int __use_tzfile=0; +static size_t __tzname_cur_max = 0; + +/************ + * FUNCTIONS + ************/ + +static void compute_tzname_max (size_t chars) +{ + const char *p; + + p = zone_names; + do + { + const char *start = p; + while (*p != '\0') + ++p; + if ((size_t) (p - start) > __tzname_cur_max) + __tzname_cur_max = p - start; + } + while (++p < &zone_names[chars]); +} + +/* Decode the four bytes at PTR as a signed integer in network byte order. */ +static inline int decode (const void *ptr) +{ + if ((BYTE_ORDER == BIG_ENDIAN) && sizeof (int) == 4) + return *(const int *) ptr; + else if (BYTE_ORDER == LITTLE_ENDIAN && sizeof (int) == 4) + return bswap_32 (*(const int *) ptr); + else + { + const unsigned char *p = ptr; + int result = *p & (1 << (CHAR_BIT - 1)) ? ~0 : 0; + + result = (result << 8) | *p++; + result = (result << 8) | *p++; + result = (result << 8) | *p++; + result = (result << 8) | *p++; + + return result; + } +} + +char * __tzstring (const char *s) +{ + char *p; + struct tzstring_l *t, *u, *new; + size_t len = strlen(s); + + /* Walk the list and look for a match. If this string is the same + as the end of an already-allocated string, it can share space. */ + for (u = t = tzstring_list; t; u = t, t = t->next) + if (len <= t->len) + { + p = &t->data[t->len - len]; + if (strcmp (s, p) == 0) + return p; + } + + /* Not found; allocate a new buffer. */ + new = malloc (sizeof (struct tzstring_l) + len + 1); + if (!new) + return NULL; + + new->next = NULL; + new->len = len; + strcpy (new->data, s); + + if (u) + u->next = new; + else + tzstring_list = new; + + return new->data; +} + +void __tzfile_read (const char *file, size_t extra, char **extrap) +{ + static const char default_tzdir[] = TZDIR; + size_t num_isstd, num_isgmt; + register FILE *f; + struct tzhead tzhead; + size_t chars; + register size_t i; + size_t total_size; + size_t types_idx; + size_t leaps_idx; + + __use_tzfile = 0; + + if (transitions != NULL) + free ((void *) transitions); + + transitions = NULL; + + if (file == NULL) +{ + /* No user specification; use the site-wide default. */ + file = TZDEFAULT; +} + else if (*file == '\0') + { + /* User specified the empty string; use UTC with no leap seconds. */ + return; + } + else + { + /* We must not allow to read an arbitrary file in a setuid + program. So we fail for any file which is not in the + directory hierachy starting at TZDIR + and which is not the system wide default TZDEFAULT. */ + if (( *file == '/' + && memcmp (file, TZDEFAULT, sizeof(TZDEFAULT)) + && memcmp (file, default_tzdir, sizeof (default_tzdir) - 1)) + || strstr (file, "../") != NULL) + { + /* This test is certainly a bit too restrictive but it should + catch all critical cases. */ + ERR("security check failed, check location of localtime file\n"); + return; + } + } + + if (*file != '/') + { + const char *tzdir; + unsigned int len, tzdir_len; + char *new, *tmp; + + tzdir = getenv ("TZDIR"); + if (tzdir == NULL || *tzdir == '\0') + { + tzdir = default_tzdir; + tzdir_len = strlen (default_tzdir); + } + else + tzdir_len = strlen (tzdir); + + len = strlen (file) + 1; + new = (char *) malloc (tzdir_len + 1 + len); + memcpy (new, tzdir, tzdir_len); + tmp = new+tzdir_len; + *tmp++ = '/'; + memcpy (tmp, file, len); + file = new; + } + + f = fopen (file, "r"); + if (f == NULL) + return; + + if (fread_unlocked ((void *) &tzhead, sizeof (tzhead), 1, f) != 1) + goto lose; + + num_transitions = (size_t) decode (tzhead.tzh_timecnt); + num_types = (size_t) decode (tzhead.tzh_typecnt); + chars = (size_t) decode (tzhead.tzh_charcnt); + num_leaps = (size_t) decode (tzhead.tzh_leapcnt); + num_isstd = (size_t) decode (tzhead.tzh_ttisstdcnt); + num_isgmt = (size_t) decode (tzhead.tzh_ttisgmtcnt); + + total_size = num_transitions * (sizeof (time_t) + 1); + total_size = ((total_size + __alignof__ (struct ttinfo) - 1) + & ~(__alignof__ (struct ttinfo) - 1)); + types_idx = total_size; + total_size += num_types * sizeof (struct ttinfo) + chars; + total_size = ((total_size + __alignof__ (struct leap) - 1) + & ~(__alignof__ (struct leap) - 1)); + leaps_idx = total_size; + total_size += num_leaps * sizeof (struct leap); + /* This is for the extra memory required by the caller. */ + total_size += extra; + + transitions = (time_t *) malloc (total_size); + if (transitions == NULL) + goto lose; + + type_idxs = (unsigned char *) transitions + (num_transitions + * sizeof (time_t)); + types = (struct ttinfo *) ((char *) transitions + types_idx); + zone_names = (char *) types + num_types * sizeof (struct ttinfo); + leaps = (struct leap *) ((char *) transitions + leaps_idx); + if (extra > 0) + *extrap = (char *) &leaps[num_leaps]; + + if (sizeof (time_t) < 4) + abort (); + + if (sizeof (time_t) == 4) + { + if (fread_unlocked (transitions, 1, (4 + 1) * num_transitions, f) + != (4 + 1) * num_transitions) + goto lose; + } + else + { + if (fread_unlocked (transitions, 4, num_transitions, f) + != num_transitions + || fread_unlocked (type_idxs, 1, num_transitions, f) + != num_transitions) + goto lose; + } + + /* Check for bogus indices in the data file, so we can hereafter + safely use type_idxs[T] as indices into `types' and never crash. */ + for (i = 0; i < num_transitions; ++i) + if (type_idxs[i] >= num_types) + goto lose; + + if (BYTE_ORDER != BIG_ENDIAN || sizeof (time_t) != 4) + { + /* Decode the transition times, stored as 4-byte integers in + network (big-endian) byte order. We work from the end of + the array so as not to clobber the next element to be + processed when sizeof (time_t) > 4. */ + i = num_transitions; + while (i-- > 0) + transitions[i] = decode ((char *) transitions + i * 4); + } + + for (i = 0; i < num_types; ++i) + { + unsigned char x[4]; + int c; + if (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x)) + goto lose; + c = getc_unlocked (f); + if ((unsigned int) c > 1u) + goto lose; + types[i].isdst = c; + c = getc_unlocked (f); + if ((size_t) c > chars) /* Bogus index in data file. */ + goto lose; + types[i].idx = c; + types[i].offset = (long int) decode (x); + } + + if (fread_unlocked (zone_names, 1, chars, f) != chars) + goto lose; + + for (i = 0; i < num_leaps; ++i) + { + unsigned char x[4]; + if (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x)) + goto lose; + leaps[i].transition = (time_t) decode (x); + if (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x)) + goto lose; + leaps[i].change = (long int) decode (x); + } + + for (i = 0; i < num_isstd; ++i) + { + int c = getc_unlocked (f); + if (c == EOF) + goto lose; + types[i].isstd = c != 0; + } + while (i < num_types) + types[i++].isstd = 0; + + for (i = 0; i < num_isgmt; ++i) + { + int c = getc_unlocked (f); + if (c == EOF) + goto lose; + types[i].isgmt = c != 0; + } + while (i < num_types) + types[i++].isgmt = 0; + + fclose (f); + + /* First "register" all timezone names. */ + for (i = 0; i < num_types; ++i) + { + TRACE("%s (%i %i %i)\n",&zone_names[types[i].idx],types[i].isdst, + types[i].isstd, types[i].isgmt); + + (void) __tzstring (&zone_names[types[i].idx]); + + } + + + /* Find the standard and daylight time offsets used by the rule file. + We choose the offsets in the types of each flavor that are + transitioned to earliest in time. */ + wine__tzname[0] = NULL; + wine__tzname[1] = NULL; + wine__tzcode = NULL; + + /* for dup matching */ + wine__tzcode = __tzstring(&zone_names[types[0].idx]);; + + for (i = num_transitions; i > 0; ) + { + int type = type_idxs[--i]; + int dst = types[type].isdst; + + if (wine__tzname[dst] == NULL) + { + int idx = types[type].idx; + + wine__tzname[dst] = __tzstring (&zone_names[idx]); + + if (wine__tzname[1 - dst] != NULL) + break; + } + } + if (wine__tzname[0] == NULL) + { + /* This should only happen if there are no transition rules. + In this case there should be only one single type. */ + wine__tzname[0] = __tzstring (zone_names); + } + if (wine__tzname[1] == NULL) + wine__tzname[1] = wine__tzname[0]; + + compute_tzname_max (chars); + + if (num_transitions == 0) + /* Use the first rule (which should also be the only one). */ + rule_stdoff = rule_dstoff = types[0].offset; + else + { + int stdoff_set = 0, dstoff_set = 0; + rule_stdoff = rule_dstoff = 0; + i = num_transitions - 1; + do + { + if (!stdoff_set && !types[type_idxs[i]].isdst) + { + stdoff_set = 1; + rule_stdoff = types[type_idxs[i]].offset; + } + else if (!dstoff_set && types[type_idxs[i]].isdst) + { + dstoff_set = 1; + rule_dstoff = types[type_idxs[i]].offset; + } + if (stdoff_set && dstoff_set) + break; + } + while (i-- > 0); + + if (!dstoff_set) + rule_dstoff = rule_stdoff; + } + + TRACE("stdoff %lx, dstoff %lx\n",rule_stdoff,rule_dstoff); + + /* does daylight savings time ever apply in this timezone? NB: NOT does DST apply right now */ + wine__daylight = rule_stdoff != rule_dstoff; + wine__timezone = -rule_stdoff; + + __use_tzfile = 1; + return; + + lose: + fclose (f); +} + +static void TIME_GetTZTransitionDates( time_t *dst, time_t *sdt) +{ + time_t currtime; + int i,j; + + *dst = 0; + *sdt = 0; + + if (!wine__daylight) + return; + + time(&currtime); + + for (i = 1; i < num_transitions; ++i) + if (currtime < transitions[i]) + break; + + if (i == num_transitions) + return; + + j = type_idxs[i-1]; + + if (types[j].isdst) + { + *dst = transitions[i-1]; + *sdt = transitions[i]; + } + else + { + j = type_idxs[i]; + if (types[j].isdst) + { + *sdt = transitions[i-1]; + *dst = transitions[i]; + } + } +} + +static void TIME_InitTZInfo() +{ + register const char *tz; + static char *old_tz = NULL; + + /* Examine the TZ environment variable. */ + tz = getenv ("TZ"); + if (tz == NULL) + /* No user specification; use the site-wide default. */ + tz = TZDEFAULT; + else if (*tz == '\0') + /* User specified the empty string; use UTC explicitly. */ + tz = "Universal"; + /* A leading colon means "implementation defined syntax". + We ignore the colon and always use the same algorithm: + try a data file, and if none exists parse the 1003.1 syntax. */ + if (tz && *tz == ':') + ++tz; + + /* Check whether the value changes since the last run. */ + if (old_tz != NULL && tz != NULL && strcmp (tz, old_tz) == 0) + /* No change, simply return. */ + return; + + /* Save the value of `tz'. */ + if (old_tz != NULL) + free (old_tz); + old_tz = tz ? __strdup (tz) : NULL; + + /* Try to read a data file. */ + __tzfile_read (tz, 0, NULL); + + if (!__use_tzfile) + { + tzset(); + wine__tzname[0] = tzname[0]; + wine__tzname[1] = tzname[1]; + wine__tzcode = NULL; + wine__timezone = timezone; + wine__daylight = daylight; + } +} + +static DWORD TIME_GetTimeNameFromReg (const CHAR* key, const CHAR* type, + WCHAR* name, INT size) +{ + HKEY hkey; + LONG rc; + OBJECT_ATTRIBUTES attr; + UNICODE_STRING nameW; + CHAR skeya[1024]; + WCHAR subkey[1024]; + WCHAR skey[9]; + + strcpy(skeya,"Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\Time Zones\\"); + strcat(skeya,key); + + MultiByteToWideChar(CP_ACP,0, skeya, -1,subkey,1024); + MultiByteToWideChar(CP_ACP,0, type, -1,skey, 9); + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = &nameW; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + RtlInitUnicodeString( &nameW, subkey ); + rc = NtOpenKey( (PHANDLE)&hkey, KEY_ALL_ACCESS, &attr ); + + if (rc == 0) + { + char buffer[1024]; + KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; + DWORD total_size; + + RtlInitUnicodeString( &nameW, skey ); + rc = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, + buffer, sizeof(buffer), &total_size ); + if (!rc) + { + INT len = min( info->DataLength, (size-1) * sizeof(WCHAR) ); + memcpy( name, info->Data, len ); + name[len / sizeof(WCHAR)] = 0; + TRACE("returning %s\n",debugstr_w(name)); + } + NtClose(hkey); + } + if (rc) + { + MultiByteToWideChar(CP_ACP,0, key, -1,name,size); + } + + return rc; +} + +/* TIME_GetTZInfo: helper function that returns the given timezone as a string. + This could be done with a hash table instead of merely iterating through + a table, however with the small amount of entries (60 or so) I didn't think + it was worth it. + + This function should return a status code of some sort, for if the requested + timezone isn't found. +*/ + +static VOID TIME_GetWindowsTZInfo (WCHAR *StandardName, + WCHAR *DaylightName, + SYSTEMTIME *DaylightDate, + SYSTEMTIME *StandardDate) +{ + int i; + + TRACE("%s %s %i %li (%i)\n",wine__tzname[0],wine__tzname[1],wine__daylight,wine__timezone,num_types); + + TIME_InitTZInfo(); + + memset(DaylightDate,0,sizeof(SYSTEMTIME)); + memset(StandardDate,0,sizeof(SYSTEMTIME)); + + for (i=0; i<(sizeof(TZ_INFO) / sizeof(struct tagTZ_INFO)); i++) + { + if ( strcmp(TZ_INFO[i].psTZFromUnix0, wine__tzname[0]) == 0 && + (strcmp(TZ_INFO[i].psTZFromUnix1, wine__tzname[1]) == 0) && + TZ_INFO[i].bias == wine__timezone && + TZ_INFO[i].dst == wine__daylight + ) + { + time_t dst, sdt; + struct tm *p; + + /* check for dups */ + if (TZ_INFO[i].types && TZ_INFO[i].types != num_types) + continue; + /* next check for dups */ + if (TZ_INFO[i].psTZFromUnixFirst[0] && + strcmp(TZ_INFO[i].psTZFromUnixFirst,wine__tzcode)!=0) + continue; + + TIME_GetTimeNameFromReg (TZ_INFO[i].psTZWindows, "Std", + StandardName, 32); + TIME_GetTimeNameFromReg (TZ_INFO[i].psTZWindows, "Dlt", + DaylightName, 32); + + TIME_GetTZTransitionDates(&dst,&sdt); + + if (dst && sdt) + { + p = localtime(&dst); + + /* the notation for these dates is somewhat odd, see the MSDN documentation on TIME_ZONE_INFORMATION */ + DaylightDate->wYear = 0; + DaylightDate->wMonth = p->tm_mon+1; + DaylightDate->wDay = (p->tm_mday - 1) / 7 + 1; + DaylightDate->wHour = p->tm_hour; + DaylightDate->wMinute = 0; + DaylightDate->wSecond = 0; + DaylightDate->wDayOfWeek = p->tm_wday; + + p = localtime(&sdt); + + StandardDate->wYear = 0; + StandardDate->wMonth = p->tm_mon+1; + StandardDate->wDay = (p->tm_mday - 1) / 7 + 1; + StandardDate->wHour = 0; + StandardDate->wMinute = 0; + StandardDate->wSecond = 0; + StandardDate->wDayOfWeek = p->tm_wday; + + TRACE("DaylightDate=dd/mm/yy %02d/%02d/%02d\n", DaylightDate->wYear, DaylightDate->wMonth, DaylightDate->wDay); + TRACE("StandardDate=dd/mm/yy %02d/%02d/%02d\n", StandardDate->wYear, StandardDate->wMonth, StandardDate->wDay); + + } + + break; + } + } +} +#endif + static inline int IsLeapYear(int Year) { return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) ? 1 : 0; @@ -215,6 +979,7 @@ static BOOL TIME_CompTimeZoneID ( const TIME_ZONE_INFORMATION *pTZinfo, return retval; } +#ifndef linux /*********************************************************************** * TIME_TimeZoneID * @@ -235,6 +1000,7 @@ static DWORD TIME_ZoneID( const TIME_ZONE_INFORMATION *pTzi ) GetSystemTimeAsFileTime( &ftTime); return TIME_CompTimeZoneID( pTzi, &ftTime, FALSE); } +#endif /*********************************************************************** * TIME_GetTimezoneBias @@ -374,6 +1140,22 @@ BOOL WINAPI SetSystemTimeAdjustment( DWORD dwTimeAdjustment, BOOL bTimeAdjustmen return TRUE; } +/* returns 1 if we are currently within daylight savings, + 0 if we're not, + -1 on error + given the start dates of both. assumption is std is earlier than daylight + */ +static int check_daylight_savings() { + time_t now; + struct tm now_broken; + time(&now); + if (!localtime_r(&now, &now_broken)) { + ERR("localtime_r failed\n"); + return -1; + } + return now_broken.tm_isdst; +} + /*********************************************************************** * GetTimeZoneInformation (KERNEL32.@) * @@ -390,6 +1172,42 @@ BOOL WINAPI SetSystemTimeAdjustment( DWORD dwTimeAdjustment, BOOL bTimeAdjustmen */ DWORD WINAPI GetTimeZoneInformation( LPTIME_ZONE_INFORMATION tzinfo ) { +#ifdef linux + int ret; + + memset(tzinfo, 0, sizeof(TIME_ZONE_INFORMATION)); + + TIME_InitTZInfo(); + + tzinfo->Bias = wine__timezone / 60; + tzinfo->StandardBias = 0; + tzinfo->DaylightBias = -60; + + /* Get the standard time string */ + TIME_GetWindowsTZInfo(tzinfo->StandardName, tzinfo->DaylightName, + &(tzinfo->DaylightDate), &(tzinfo->StandardDate)); + + TRACE("Zone Names: %s %s \n",debugstr_w(tzinfo->StandardName), + debugstr_w(tzinfo->DaylightName)); + + /* are we currently operating in daylight savings time? */ + ret = check_daylight_savings(); + if (ret == -1) { + ERR("check_daylight_savings failed, defaulting to no DST\n"); + return TIME_ZONE_ID_UNKNOWN; + } + + if (ret) TRACE("DST is active\n"); + else TRACE("DST is not active\n"); + + if (ret) + return TIME_ZONE_ID_DAYLIGHT; + + /* FIXME: there is a 9x/NT incompatibility here. + * On NT we should return ID_UNKNOWN and on 9x ID_STANDARD. See MSDN + */ + return TIME_ZONE_ID_UNKNOWN; +#else NTSTATUS status; status = RtlQueryTimeZoneInformation( (RTL_TIME_ZONE_INFORMATION*)tzinfo ); @@ -399,6 +1217,7 @@ DWORD WINAPI GetTimeZoneInformation( LPTIME_ZONE_INFORMATION tzinfo ) return TIME_ZONE_ID_INVALID; } return TIME_ZoneID( tzinfo ); +#endif } /*********************************************************************** diff --git a/dlls/kernel32/volume.c b/dlls/kernel32/volume.c index 536fcfac372..a0075b9a3d1 100644 --- a/dlls/kernel32/volume.c +++ b/dlls/kernel32/volume.c @@ -175,7 +175,7 @@ static UINT get_registry_drive_type( const WCHAR *root ) HANDLE hkey; DWORD dummy; UINT ret = DRIVE_UNKNOWN; - char tmp[32 + sizeof(KEY_VALUE_PARTIAL_INFORMATION)]; + char tmp[64 + sizeof(KEY_VALUE_PARTIAL_INFORMATION)]; WCHAR driveW[] = {'A',':',0}; attr.Length = sizeof(attr); @@ -200,11 +200,13 @@ static UINT get_registry_drive_type( const WCHAR *root ) if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy )) { unsigned int i; + WCHAR buffer[0x20]; WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data; + ExpandEnvironmentStringsW( data, buffer, sizeof(buffer)/sizeof(WCHAR) ); for (i = 0; i < sizeof(drive_types)/sizeof(drive_types[0]); i++) { - if (!strcmpiW( data, drive_types[i] )) + if (!strcmpiW( buffer, drive_types[i] )) { ret = i; break; @@ -480,9 +482,25 @@ BOOL WINAPI GetVolumeInformationW( LPCWSTR root, LPWSTR label, DWORD label_len, { if (!root[0] || root[1] != ':') { - SetLastError( ERROR_INVALID_NAME ); - return FALSE; - } + ANSI_STRING source_unix; + UNICODE_STRING nt_name; + NTSTATUS status; + + if (!RtlDosPathNameToNtPathName_U( root, &nt_name, NULL, NULL )) + { + SetLastError( ERROR_INVALID_NAME ); + return FALSE; + } + source_unix.Buffer = NULL; + + /*check if in root is correct path, maybe UNC*/ + status=wine_nt_to_unix_file_name( &nt_name, &source_unix, FILE_OPEN, FALSE ); + RtlFreeUnicodeString( &nt_name ); + if (status != STATUS_SUCCESS) { + SetLastError( ERROR_INVALID_NAME ); + return FALSE; + } + } device[4] = root[0]; } diff --git a/dlls/kernel32/vxd.c b/dlls/kernel32/vxd.c index bd984da9ba8..d39ecdca1a7 100644 --- a/dlls/kernel32/vxd.c +++ b/dlls/kernel32/vxd.c @@ -346,6 +346,15 @@ BOOL WINAPI DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, /* Not a VxD, let ntdll handle it */ + if (( HIWORD( dwIoControlCode ) == IOCTL_STORAGE_BASE) || + (HIWORD( dwIoControlCode ) == FILE_DEVICE_CONTROLLER)) + { + if (Device_DeviceIoControl(hDevice,dwIoControlCode, lpvInBuffer, + cbInBuffer, lpvOutBuffer, cbOutBuffer, + lpcbBytesReturned, lpOverlapped)) return TRUE; + /* fall through to normal handling */ + } + if (lpOverlapped) { if (HIWORD(dwIoControlCode) == FILE_DEVICE_FILE_SYSTEM) diff --git a/dlls/msdmo/dmoreg.c b/dlls/msdmo/dmoreg.c index bba159a3923..66fbe5bd462 100644 --- a/dlls/msdmo/dmoreg.c +++ b/dlls/msdmo/dmoreg.c @@ -606,7 +606,7 @@ static HRESULT WINAPI IEnumDMO_fnClone(IEnumDMO * iface, IEnumDMO **ppEnum) FIXME("(%p)->() to (%p)->() E_NOTIMPL\n", This, ppEnum); - return E_NOTIMPL; + return S_OK; } diff --git a/dlls/mshtml/htmlbody.c b/dlls/mshtml/htmlbody.c index f8be55051e7..6c7c48a46c1 100644 --- a/dlls/mshtml/htmlbody.c +++ b/dlls/mshtml/htmlbody.c @@ -138,245 +138,264 @@ static HRESULT WINAPI HTMLBodyElement_Invoke(IHTMLBodyElement *iface, DISPID dis static HRESULT WINAPI HTMLBodyElement_put_background(IHTMLBodyElement *iface, BSTR v) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->(%s)\n", This, debugstr_w(v)); + FIXME("(%p)->(%s)\n", This, debugstr_w(v)); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_get_background(IHTMLBodyElement *iface, BSTR *p) { HTMLBodyElement *This = HTMLBODY_THIS(iface); + nsAString background_str; + nsresult nsres; + TRACE("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + + nsAString_Init(&background_str, NULL); + + nsres = nsIDOMHTMLBodyElement_GetBackground(This->nsbody, &background_str); + if(NS_SUCCEEDED(nsres)) { + const PRUnichar *background; + nsAString_GetData(&background_str, &background, NULL); + *p = SysAllocString(background); + }else { + ERR("GetBackground failed: %08x\n", nsres); + *p = NULL; + } + + nsAString_Finish(&background_str); + + TRACE("*p = %s\n", debugstr_w(*p)); + return S_OK; } static HRESULT WINAPI HTMLBodyElement_put_bgProperties(IHTMLBodyElement *iface, BSTR v) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->(%s)\n", This, debugstr_w(v)); + FIXME("(%p)->(%s)\n", This, debugstr_w(v)); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_get_bgProperties(IHTMLBodyElement *iface, BSTR *p) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->(%p)\n", This, p); + FIXME("(%p)->(%p)\n", This, p); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_put_leftMargin(IHTMLBodyElement *iface, VARIANT v) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->()\n", This); + FIXME("(%p)->()\n", This); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_get_leftMargin(IHTMLBodyElement *iface, VARIANT *p) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->(%p)\n", This, p); + FIXME("(%p)->(%p)\n", This, p); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_put_topMargin(IHTMLBodyElement *iface, VARIANT v) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->()\n", This); + FIXME("(%p)->()\n", This); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_get_topMargin(IHTMLBodyElement *iface, VARIANT *p) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->(%p)\n", This, p); + FIXME("(%p)->(%p)\n", This, p); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_put_rightMargin(IHTMLBodyElement *iface, VARIANT v) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->()\n", This); + FIXME("(%p)->()\n", This); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_get_rightMargin(IHTMLBodyElement *iface, VARIANT *p) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->(%p)\n", This, p); + FIXME("(%p)->(%p)\n", This, p); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_put_bottomMargin(IHTMLBodyElement *iface, VARIANT v) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->()\n", This); + FIXME("(%p)->()\n", This); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_get_bottomMargin(IHTMLBodyElement *iface, VARIANT *p) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->(%p)\n", This, p); + FIXME("(%p)->(%p)\n", This, p); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_put_noWrap(IHTMLBodyElement *iface, VARIANT_BOOL v) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->(%x)\n", This, v); + FIXME("(%p)->(%x)\n", This, v); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_get_noWrap(IHTMLBodyElement *iface, VARIANT_BOOL *p) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->(%p)\n", This, p); + FIXME("(%p)->(%p)\n", This, p); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_put_bgColor(IHTMLBodyElement *iface, VARIANT v) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->()\n", This); + FIXME("(%p)->()\n", This); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_get_bgColor(IHTMLBodyElement *iface, VARIANT *p) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->(%p)\n", This, p); + FIXME("(%p)->(%p)\n", This, p); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_put_text(IHTMLBodyElement *iface, VARIANT v) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->()\n", This); + FIXME("(%p)->()\n", This); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_get_text(IHTMLBodyElement *iface, VARIANT *p) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->(%p)\n", This, p); + FIXME("(%p)->(%p)\n", This, p); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_put_link(IHTMLBodyElement *iface, VARIANT v) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->()\n", This); + FIXME("(%p)->()\n", This); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_get_link(IHTMLBodyElement *iface, VARIANT *p) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->(%p)\n", This, p); + FIXME("(%p)->(%p)\n", This, p); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_put_vLink(IHTMLBodyElement *iface, VARIANT v) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->()\n", This); + FIXME("(%p)->()\n", This); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_get_vLink(IHTMLBodyElement *iface, VARIANT *p) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->(%p)\n", This, p); + FIXME("(%p)->(%p)\n", This, p); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_put_aLink(IHTMLBodyElement *iface, VARIANT v) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->()\n", This); + FIXME("(%p)->()\n", This); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_get_aLink(IHTMLBodyElement *iface, VARIANT *p) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->(%p)\n", This, p); + FIXME("(%p)->(%p)\n", This, p); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_put_onload(IHTMLBodyElement *iface, VARIANT v) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->()\n", This); + FIXME("(%p)->()\n", This); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_get_onload(IHTMLBodyElement *iface, VARIANT *p) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->(%p)\n", This, p); + FIXME("(%p)->(%p)\n", This, p); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_put_onunload(IHTMLBodyElement *iface, VARIANT v) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->()\n", This); + FIXME("(%p)->()\n", This); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_get_onunload(IHTMLBodyElement *iface, VARIANT *p) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->(%p)\n", This, p); + FIXME("(%p)->(%p)\n", This, p); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_put_scroll(IHTMLBodyElement *iface, BSTR v) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->(%s)\n", This, debugstr_w(v)); + FIXME("(%p)->(%s)\n", This, debugstr_w(v)); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_get_scroll(IHTMLBodyElement *iface, BSTR *p) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->(%p)\n", This, p); + FIXME("(%p)->(%p)\n", This, p); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_put_onselect(IHTMLBodyElement *iface, VARIANT v) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->()\n", This); + FIXME("(%p)->()\n", This); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_get_onselect(IHTMLBodyElement *iface, VARIANT *p) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->(%p)\n", This, p); + FIXME("(%p)->(%p)\n", This, p); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_put_onbeforeunload(IHTMLBodyElement *iface, VARIANT v) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->()\n", This); + FIXME("(%p)->()\n", This); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_get_onbeforeunload(IHTMLBodyElement *iface, VARIANT *p) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->(%p)\n", This, p); + FIXME("(%p)->(%p)\n", This, p); return E_NOTIMPL; } static HRESULT WINAPI HTMLBodyElement_createTextRange(IHTMLBodyElement *iface, IHTMLTxtRange **range) { HTMLBodyElement *This = HTMLBODY_THIS(iface); - TRACE("(%p)->(%p)\n", This, range); + FIXME("(%p)->(%p)\n", This, range); return E_NOTIMPL; } diff --git a/dlls/mshtml/htmltextcont.c b/dlls/mshtml/htmltextcont.c index 42f0805063e..41881abc200 100644 --- a/dlls/mshtml/htmltextcont.c +++ b/dlls/mshtml/htmltextcont.c @@ -102,14 +102,16 @@ static HRESULT WINAPI HTMLTextContainer_get_scrollHeight(IHTMLTextContainer *ifa { HTMLTextContainer *This = HTMLTEXTCONT_THIS(iface); FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + *p = 15000; + return S_OK; } static HRESULT WINAPI HTMLTextContainer_get_scrollWidth(IHTMLTextContainer *iface, long *p) { HTMLTextContainer *This = HTMLTEXTCONT_THIS(iface); FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + *p = 300; + return S_OK; } static HRESULT WINAPI HTMLTextContainer_put_scrollTop(IHTMLTextContainer *iface, long v) diff --git a/dlls/mshtml/install.c b/dlls/mshtml/install.c index 07f83e7d9ae..96a9b2563ff 100644 --- a/dlls/mshtml/install.c +++ b/dlls/mshtml/install.c @@ -358,6 +358,36 @@ static INT_PTR CALLBACK installer_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARA return FALSE; } +static BOOL run_cxhtmlsetup(void) +{ + PROCESS_INFORMATION pi; + STARTUPINFOA si; + DWORD exit_code; + BOOL res; + static char cmdline[] = "cxhtmlsetup.exe"; + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + + res = CreateProcessA(NULL, cmdline, NULL, NULL, 0, 0, NULL, NULL, &si, &pi); + if(!res) { + ERR("CreateProcessFailed: %d\n", GetLastError()); + return FALSE; + } + + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hThread); + + res = GetExitCodeProcess(pi.hProcess, &exit_code); + CloseHandle(pi.hProcess); + if(!res) { + ERR("Could not get exit code: %d\n", GetLastError()); + return FALSE; + } + + return exit_code == 0; +} + BOOL install_wine_gecko(void) { HANDLE hsem; @@ -368,7 +398,7 @@ BOOL install_wine_gecko(void) if(GetLastError() == ERROR_ALREADY_EXISTS) { WaitForSingleObject(hsem, INFINITE); }else { - if((url = get_url())) + if(!run_cxhtmlsetup() && (url = get_url())) DialogBoxW(hInst, MAKEINTRESOURCEW(ID_DWL_DIALOG), 0, installer_proc); } diff --git a/dlls/mshtml/mshtml.inf b/dlls/mshtml/mshtml.inf index e0098ce4652..8f18ea6e551 100644 --- a/dlls/mshtml/mshtml.inf +++ b/dlls/mshtml/mshtml.inf @@ -310,14 +310,12 @@ HKCR,"MIME\Database\Content Type\text/html","CLSID",,"%CLSID_HTMLDocument%" HKCR,"MIME\Database\Content Type\text/html","Extension",,".htm" HKCR,"MIME\Database\Content Type\text/html","Encoding",1,08,00,00,00 HKCR,"MIME\Database\Content Type\image/x-jg","CLSID",,"%CLSID_HTMLDocument%" -HKCR,"InternetShortcut\shell\print\command",,,"rundll32.exe mshtml.dll,PrintHTML ""%%1""" -HKCR,"InternetShortcut\shell\printto\command",,,"rundll32.exe mshtml.dll,PrintHTML ""%%1"" ""%%2"" ""%%3"" ""%%4""" HKCR,"htmlfile\shell\print\command",,,"rundll32.exe mshtml.dll,PrintHTML ""%%1""" HKCR,"htmlfile\shell\printto\command",,,"rundll32.exe mshtml.dll,PrintHTML ""%%1"" ""%%2"" ""%%3"" ""%%4""" HKCR,"htmlfile",,,"HTML Document" HKCR,"htmlfile\BrowseInPlace",,,"" HKCR,"htmlfile\CLSID",,,"%CLSID_HTMLDocument%" -;; HKCR,"htmlfile\DefaultIcon",,0x00020000,"%IEXPLORE%,1" +;; HKCR,"htmlfile\DefaultIcon",,,"%IEXPLORE%,1" HKCR,"htmlfile_FullWindowEmbed",,,"HTML Plugin Document" HKCR,"htmlfile_FullWindowEmbed\BrowseInPlace",,,"" HKCR,"htmlfile_FullWindowEmbed\CLSID",,,"%CLSID_HTMLPluginDocument%" @@ -409,6 +407,11 @@ HKCR,"MIME\Database\Content Type\text/plain","Extension",,".txt" HKCR,"MIME\Database\Content Type\text/plain","Encoding",1,07,00,00,00 HKCR,".txt","Content Type",,"text/plain" +;; URL +HKCR,".url",,,"InternetShortcut" +HKCR,"InternetShortcut\shell\print\command",,,"rundll32.exe mshtml.dll,PrintHTML ""%%1""" +HKCR,"InternetShortcut\shell\printto\command",,,"rundll32.exe mshtml.dll,PrintHTML ""%%1"" ""%%2"" ""%%3"" ""%%4""" + ;; XBM HKCR,"MIME\Database\Content Type\image/xbm","Extension",,".xbm" HKCR,"MIME\Database\Content Type\image/x-xbitmap","CLSID",,"%CLSID_HTMLDocument%" diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 7038c703e4d..6d8e1546bfc 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -165,6 +165,7 @@ typedef struct { nsLoadFlags load_flags; nsIURI *original_uri; char *content; + char *charset; } nsChannel; typedef struct { diff --git a/dlls/mshtml/navigate.c b/dlls/mshtml/navigate.c index f9525e7be1f..c2a6947e9a9 100644 --- a/dlls/mshtml/navigate.c +++ b/dlls/mshtml/navigate.c @@ -37,6 +37,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(mshtml); #define CONTENT_LENGTH "Content-Length" +#define UTF16_STR "utf-16" #define NSINSTREAM(x) ((nsIInputStream*) &(x)->lpInputStreamVtbl) @@ -399,31 +400,38 @@ static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *if TRACE("(%p)->(%08x %d %p %p)\n", This, grfBSCF, dwSize, pformatetc, pstgmed); if(This->nslistener) { - if(!This->nsstream) { + if(!This->nsstream) This->nsstream = create_nsprotocol_stream(pstgmed->u.pstm); - nsres = nsIStreamListener_OnStartRequest(This->nslistener, - (nsIRequest*)NSCHANNEL(This->nschannel), This->nscontext); - if(NS_FAILED(nsres)) - FIXME("OnStartRequest failed: %08x\n", nsres); - } - do { hres = IStream_Read(pstgmed->u.pstm, This->nsstream->buf, sizeof(This->nsstream->buf), &This->nsstream->buf_size); if(!This->nsstream->buf_size) break; + if(!This->readed && This->nsstream->buf_size >= 2 && *(WORD*)This->nsstream->buf == 0xfeff) { + This->nschannel->charset = mshtml_alloc(sizeof(UTF16_STR)); + memcpy(This->nschannel->charset, UTF16_STR, sizeof(UTF16_STR)); + } + + if(!This->readed) { + nsres = nsIStreamListener_OnStartRequest(This->nslistener, + (nsIRequest*)NSCHANNEL(This->nschannel), This->nscontext); + if(NS_FAILED(nsres)) + FIXME("OnStartRequest failed: %08x\n", nsres); + } + + This->readed += This->nsstream->buf_size; + nsres = nsIStreamListener_OnDataAvailable(This->nslistener, (nsIRequest*)NSCHANNEL(This->nschannel), This->nscontext, - NSINSTREAM(This->nsstream), This->readed, This->nsstream->buf_size); + NSINSTREAM(This->nsstream), This->readed-This->nsstream->buf_size, + This->nsstream->buf_size); if(NS_FAILED(nsres)) - FIXME("OnDataAvailable failed: %08x\n", nsres); + ERR("OnDataAvailable failed: %08x\n", nsres); if(This->nsstream->buf_size) FIXME("buffer is not empty!\n"); - - This->readed += This->nsstream->buf_size; }while(hres == S_OK); }else { BYTE buf[1024]; diff --git a/dlls/mshtml/nsio.c b/dlls/mshtml/nsio.c index 06bad648540..e3eba43b058 100644 --- a/dlls/mshtml/nsio.c +++ b/dlls/mshtml/nsio.c @@ -221,6 +221,7 @@ static nsrefcnt NSAPI nsChannel_Release(nsIHttpChannel *iface) if(This->original_uri) nsIURI_Release(This->original_uri); mshtml_free(This->content); + mshtml_free(This->charset); mshtml_free(This); } @@ -512,11 +513,20 @@ static nsresult NSAPI nsChannel_GetContentCharset(nsIHttpChannel *iface, TRACE("(%p)->(%p)\n", This, aContentCharset); - if(This->channel) - return nsIChannel_GetContentCharset(This->channel, aContentCharset); + if(This->charset) { + nsACString_SetData(aContentCharset, This->charset); + return NS_OK; + } - FIXME("default action not implemented\n"); - return NS_ERROR_NOT_IMPLEMENTED; + if(This->channel) { + nsresult nsres = nsIChannel_GetContentCharset(This->channel, aContentCharset); + const char *ch; + nsACString_GetData(aContentCharset, &ch, NULL); + return nsres; + } + + nsACString_SetData(aContentCharset, ""); + return NS_OK; } static nsresult NSAPI nsChannel_SetContentCharset(nsIHttpChannel *iface, @@ -1871,6 +1881,7 @@ static nsresult NSAPI nsIOService_NewChannelFromURI(nsIIOService *iface, nsIURI ret->notif_callback = NULL; ret->load_flags = 0; ret->content = NULL; + ret->charset = NULL; nsIURI_AddRef(aURI); ret->original_uri = aURI; diff --git a/dlls/mshtml/olecmd.c b/dlls/mshtml/olecmd.c index 75af04a611b..deac11e7757 100644 --- a/dlls/mshtml/olecmd.c +++ b/dlls/mshtml/olecmd.c @@ -911,6 +911,24 @@ static HRESULT exec_outdent(HTMLDocument *This) return S_OK; } +static HRESULT exec_htmleditmode(HTMLDocument *This) +{ + FIXME("(%p)\n", This); + return S_OK; +} + +static HRESULT exec_composesettings(HTMLDocument *This, VARIANT *in) +{ + if(!in || V_VT(in) != VT_BSTR) { + WARN("invalid arg\n"); + return E_INVALIDARG; + } + + FIXME("%s\n", debugstr_w(V_BSTR(in))); + + return S_OK; +} + static const struct { OLECMDF cmdf; HRESULT (*func)(HTMLDocument*,DWORD,VARIANT*,VARIANT*); @@ -1206,6 +1224,14 @@ static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID if(pvaIn || pvaOut) FIXME("unsupported arguments\n"); return exec_outdent(This); + case IDM_HTMLEDITMODE: + if(pvaIn || pvaOut) + FIXME("unsupported arguments\n"); + return exec_htmleditmode(This); + case IDM_COMPOSESETTINGS: + if(pvaOut) + FIXME("unsupported arguments\n"); + return exec_composesettings(This, pvaIn); default: FIXME("unsupported nCmdID %d of CGID_MSHTML group\n", nCmdID); return OLECMDERR_E_NOTSUPPORTED; diff --git a/dlls/mshtml/persist.c b/dlls/mshtml/persist.c index 2d614327aeb..6b9ef8dfc8a 100644 --- a/dlls/mshtml/persist.c +++ b/dlls/mshtml/persist.c @@ -39,6 +39,48 @@ WINE_DEFAULT_DEBUG_CHANNEL(mshtml); +static HRESULT get_doc_string(HTMLDocument *This, char **str, DWORD *len) +{ + nsIDOMDocument *nsdoc; + nsIDOMNode *nsnode; + LPCWSTR strw; + nsAString nsstr; + nsresult nsres; + + if(!This->nscontainer) { + WARN("no nscontainer, returning NULL\n"); + return S_OK; + } + + nsres = nsIWebNavigation_GetDocument(This->nscontainer->navigation, &nsdoc); + if(NS_FAILED(nsres)) { + ERR("GetDocument failed: %08x\n", nsres); + return E_FAIL; + } + + nsres = nsIDOMDocument_QueryInterface(nsdoc, &IID_nsIDOMNode, (void**)&nsnode); + nsIDOMDocument_Release(nsdoc); + if(NS_FAILED(nsres)) { + ERR("Could not get nsIDOMNode failed: %08x\n", nsres); + return E_FAIL; + } + + nsAString_Init(&nsstr, NULL); + nsnode_to_nsstring(nsnode, &nsstr); + nsIDOMNode_Release(nsnode); + + nsAString_GetData(&nsstr, &strw, NULL); + TRACE("%s\n", debugstr_w(strw)); + + *len = WideCharToMultiByte(CP_ACP, 0, strw, -1, NULL, 0, NULL, NULL); + *str = mshtml_alloc(*len); + WideCharToMultiByte(CP_ACP, 0, strw, -1, *str, *len, NULL, NULL); + + nsAString_Finish(&nsstr); + + return S_OK; +} + /********************************************************** * IPersistMoniker implementation */ @@ -420,8 +462,27 @@ static HRESULT WINAPI PersistFile_Load(IPersistFile *iface, LPCOLESTR pszFileNam static HRESULT WINAPI PersistFile_Save(IPersistFile *iface, LPCOLESTR pszFileName, BOOL fRemember) { HTMLDocument *This = PERSISTFILE_THIS(iface); - FIXME("(%p)->(%s %x)\n", This, debugstr_w(pszFileName), fRemember); - return E_NOTIMPL; + char *str; + DWORD len, written=0; + HANDLE file; + HRESULT hres; + + TRACE("(%p)->(%s %x)\n", This, debugstr_w(pszFileName), fRemember); + + file = CreateFileW(pszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); + if(file == INVALID_HANDLE_VALUE) { + WARN("Could not create file: %u\n", GetLastError()); + return E_FAIL; + } + + hres = get_doc_string(This, &str, &len); + if(FAILED(hres)) + return hres; + + WriteFile(file, str, len, &written, NULL); + CloseHandle(file); + return S_OK; } static HRESULT WINAPI PersistFile_SaveCompleted(IPersistFile *iface, LPCOLESTR pszFileName) @@ -495,53 +556,22 @@ static HRESULT WINAPI PersistStreamInit_Save(IPersistStreamInit *iface, LPSTREAM BOOL fClearDirty) { HTMLDocument *This = PERSTRINIT_THIS(iface); - nsIDOMDocument *nsdoc; - nsIDOMNode *nsnode; - nsAString nsstr; - LPCWSTR strw; char *str; DWORD len, written=0; - nsresult nsres; HRESULT hres; WARN("(%p)->(%p %x) needs more work\n", This, pStm, fClearDirty); - if(!This->nscontainer) - return S_OK; - - nsres = nsIWebNavigation_GetDocument(This->nscontainer->navigation, &nsdoc); - if(NS_FAILED(nsres)) { - ERR("GetDocument failed: %08x\n", nsres); - return E_FAIL; - } - - nsres = nsIDOMDocument_QueryInterface(nsdoc, &IID_nsIDOMNode, (void**)&nsnode); - nsIDOMDocument_Release(nsdoc); - if(NS_FAILED(nsres)) { - ERR("Could not get nsIDOMNode failed: %08x\n", nsres); - return E_FAIL; - } - - nsAString_Init(&nsstr, NULL); - nsnode_to_nsstring(nsnode, &nsstr); - nsIDOMNode_Release(nsnode); - - nsAString_GetData(&nsstr, &strw, NULL); - - len = WideCharToMultiByte(CP_ACP, 0, strw, -1, NULL, 0, NULL, NULL); - str = mshtml_alloc(len); - WideCharToMultiByte(CP_ACP, 0, strw, -1, str, len, NULL, NULL); - - nsAString_Finish(&nsstr); + hres = get_doc_string(This, &str, &len); + if(FAILED(hres)) + return hres; - TRACE("%s\n", debugstr_a(str)); hres = IStream_Write(pStm, str, len, &written); if(FAILED(hres)) FIXME("Write failed: %08x\n", hres); mshtml_free(str); - return S_OK; } diff --git a/dlls/msi/action.c b/dlls/msi/action.c index 51d827e6ae2..5b0110cbfe5 100644 --- a/dlls/msi/action.c +++ b/dlls/msi/action.c @@ -639,6 +639,21 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath, msi_parse_command_line( package, szCommandLine ); + { + static const WCHAR szcdcache[] = { 'C','D','C','A','C','H','E',0 }; + static const WCHAR szzero[] = { '0',0 }; + static const WCHAR szprodname[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 }; + static const WCHAR szword2003[] = { + 'M','i','c','r','o','s','o','f','t',' ','O','f','f','i','c','e',' ', + 'W','o','r','d',' ','V','i','e','w','e','r',' ','2','0','0','3',0}; + LPWSTR prod; + + prod = msi_dup_property( package, szprodname ); + if (!lstrcmpW( prod, szword2003 )) + MSI_SetPropertyW( package, szcdcache, szzero ); + msi_free( prod ); + } + msi_apply_transforms( package ); msi_apply_patches( package ); @@ -3802,6 +3817,7 @@ static UINT ACTION_InstallExecute(MSIPACKAGE *package) return execute_script(package,INSTALL_SCRIPT); } +int global_deferred=0; static UINT ACTION_InstallFinalize(MSIPACKAGE *package) { UINT rc; @@ -3815,7 +3831,11 @@ static UINT ACTION_InstallFinalize(MSIPACKAGE *package) return rc; /* then handle Commit Actions */ + TRACE("setting global_deferred=1\n"); + global_deferred=1; rc = execute_script(package,COMMIT_SCRIPT); + global_deferred=0; + TRACE("setting global_deferred=0\n"); return rc; } diff --git a/dlls/msi/custom.c b/dlls/msi/custom.c index 48a07691c62..969ab90a6ad 100644 --- a/dlls/msi/custom.c +++ b/dlls/msi/custom.c @@ -180,6 +180,7 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute) if (type & msidbCustomActionTypeInScript) { + TRACE("msidbCustomActionTypeInScript\n"); if (type & msidbCustomActionTypeNoImpersonate) FIXME("msidbCustomActionTypeNoImpersonate not handled\n"); @@ -499,6 +500,8 @@ static DWORD WINAPI ACTION_CallDllFunction( const GUID *guid ) TRACE("%s %s\n", debugstr_w( info->dllname ), debugstr_w( info->function ) ); + TlsSetValue( tls_slot, (void*) 1 ); + hModule = LoadLibraryW( info->dllname ); if (!hModule) { @@ -579,6 +582,7 @@ static msi_custom_action_info *do_msidbCustomActionTypeDll( return info; } +extern int global_deferred; static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source, LPCWSTR target, const INT type, LPCWSTR action) { @@ -586,6 +590,12 @@ static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source, WCHAR tmp_file[MAX_PATH]; UINT r; + if (type & msidbCustomActionTypeInScript) + { + TRACE("setting global_deferred=1\n"); + global_deferred=1; + } + r = store_binary_to_temp(package, source, tmp_file); if (r != ERROR_SUCCESS) return r; @@ -601,7 +611,13 @@ static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source, info = do_msidbCustomActionTypeDll( package, type, tmp_file, target, action ); - return wait_thread_handle( info ); + r = wait_thread_handle( info ); + if (type & msidbCustomActionTypeInScript) + { + TRACE("setting global_deferred=0\n"); + global_deferred=0; + } + return r; } static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source, @@ -887,7 +903,8 @@ void ACTION_FinishCustomActions(MSIPACKAGE* package) { if (info->package == package ) { - wait_handles[handle_count++] = info->handle; + if (DuplicateHandle(GetCurrentProcess(), info->handle, GetCurrentProcess(), &wait_handles[handle_count], SYNCHRONIZE, FALSE, 0)) + handle_count++; free_custom_action_data( info ); } } @@ -895,7 +912,10 @@ void ACTION_FinishCustomActions(MSIPACKAGE* package) LeaveCriticalSection( &msi_custom_action_cs ); for (i = 0; i < handle_count; i++) + { msi_dialog_check_messages( wait_handles[i] ); + CloseHandle( wait_handles[i] ); + } HeapFree( GetProcessHeap(), 0, wait_handles ); } diff --git a/dlls/msi/font.c b/dlls/msi/font.c index 2b08a0f7a43..b0c43f3672e 100644 --- a/dlls/msi/font.c +++ b/dlls/msi/font.c @@ -216,8 +216,8 @@ static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param) if (name) { - msi_reg_set_val_str( hkey1, name, file->FileName ); - msi_reg_set_val_str( hkey2, name, file->FileName ); + msi_reg_set_val_str( hkey1, name, file->TargetPath); + msi_reg_set_val_str( hkey2, name, file->TargetPath); } msi_free(name); diff --git a/dlls/msi/helpers.c b/dlls/msi/helpers.c index 7357bd73c53..74665e57d59 100644 --- a/dlls/msi/helpers.c +++ b/dlls/msi/helpers.c @@ -310,9 +310,26 @@ LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, p = resolve_folder(package, parent, source, set_prop, load_prop, NULL); if (!source) { + WCHAR szShellObjectFolder[] = +{'S','H','E','L','L','_','O','B','J','E','C','T','_','F','O','L','D','E','R',0}; + TRACE(" TargetDefault = %s\n", debugstr_w(f->TargetDefault)); - path = build_directory_name( 3, p, f->TargetDefault, NULL ); + /* hack for GUPTA */ + if (f->TargetDefault && strcmpW( f->TargetDefault, szShellObjectFolder)==0) + { + LPWSTR sof = msi_dup_property(package,szShellObjectFolder); + if (sof) + { + path = build_directory_name(3, p, sof, NULL); + msi_free(sof); + } + else + path = build_directory_name(3, p, f->TargetDefault, NULL); + } + else + path = build_directory_name(3, p, f->TargetDefault, NULL); + clean_spaces_from_path( path ); f->ResolvedTarget = strdupW( path ); TRACE("target -> %s\n", debugstr_w(path)); diff --git a/dlls/msi/install.c b/dlls/msi/install.c index b6cff6df2c6..9b43bc3c35e 100644 --- a/dlls/msi/install.c +++ b/dlls/msi/install.c @@ -450,6 +450,7 @@ UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder, * Not in the state: FALSE * */ +extern int global_deferred; BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode) { BOOL r = FALSE; @@ -467,8 +468,10 @@ BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode) break; case MSIRUNMODE_SCHEDULED: - case MSIRUNMODE_ROLLBACK: case MSIRUNMODE_COMMIT: + if (global_deferred) r = TRUE; + break; + case MSIRUNMODE_ROLLBACK: break; default: @@ -476,6 +479,7 @@ BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode) r = TRUE; } + TRACE("%d -> %d\n", iRunMode, r); return r; } diff --git a/dlls/msi/msi.c b/dlls/msi/msi.c index 2cb4848dbb7..aeb9c6c97c7 100644 --- a/dlls/msi/msi.c +++ b/dlls/msi/msi.c @@ -1111,6 +1111,21 @@ INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature) if (!szProduct || !szFeature) return INSTALLSTATE_INVALIDARG; + /* HACK: Pretend that the VBAFiles feature isn't present. + VBAFiles seems to depend on Internet Explorer, and displays + an error at Project startup "This feature depends on Internet Explorer..." */ + if (1) { + static const WCHAR p[] = { + '{','9','0','3','B','0','4','0','9','-', + '6','0','0','0','-','1','1','D','3','-', + '8','C','F','E','-','0','1','5','0','0', + '4','8','3','8','3','C','9','}',0}; + static const WCHAR f[] = { + 'V','B','A','F','i','l','e','s',0}; + if ( !lstrcmpW(p, szProduct) && !lstrcmpW(f, szFeature)) + return INSTALLSTATE_UNKNOWN; + } + if (!squash_guid( szProduct, squishProduct )) return INSTALLSTATE_INVALIDARG; @@ -1562,15 +1577,29 @@ static USERINFOSTATE WINAPI MSI_GetUserInfo(LPCWSTR szProduct, state = USERINFOSTATE_PRESENT; - r = msi_strcpy_to_awstring( user, lpUserNameBuf, pcchUserNameBuf ); - if (r == ERROR_MORE_DATA) - state = USERINFOSTATE_MOREDATA; - r = msi_strcpy_to_awstring( org, lpOrgNameBuf, pcchOrgNameBuf ); - if (r == ERROR_MORE_DATA) - state = USERINFOSTATE_MOREDATA; - r = msi_strcpy_to_awstring( serial, lpSerialBuf, pcchSerialBuf ); - if (r == ERROR_MORE_DATA) - state = USERINFOSTATE_MOREDATA; + if (user) + { + r = msi_strcpy_to_awstring( user, lpUserNameBuf, pcchUserNameBuf ); + if (r == ERROR_MORE_DATA) + state = USERINFOSTATE_MOREDATA; + } + else + state = USERINFOSTATE_ABSENT; + if (org) + { + r = msi_strcpy_to_awstring( org, lpOrgNameBuf, pcchOrgNameBuf ); + if (r == ERROR_MORE_DATA && state == USERINFOSTATE_PRESENT) + state = USERINFOSTATE_MOREDATA; + } + /* msdn states: The user information is considered to be present even in the absence of a company name. */ + if (serial) + { + r = msi_strcpy_to_awstring( serial, lpSerialBuf, pcchSerialBuf ); + if (r == ERROR_MORE_DATA && state == USERINFOSTATE_PRESENT) + state = USERINFOSTATE_MOREDATA; + } + else + state = USERINFOSTATE_ABSENT; msi_free( user ); msi_free( org ); diff --git a/dlls/msi/msi_main.c b/dlls/msi/msi_main.c index a3dac7f3f4b..97f17948f85 100644 --- a/dlls/msi/msi_main.c +++ b/dlls/msi/msi_main.c @@ -47,6 +47,7 @@ WCHAR gszLogFile[MAX_PATH]; WCHAR msi_path[MAX_PATH]; ITypeLib *msi_typelib = NULL; HINSTANCE msi_hInstance; +DWORD tls_slot; /* * Dll lifetime tracking declaration @@ -70,6 +71,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { case DLL_PROCESS_ATTACH: msi_hInstance = hinstDLL; + tls_slot = TlsAlloc(); DisableThreadLibraryCalls(hinstDLL); msi_dialog_register_class(); break; diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index 55dd2fa9e6b..b8af1d5bc7a 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -799,6 +799,8 @@ extern const WCHAR szProductCode[]; extern const WCHAR cszRootDrive[]; extern const WCHAR cszbs[]; +extern DWORD tls_slot; + /* memory allocation macro functions */ static inline void *msi_alloc( size_t len ) { diff --git a/dlls/msi/package.c b/dlls/msi/package.c index 73298afa15a..188d0b0828d 100644 --- a/dlls/msi/package.c +++ b/dlls/msi/package.c @@ -1240,6 +1240,17 @@ UINT WINAPI MsiGetPropertyA( MSIHANDLE hInstall, LPCSTR szName, return ERROR_OUTOFMEMORY; r = MSI_GetProperty( hInstall, name, &val, pchValueBuf ); + + /* + * bug emulation! + * When executed in a custom action, this function reports strings are twice as long !?! + */ + if ((r == ERROR_SUCCESS || r == ERROR_MORE_DATA) && pchValueBuf && TlsGetValue( tls_slot )) + { + *pchValueBuf *= sizeof(WCHAR); + TRACE("bug emulation, pchValueBuf = %d\n", *pchValueBuf); + } + msi_free( name ); return r; } diff --git a/dlls/msnet32/msnet32.spec b/dlls/msnet32/msnet32.spec index fcf4a0c994b..359a1cd5ba3 100644 --- a/dlls/msnet32/msnet32.spec +++ b/dlls/msnet32/msnet32.spec @@ -54,7 +54,7 @@ 54 stub @ 55 stub @ 56 stub @ - 57 stdcall @(long long ptr long ptr) MSNET32_57 +# 57 stdcall @(long long ptr long ptr) MSNET32_57 58 stub @ 59 stub @ 60 stub @ diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c index f06166bdaab..6f8da46b66c 100644 --- a/dlls/msvcrt/math.c +++ b/dlls/msvcrt/math.c @@ -878,10 +878,20 @@ char * CDECL _fcvt( double number, int ndigits, int *decpt, int *sign ) if (!data->efcvt_buffer) data->efcvt_buffer = MSVCRT_malloc( 80 ); /* ought to be enough */ - snprintf(data->efcvt_buffer, 80, "%.*e", ndigits, number); + snprintf(data->efcvt_buffer, 80, "%.*f", ndigits, number); *sign = (number < 0); dec = strchr(data->efcvt_buffer, '.'); - *decpt = (dec) ? dec - data->efcvt_buffer : -1; + if (dec) + { + *decpt = dec - data->efcvt_buffer; + while (*dec) + { + *dec =*(dec+1); + dec++; + } + } + else + *decpt = strlen(data->efcvt_buffer); return data->efcvt_buffer; } diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c index 50aaa2741c0..5e3eca6cdeb 100644 --- a/dlls/ntdll/directory.c +++ b/dlls/ntdll/directory.c @@ -602,6 +602,198 @@ static char *get_device_mount_point( dev_t dev ) /*********************************************************************** + * get_autofs_mount_points + * + * Return a list of autofs mount points. + */ +static struct drive_info *get_autofs_mount_points( unsigned int *ret_count ) +{ + struct drive_info *ret = NULL; + +#ifdef linux + unsigned int count, total; + struct mntent *entry; + struct stat st; + FILE *f; + + if (!(f = fopen( "/etc/mtab", "r" ))) return NULL; + count = total = 0; + while ((entry = getmntent( f ))) + { + if (strcmp( entry->mnt_type, "autofs" )) continue; + if (stat( entry->mnt_dir, &st ) == -1) continue; + if (count >= total) + { + total += 16; + if (!ret) ret = RtlAllocateHeap( GetProcessHeap(), 0, total * sizeof(*ret) ); + else + { + void *new = RtlReAllocateHeap( GetProcessHeap(), 0, ret, total * sizeof(*ret) ); + if (!new) RtlFreeHeap( GetProcessHeap(), 0, ret ); + ret = new; + } + if (!ret) break; + } + ret[count].dev = st.st_dev; + ret[count].ino = st.st_ino; + count++; + } + *ret_count = count; + endmntent( f ); +#endif + return ret; +} + + +/*********************************************************************** + * read_drive_symlink + * + * Read the symlink for a given drive and return the resulting full path. + */ +static char *read_drive_symlink( char *dos_device, unsigned int *prefix ) +{ + char *buffer, *p; + int ret, size = 128; + + if (!(p = strrchr( dos_device, '/' ))) p = dos_device; + else p++; + + for (;;) + { + if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, size + (p - dos_device) ))) + { + errno = ENOMEM; + return NULL; + } + ret = readlink( dos_device, buffer, size ); + if (ret == -1) + { + RtlFreeHeap( GetProcessHeap(), 0, buffer ); + return NULL; + } + if (ret != size) + { + buffer[ret] = 0; + break; + } + RtlFreeHeap( GetProcessHeap(), 0, buffer ); + size *= 2; + } + if (buffer[0] != '/') + { + memmove( buffer + (p - dos_device), buffer, strlen(buffer) + 1 ); + memcpy( buffer, dos_device, p - dos_device ); + *prefix = p - dos_device; + } + else *prefix = 0; + return buffer; +} + + +/*********************************************************************** + * is_drive_automounted + * + * Check if any element of the specified dosdevice is inside an autofs + * mount point and isn't currently mounted. + */ +static int is_drive_automounted( char *dos_device, struct drive_info *mount_points, unsigned int count ) +{ + struct stat st; + unsigned int i, start; + char *symlink, *next, *p; + + if (!(symlink = read_drive_symlink( dos_device, &start ))) return -1; + + p = symlink + start; + while (*p == '/') p++; /* skip leading slashes */ + for (;;) + { + while (*p && *p != '/') p++; + next = p; + while (*next == '/') next++; + if (!*next) break; /* don't stat the last element */ + *p = 0; + if (stat( symlink, &st ) != -1) + { + for (i = 0; i < count; i++) + if (mount_points[i].dev == st.st_dev && mount_points[i].ino == st.st_ino) break; + if (i < count) + { + /* now check if the next path element exists, without triggering a mount */ + struct dirent *de; + DIR *dir = opendir( symlink ); + if (!dir) break; + while ((de = readdir( dir ))) + { + unsigned int len = strlen(de->d_name); + if (!strncmp( de->d_name, next, len ) && (!next[len] || next[len] == '/')) + break; + } + closedir( dir ); + if (!de) /* not found in the dir -> automounted */ + { + TRACE( "%s is automounted under %s\n", dos_device, symlink ); + RtlFreeHeap( GetProcessHeap(), 0, symlink ); + return 1; + } + TRACE( "%s found in %s -> already mounted\n", next, symlink ); + } + } + *p = '/'; + p = next; + } + RtlFreeHeap( GetProcessHeap(), 0, symlink ); + return 0; +} + + +/*********************************************************************** + * get_drives_info + * + * Retrieve device/inode number for all the drives. + */ +int DIR_get_drives_info( struct drive_info info[MAX_DOS_DRIVES] ) +{ + const char *config_dir = wine_get_config_dir(); + char *buffer, *p; + struct stat st; + int i, ret; + unsigned int count = 0; + struct drive_info *mount_points; + + buffer = RtlAllocateHeap( GetProcessHeap(), 0, strlen(config_dir) + sizeof("/dosdevices/a:") ); + if (!buffer) return 0; + strcpy( buffer, config_dir ); + strcat( buffer, "/dosdevices/a:" ); + p = buffer + strlen(buffer) - 2; + + mount_points = get_autofs_mount_points( &count ); + + for (i = ret = 0; i < MAX_DOS_DRIVES; i++) + { + info[i].dev = 0; + info[i].ino = 0; + *p = 'a' + i; + /* skip the stat for automounted drives to avoid triggering a mount */ + if (mount_points) + { + int res = is_drive_automounted( buffer, mount_points, count ); + if (res > 0 || (res == -1 && errno == ENOENT)) continue; + } + if (!stat( buffer, &st )) + { + info[i].dev = st.st_dev; + info[i].ino = st.st_ino; + ret++; + } + } + RtlFreeHeap( GetProcessHeap(), 0, mount_points ); + RtlFreeHeap( GetProcessHeap(), 0, buffer ); + return ret; +} + + +/*********************************************************************** * init_options * * Initialize the show_dot_files options. @@ -678,30 +870,50 @@ static ULONG hash_short_file_name( const UNICODE_STRING *name, LPWSTR buffer ) { static const char hash_chars[32] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"; - LPCWSTR p, ext, end = name->Buffer + name->Length / sizeof(WCHAR); + LPCWSTR p, ext, hash_end, end = name->Buffer + name->Length / sizeof(WCHAR); LPWSTR dst; unsigned short hash; int i; + /* Find last dot for start of the extension */ + for (p = name->Buffer + 1, ext = NULL; p < end - 1; p++) if (*p == '.') ext = p; + + /* don't include the standard 3 char .ext in the filename hash */ + hash_end = end; + if (ext && ((end - ext) == 4 )) + { + /* + * FIXME: CodeWeavers hack alert + * The next five lines are a nasty hack to only activate this + * (more correct behaviour) for Quicken files for the moment. + * We don't want to break our install base of programs that have + * shortfile names stored in the registry or elsewhere. + */ + WCHAR szqdf[]={'.','q','d','f'}; + WCHAR szqsd[]={'.','q','s','d'}; + WCHAR szqel[]={'.','q','e','l'}; + WCHAR szqph[]={'.','q','p','h'}; + if (!strncmpiW(ext,szqdf,4) || !strncmpiW(ext,szqsd,4) || + !strncmpiW(ext,szqph,4) || !strncmpiW(ext,szqel,4)) + hash_end = ext; + } + /* Compute the hash code of the file name */ /* If you know something about hash functions, feel free to */ /* insert a better algorithm here... */ if (!is_case_sensitive) { - for (p = name->Buffer, hash = 0xbeef; p < end - 1; p++) + for (p = name->Buffer, hash = 0xbeef; p < hash_end - 1; p++) hash = (hash<<3) ^ (hash>>5) ^ tolowerW(*p) ^ (tolowerW(p[1]) << 8); hash = (hash<<3) ^ (hash>>5) ^ tolowerW(*p); /* Last character */ } else { - for (p = name->Buffer, hash = 0xbeef; p < end - 1; p++) + for (p = name->Buffer, hash = 0xbeef; p < hash_end - 1; p++) hash = (hash << 3) ^ (hash >> 5) ^ *p ^ (p[1] << 8); hash = (hash << 3) ^ (hash >> 5) ^ *p; /* Last character */ } - /* Find last dot for start of the extension */ - for (p = name->Buffer + 1, ext = NULL; p < end - 1; p++) if (*p == '.') ext = p; - /* Copy first 4 chars, replacing invalid chars with '_' */ for (i = 4, p = name->Buffer, dst = buffer; i > 0; i--, p++) { diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index 89de3b332a7..dbd53b0322d 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -203,6 +203,26 @@ NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIB *handle = reply->handle; } SERVER_END_REQ; + + /* BEGIN CODEWEAVERS HACK */ + if (created) + { + static const char wininit[] = "WinInit.Ini", sc[] = { ';',';' }; + + if (unix_name.Length >= sizeof(wininit)-1 && + !strcmp( unix_name.Buffer + unix_name.Length - (sizeof(wininit)-1), wininit )) + { + int fd; + if (wine_server_handle_to_fd( *handle, FILE_WRITE_DATA, &fd, NULL ) == STATUS_SUCCESS) + { + struct stat st; + if (fstat( fd, &st ) != -1 && st.st_size == 0) pwrite( fd, sc, sizeof(sc), 0 ); + wine_server_release_fd( *handle, fd ); + } + } + } + /* END CODEWEAVERS HACK */ + RtlFreeAnsiString( &unix_name ); } else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), io->u.Status ); diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c index 4158f4ee4d7..bdae16636b6 100644 --- a/dlls/ntdll/nt.c +++ b/dlls/ntdll/nt.c @@ -177,6 +177,16 @@ NTSTATUS WINAPI NtAdjustPrivilegesToken( return ret; } +static BOOLEAN is_msmapi32_present(void) +{ + HMODULE dummy; + static const WCHAR wszMsmapi32[] = {'m','s','m','a','p','i','3','2','.','d','l','l',0}; + UNICODE_STRING string; + RtlInitUnicodeString(&string, wszMsmapi32); + return (STATUS_SUCCESS == + LdrGetDllHandle(0, 0, &string, &dummy)); +} + /****************************************************************************** * NtQueryInformationToken [NTDLL.@] * ZwQueryInformationToken [NTDLL.@] @@ -288,10 +298,26 @@ NTSTATUS WINAPI NtQueryInformationToken( struct token_groups *tg = buffer; unsigned int *attr = (unsigned int *)(tg + 1); ULONG i; - const int non_sid_portion = (sizeof(struct token_groups) + tg->count * sizeof(unsigned long)); - SID *sids = (SID *)((char *)tokeninfo + FIELD_OFFSET( TOKEN_GROUPS, Groups[tg->count] )); - ULONG needed_bytes = FIELD_OFFSET( TOKEN_GROUPS, Groups[tg->count] ) + - reply->user_len - non_sid_portion; + int non_sid_portion; + SID *sids; + ULONG needed_bytes; + static const SID service_sid = { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_SERVICE_RID } }; + BOOLEAN is_msmapi32 = is_msmapi32_present(); + + if (is_msmapi32) + { + non_sid_portion = (sizeof(struct token_groups) + (tg->count + 1) * sizeof(unsigned long)); + sids = (SID *)((char *)tokeninfo + FIELD_OFFSET( TOKEN_GROUPS, Groups[tg->count + 1] )); + needed_bytes = FIELD_OFFSET( TOKEN_GROUPS, Groups[tg->count + 1] ) + + reply->user_len - non_sid_portion + sizeof(service_sid); + } + else + { + non_sid_portion = (sizeof(struct token_groups) + tg->count * sizeof(unsigned long)); + sids = (SID *)((char *)tokeninfo + FIELD_OFFSET( TOKEN_GROUPS, Groups[tg->count] )); + needed_bytes = FIELD_OFFSET( TOKEN_GROUPS, Groups[tg->count] ) + + reply->user_len - non_sid_portion; + } if (retlen) *retlen = needed_bytes; @@ -307,6 +333,13 @@ NTSTATUS WINAPI NtQueryInformationToken( groups->Groups[i].Sid = sids; sids = (SID *)((char *)sids + RtlLengthSid(sids)); } + if (is_msmapi32) + { + groups->Groups[i].Attributes = 0; + groups->Groups[i].Sid = sids; + groups->GroupCount++; + memcpy(sids, &service_sid, sizeof(service_sid)); + } } else status = STATUS_BUFFER_TOO_SMALL; } diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index 443b2812ae6..226aa993003 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -21,6 +21,7 @@ #include #include +#include #include "windef.h" #include "winnt.h" @@ -30,6 +31,14 @@ #define MAX_NT_PATH_LENGTH 277 +#define MAX_DOS_DRIVES 26 + +struct drive_info +{ + dev_t dev; + ino_t ino; +}; + /* exceptions */ extern void wait_suspend( CONTEXT *context ); extern void WINAPI __regs_RtlRaiseException( PEXCEPTION_RECORD, PCONTEXT ); @@ -114,6 +123,7 @@ extern NTSTATUS FILE_GetNtStatus(void); extern BOOL DIR_is_hidden_file( const UNICODE_STRING *name ); extern NTSTATUS DIR_unmount_device( HANDLE handle ); extern NTSTATUS DIR_get_unix_cwd( char **cwd ); +extern int DIR_get_drives_info( struct drive_info info[MAX_DOS_DRIVES] ); /* virtual memory */ extern NTSTATUS VIRTUAL_HandleFault(LPCVOID addr); @@ -155,8 +165,8 @@ struct ntdll_thread_data int reply_fd; /* fd for receiving server replies */ int wait_fd[2]; /* fd for sleeping server requests */ void *vm86_ptr; /* data for vm86 mode */ - - void *pad[4]; /* change this if you add fields! */ + DWORD delta_priority; + void *pad[3]; /* change this if you add fields! */ }; static inline struct ntdll_thread_data *ntdll_get_thread_data(void) diff --git a/dlls/ntdll/path.c b/dlls/ntdll/path.c index a42682dbf4b..6f161a3ed3d 100644 --- a/dlls/ntdll/path.c +++ b/dlls/ntdll/path.c @@ -50,52 +50,6 @@ static const WCHAR UncPfxW[] = {'U','N','C','\\',0}; #define IS_SEPARATOR(ch) ((ch) == '\\' || (ch) == '/') -#define MAX_DOS_DRIVES 26 - -struct drive_info -{ - dev_t dev; - ino_t ino; -}; - -/*********************************************************************** - * get_drives_info - * - * Retrieve device/inode number for all the drives. Helper for find_drive_root. - */ -static inline int get_drives_info( struct drive_info info[MAX_DOS_DRIVES] ) -{ - const char *config_dir = wine_get_config_dir(); - char *buffer, *p; - struct stat st; - int i, ret; - - buffer = RtlAllocateHeap( GetProcessHeap(), 0, strlen(config_dir) + sizeof("/dosdevices/a:") ); - if (!buffer) return 0; - strcpy( buffer, config_dir ); - strcat( buffer, "/dosdevices/a:" ); - p = buffer + strlen(buffer) - 2; - - for (i = ret = 0; i < MAX_DOS_DRIVES; i++) - { - *p = 'a' + i; - if (!stat( buffer, &st )) - { - info[i].dev = st.st_dev; - info[i].ino = st.st_ino; - ret++; - } - else - { - info[i].dev = 0; - info[i].ino = 0; - } - } - RtlFreeHeap( GetProcessHeap(), 0, buffer ); - return ret; -} - - /*********************************************************************** * remove_last_componentA * @@ -149,7 +103,7 @@ static NTSTATUS find_drive_rootA( LPCSTR *ppath, unsigned int len, int *drive_re struct drive_info info[MAX_DOS_DRIVES]; /* get device and inode of all drives */ - if (!get_drives_info( info )) return STATUS_OBJECT_PATH_NOT_FOUND; + if (!DIR_get_drives_info( info )) return STATUS_OBJECT_PATH_NOT_FOUND; /* strip off trailing slashes */ while (len > 1 && path[len - 1] == '/') len--; @@ -240,7 +194,7 @@ static int find_drive_rootW( LPCWSTR *ppath ) struct drive_info info[MAX_DOS_DRIVES]; /* get device and inode of all drives */ - if (!get_drives_info( info )) return -1; + if (!DIR_get_drives_info( info )) return -1; /* strip off trailing slashes */ lenW = strlenW(path); diff --git a/dlls/ntdll/relay.c b/dlls/ntdll/relay.c index 75dbe7c3af1..8e17d19f9f8 100644 --- a/dlls/ntdll/relay.c +++ b/dlls/ntdll/relay.c @@ -40,7 +40,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(relay); #ifdef __i386__ WINE_DECLARE_DEBUG_CHANNEL(snoop); +#if 0 WINE_DECLARE_DEBUG_CHANNEL(seh); +#endif struct relay_descr /* descriptor for a module */ { @@ -764,6 +766,7 @@ FARPROC SNOOP_GetProcAddress( HMODULE hmod, const IMAGE_EXPORT_DIRECTORY *export static void SNOOP_PrintArg(DWORD x) { +#if 0 int i,nostring; DPRINTF("%08x",x); @@ -797,6 +800,9 @@ static void SNOOP_PrintArg(DWORD x) { } __ENDTRY +#else + DPRINTF("%08x",x); +#endif } #define CALLER1REF (*(DWORD*)context->Esp) diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c index 32142378a63..47a3751d112 100644 --- a/dlls/ntdll/server.c +++ b/dlls/ntdll/server.c @@ -1009,6 +1009,23 @@ void server_init_process(void) fd_socket = server_connect( server_dir ); } +#ifdef __APPLE__ + /* suppress CrashReporter from catching our exceptions */ + if (getenv("WINE_ENABLE_MAC_CRASHREPORTER") == NULL) + { + kern_return_t kret = task_set_exception_ports( + mach_task_self(), + EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC, + MACH_PORT_NULL, + EXCEPTION_STATE_IDENTITY, + MACHINE_THREAD_STATE); + + /* not fatal */ + if (kret != KERN_SUCCESS) + fprintf(stderr, "wine: Could not disable CrashReporter. Mach error code %d\n", (int)kret); + } +#endif + /* setup the signal mask */ sigemptyset( &server_block_set ); sigaddset( &server_block_set, SIGALRM ); diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index 106ebed574e..58fd167b8ad 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -1125,7 +1125,13 @@ static void usr2_handler( int signal, siginfo_t *siginfo, void *sigcontext ) static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { SIGCONTEXT *context = sigcontext; - EXCEPTION_RECORD *rec = setup_exception( context, raise_segv_exception ); + EXCEPTION_RECORD *rec; + +#ifdef __APPLE__ + if (get_trap_code(context) == 0) return; +#endif + + rec = setup_exception( context, raise_segv_exception ); switch(get_trap_code(context)) { @@ -1189,7 +1195,17 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { SIGCONTEXT *context = sigcontext; - EXCEPTION_RECORD *rec = setup_exception( context, raise_trap_exception ); + EXCEPTION_RECORD *rec; + +#ifdef __APPLE__ + /* MacOS single step flag handling is broken */ + if (wine_ldt_is_system(CS_sig(context)) && + (void *)EIP_sig(context) == raise_trap_exception && + !(EFL_sig(context) & 0x100)) + return; +#endif + + rec = setup_exception( context, raise_trap_exception ); switch(get_trap_code(context)) { diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index 72d73bb9e66..0a263b4ecc7 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -907,6 +907,8 @@ NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handles, UIN req->timeout = abs_timeout; wine_server_add_data( req, handles, count * sizeof(HANDLE) ); ret = wine_server_call( req ); + + ntdll_get_thread_data()->delta_priority = reply->priority + 100; } SERVER_END_REQ; if (ret == STATUS_PENDING) ret = wait_reply( &cookie ); @@ -915,11 +917,29 @@ NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handles, UIN signal_object = 0; /* don't signal it multiple times */ } - /* A test on Windows 2000 shows that Windows always yields during - a wait, but a wait that is hit by an event gets a priority - boost as well. This seems to model that behavior the closest. */ - if (ret == WAIT_TIMEOUT) NtYieldExecution(); - + /* + ** With the Linux 2.6.x kernel, it has become necessary to + ** try to more accurately recreate Windows scheduling in Wine. + ** 1. Tests on Windows 2000 show that all Waits + ** yield, but those that are signalled get a priority boost, + ** essentially negating the yield. Hence, we yield on all + ** Waits that timeout. + ** 2. High priority threads on Windows effectively don't yield + ** in this situation; we have to make a crude approximation of this. + ** Useful raw data: on 2.6 kernels, a sched_yield(), while it + ** matches the Windows behavior and relinquishes the time quanta, + ** it carries an extremely heavy penalty. + ** FIXME: Ask the kernel guys to give us the scheduling tools we need + */ +#ifdef HAVE_SCHED_YIELD + if (ret == WAIT_TIMEOUT) + { + if (ntdll_get_thread_data()->delta_priority == 0 || ntdll_get_thread_data()->delta_priority <= 100) + sched_yield(); + else + TRACE("%04x: skipped a yield! priority %u\n", GetCurrentThreadId(), ntdll_get_thread_data()->delta_priority); + } +#endif return ret; } @@ -1003,9 +1023,28 @@ NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeou NTDLL_get_server_abstime( &when, timeout ); - /* Note that we yield after establishing the desired timeout */ - NtYieldExecution(); + /* On Windows, a Sleep always yields; we replicate this, + but flavor it by yielding on higher priority threads only + when the time passed in was 0. + FIXME: Our info about the threads priority may not be accurate + FIXME: This is a crude approximation that should be obviated by kernel fixes */ +#ifdef HAVE_SCHED_YIELD + if (ntdll_get_thread_data()->delta_priority == 0) + { + THREAD_BASIC_INFORMATION info; + NTSTATUS status = NtQueryInformationThread( GetCurrentThread(), ThreadBasicInformation, + &info, sizeof(info), NULL ); + if (status == 0) + ntdll_get_thread_data()->delta_priority = info.Priority + 100; + } + if (ntdll_get_thread_data()->delta_priority == 0 || ntdll_get_thread_data()->delta_priority <= 100 || timeout->QuadPart == 0) + { + sched_yield(); + } + else + TRACE("%04x: skipped a yield! priority %u\n", GetCurrentThreadId(), ntdll_get_thread_data()->delta_priority); +#endif for (;;) { struct timeval tv; diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index 1fb0db61e03..3828750df87 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -112,6 +112,7 @@ static inline NTSTATUS init_teb( TEB *teb ) teb->Tib.Self = &teb->Tib; teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer; teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); + teb->ThreadLocalStoragePointer = teb->TlsSlots; if (!(thread_regs->fs = wine_ldt_alloc_fs())) return STATUS_TOO_MANY_THREADS; thread_data->request_fd = -1; diff --git a/dlls/ntdll/version.c b/dlls/ntdll/version.c index 5879ff27ce3..281b84c2a3d 100644 --- a/dlls/ntdll/version.c +++ b/dlls/ntdll/version.c @@ -368,25 +368,15 @@ static BOOL get_win9x_registry_version( RTL_OSVERSIONINFOEXW *version ) /********************************************************************** - * parse_win_version - * - * Parse the contents of the Version key. + * parse_version_string */ -static BOOL parse_win_version( HANDLE hkey ) +static BOOL parse_version_string( const WCHAR *str, DWORD length ) { - static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0}; - - UNICODE_STRING valueW; - char tmp[64], buffer[50]; - KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp; - DWORD count, len; int i; + DWORD len; + char buffer[50]; - RtlInitUnicodeString( &valueW, VersionW ); - if (NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp), &count )) - return FALSE; - - RtlUnicodeToMultiByteN( buffer, sizeof(buffer)-1, &len, (WCHAR *)info->Data, info->DataLength ); + RtlUnicodeToMultiByteN( buffer, sizeof(buffer)-1, &len, str, length ); buffer[len] = 0; for (i = 0; i < NB_WINDOWS_VERSIONS; i++) @@ -420,6 +410,27 @@ static BOOL parse_win_version( HANDLE hkey ) return FALSE; } +/********************************************************************** + * parse_win_version + * + * Parse the contents of the Version key. + */ +static BOOL parse_win_version( HKEY hkey ) +{ + static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0}; + + UNICODE_STRING valueW; + char tmp[64]; + KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp; + DWORD count; + + RtlInitUnicodeString( &valueW, VersionW ); + if (NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, tmp, sizeof(tmp), &count )) + return FALSE; + + return parse_version_string( (WCHAR *)info->Data, info->DataLength ); +} + /********************************************************************** * version_init @@ -436,6 +447,23 @@ void version_init( const WCHAR *appname ) current_version = &VersionData[NT2K]; /* default if nothing else is specified */ + /* awful CrossOver hack^H^H^H^Hproprietary enhancement */ + { + static const WCHAR cxverW[] = {'C','X','_','W','I','N','D','O','W','S','_','V','E','R','S','I','O','N',0}; + UNICODE_STRING valueW; + WCHAR cxversion[32]; + + RtlInitUnicodeString( &nameW, cxverW ); + valueW.MaximumLength = sizeof(cxversion); + valueW.Buffer = cxversion; + if (RtlQueryEnvironmentVariable_U(NULL, &nameW, &valueW) == STATUS_SUCCESS) + { + TRACE( "getting version from CX_WINDOWS_VERSION\n" ); + got_win_ver = parse_version_string( cxversion, strlenW(cxversion) * sizeof(WCHAR) ); + goto done; + } + } + RtlOpenCurrentUser( KEY_ALL_ACCESS, &root ); attr.Length = sizeof(attr); attr.RootDirectory = root; diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c index f2dd2992150..59024e2341e 100644 --- a/dlls/ntdll/virtual.c +++ b/dlls/ntdll/virtual.c @@ -54,6 +54,7 @@ #include "wine/list.h" #include "wine/debug.h" #include "ntdll_misc.h" +#include "wine/unicode.h" WINE_DEFAULT_DEBUG_CHANNEL(virtual); WINE_DECLARE_DEBUG_CHANNEL(module); @@ -73,6 +74,8 @@ typedef struct file_view void *base; /* Base address */ size_t size; /* Size in bytes */ HANDLE mapping; /* Handle to the file mapping */ + int id; /* a unique ID for this mapping */ + UINT refcount; /* number of times this view is references */ BYTE flags; /* Allocation flags (VFLAG_*) */ BYTE protect; /* Protection for all pages at allocation time */ BYTE prot[1]; /* Protection byte for each page */ @@ -372,6 +375,40 @@ static inline int is_beyond_limit( void *addr, size_t size, void *limit ) return (limit && (addr >= limit || (char *)addr + size > (char *)limit)); } +/**********************************************************************/ +/******************** CODEWEAVERS HACKS START HERE ********************/ + +/*********************************************************************** + * VIRTUAL_FindViewById + * + * Find the view matching an ID + * + * RETURNS + * View: Success + * NULL: Failure + */ +static BOOL VIRTUAL_FindViewById( int id, PVOID *addr_ptr, SIZE_T *size_ptr ) +{ + struct list *ptr; + + LIST_FOR_EACH( ptr, &views_list ) + { + struct file_view *view = LIST_ENTRY( ptr, struct file_view, entry ); + if (view->id == id) + { + view->refcount++; + *size_ptr = view->size; + *addr_ptr = view->base; + return TRUE; + } + } + + return FALSE; +} + +/********************* CODEWEAVERS HACKS END HERE *********************/ +/**********************************************************************/ + /*********************************************************************** * unmap_area @@ -397,6 +434,8 @@ static inline void unmap_area( void *addr, size_t size ) */ static void delete_view( struct file_view *view ) /* [in] View */ { + if ( --view->refcount > 0 ) + return; if (!(view->flags & VFLAG_SYSTEM)) unmap_area( view->base, view->size ); list_remove( &view->entry ); if (view->mapping) NtClose( view->mapping ); @@ -427,6 +466,8 @@ static NTSTATUS create_view( struct file_view **view_ret, void *base, size_t siz view->flags = 0; view->mapping = 0; view->protect = vprot; + view->refcount = 1; + view->id = 0; memset( view->prot, vprot & ~VPROT_IMAGE, size >> page_shift ); /* Insert it in the linked list */ @@ -1745,15 +1786,7 @@ NTSTATUS WINAPI NtQueryVirtualMemory( HANDLE process, LPCVOID addr, /* Fill the info structure */ - if (!view) - { - info->State = MEM_FREE; - info->Protect = PAGE_NOACCESS; - info->AllocationBase = 0; - info->AllocationProtect = 0; - info->Type = 0; - } - else + if (view) { BYTE vprot = view->prot[(base - alloc_base) >> page_shift]; info->State = (vprot & VPROT_COMMITTED) ? MEM_COMMIT : MEM_RESERVE; @@ -1765,12 +1798,66 @@ NTSTATUS WINAPI NtQueryVirtualMemory( HANDLE process, LPCVOID addr, else info->Type = MEM_MAPPED; for (size = base - alloc_base; size < view->size; size += page_size) if (view->prot[size >> page_shift] != vprot) break; + size -= base - alloc_base; + } + else + { + unsigned char vec; + size_t i; + int rc; + + rc = mincore((caddr_t)base, page_size, &vec); + if (rc == -1) + { + TRACE("mincore() == -1: %p is free\n", base); + info->State = MEM_FREE; + info->Protect = PAGE_NOACCESS; + info->AllocationBase = 0; + info->AllocationProtect = 0; + info->Type = 0; + } + else + { + /* We don't have any real information for these + * so make something up + */ + TRACE("mincore() == 0: %p is in use\n", base); + info->State = MEM_COMMIT; + info->Protect = PAGE_EXECUTE_READ; + info->AllocationProtect = PAGE_EXECUTE_READ; + info->Type = MEM_MAPPED; + } + + /* Scan up so we see how big this range really is */ + size -= base - alloc_base; + for (i = page_size; i < size; i += page_size) + { + if (mincore((caddr_t)base + i, page_size, &vec) != rc) + { + TRACE("mincore() != %d for %p\n", rc, base + i); + break; + } + } + size = i; + + /* And scan down so we report the proper AllocationBase */ + for (i = page_size; i <= base - alloc_base; i += page_size) + { + if (mincore((caddr_t)base - i, page_size, &vec) != rc) + { + TRACE("mincore() != %d for %p\n", rc, base - i); + break; + } + } + alloc_base = base - (i - page_size); + if (info->State != MEM_FREE) info->AllocationBase = alloc_base; } server_leave_uninterrupted_section( &csVirtual, &sigset ); info->BaseAddress = base; - info->RegionSize = size - (base - alloc_base); + info->RegionSize = size; if (res_len) *res_len = sizeof(*info); + TRACE("%p-%p alloc=%p size=0x%08lx State=%04x Protect=%04x Type=%04x\n", base, base+size, alloc_base, size, info->State, info->Protect, info->Type); return STATUS_SUCCESS; } @@ -1857,6 +1944,17 @@ NTSTATUS WINAPI NtCreateSection( HANDLE *handle, ACCESS_MASK access, const OBJEC BYTE vprot; DWORD len = (attr && attr->ObjectName) ? attr->ObjectName->Length : 0; + /******************** CODEWEAVERS HACKS START HERE ********************/ + DWORD hack_val = 0; + WCHAR cw_magic[] = { 'M','A','P','I','-','H','P','!' }; + + if( (file==NULL) && (len>sizeof cw_magic) && + !memcmp( cw_magic, attr->ObjectName->Buffer, sizeof cw_magic ) ) + { + hack_val = 1; + } + /******************** CODEWEAVERS HACKS ENDS HERE *********************/ + /* Check parameters */ if (len > MAX_PATH*sizeof(WCHAR)) return STATUS_NAME_TOO_LONG; @@ -1881,6 +1979,7 @@ NTSTATUS WINAPI NtCreateSection( HANDLE *handle, ACCESS_MASK access, const OBJEC req->size_high = size ? size->u.HighPart : 0; req->size_low = size ? size->u.LowPart : 0; req->protect = vprot; + req->hack_val = hack_val; if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len ); ret = wine_server_call( req ); *handle = reply->handle; @@ -1933,6 +2032,7 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p HANDLE dup_mapping, shared_file; LARGE_INTEGER offset; sigset_t sigset; + int id, hack_val; offset.QuadPart = offset_ptr ? offset_ptr->QuadPart : 0; @@ -1981,6 +2081,8 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p dup_mapping = reply->mapping; shared_file = reply->shared_file; shared_size = reply->shared_size; + id = reply->id; + hack_val = reply->hack_val; } SERVER_END_REQ; if (res) return res; @@ -2046,17 +2148,49 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p goto done; } - /* FIXME: If a mapping is created with SEC_RESERVE and a process, + /* Reserve a properly aligned area */ + + server_enter_uninterrupted_section( &csVirtual, &sigset ); + + /******************* CODEWEAVERS HACKS START HERE ******************* + * + * These two problems both happen with the section generated by + * msmapi32.dll in Windows 9x. This hack detects that section by name. + * + * PROBLEM 1 + * + * In Windows 9x, two mappings of the same section result in + * the same pointer across threads and processes. + * + * In Wine this is hard to duplicate across processes, so + * just try and do it in one process for the time being + * + * PROBLEM 2 + * + * FIXME: If a mapping is created with SEC_RESERVE and a process, * which has a view of this mapping commits some pages, they will * appear committed in all other processes, which have the same * view created. Since we don't support this yet, we create the * whole mapping committed. + * + * This hack is for Outlook XP - don't set VPROT_COMMITTED */ - prot |= VPROT_COMMITTED; + if( hack_val ) + { + if (VIRTUAL_FindViewById( id, addr_ptr, size_ptr )) + { + TRACE("Trying to be compatible with win9x mapping\n"); + res = STATUS_SUCCESS; + server_leave_uninterrupted_section( &csVirtual, &sigset ); + goto done; + } - /* Reserve a properly aligned area */ + /* prot |= VPROT_COMMITTED; */ + } + else + prot |= VPROT_COMMITTED; - server_enter_uninterrupted_section( &csVirtual, &sigset ); + /******************* CODEWEAVERS HACKS END HERE ********************/ res = map_view( &view, *addr_ptr, size, mask, FALSE, prot ); if (res) @@ -2075,6 +2209,7 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p { *addr_ptr = view->base; *size_ptr = size; + view->id = id; view->mapping = dup_mapping; dup_mapping = 0; /* don't close it */ } diff --git a/dlls/ole32/Makefile.in b/dlls/ole32/Makefile.in index 6779695d78d..965e06a4d9b 100644 --- a/dlls/ole32/Makefile.in +++ b/dlls/ole32/Makefile.in @@ -16,6 +16,7 @@ C_SRCS = \ compobj.c \ compositemoniker.c \ datacache.c \ + dcom_p.c \ defaulthandler.c \ dictionary.c \ enumx.c \ @@ -29,12 +30,14 @@ C_SRCS = \ marshal.c \ memlockbytes.c \ moniker.c \ + objidl_p.c \ ole2.c \ ole2stubs.c \ ole2impl.c \ ole32_main.c \ oleobj.c \ oleproxy.c \ + oleidl_p.c \ regsvr.c \ rpc.c \ stg_bigblockfile.c \ @@ -42,6 +45,7 @@ C_SRCS = \ stg_stream.c \ storage32.c \ stubmanager.c \ + unknwn_p.c \ usrmarshal.c C_SRCS16 = \ diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index 28bd184d451..2002df6fa82 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -2249,9 +2249,12 @@ void WINAPI CoFreeAllLibraries(void) */ void WINAPI CoFreeUnusedLibraries(void) { + /* CODEWEAVERS HACK for Office 2003: Don't call + * COMPOBJ_DllList_FreeUnused as it appears to do something the app + * doesn't expect and free a module that is in-use */ /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route * through the main apartment's thread to call DllCanUnloadNow */ - COMPOBJ_DllList_FreeUnused(0); + if (0) COMPOBJ_DllList_FreeUnused(0); } /*********************************************************************** diff --git a/dlls/ole32/defaulthandler.c b/dlls/ole32/defaulthandler.c index 9486813f105..124ffd56584 100644 --- a/dlls/ole32/defaulthandler.c +++ b/dlls/ole32/defaulthandler.c @@ -116,6 +116,11 @@ struct DefaultHandler /* connection cookie for the advise on the delegate OLE object */ DWORD dwAdvConn; + + /* optional class factory for object */ + IClassFactory *pCFObject; + /* TRUE if acting as an inproc server instead of an inproc handler */ + BOOL inproc_server; }; typedef struct DefaultHandler DefaultHandler; @@ -174,6 +179,8 @@ static HRESULT WINAPI DefaultHandler_NDIUnknown_QueryInterface( { DefaultHandler *This = impl_from_NDIUnknown(iface); + TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObject); + /* Perform a sanity check on the parameters. */ if (!ppvObject) return E_INVALIDARG; @@ -199,12 +206,21 @@ static HRESULT WINAPI DefaultHandler_NDIUnknown_QueryInterface( if (FAILED(hr)) FIXME("interface %s not implemented by data cache\n", debugstr_guid(riid)); return hr; } + else if (This->pOleDelegate) + { + HRESULT hr = IUnknown_QueryInterface(This->pOleDelegate, riid, ppvObject); + TRACE("delegate object returned hr 0x%08x\n", hr); + return hr; + } /* Check that we obtained an interface. */ if (*ppvObject == NULL) { WARN( "() : asking for un supported interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; + /* native returns CO_E_OBJNOTCONNECTED here instead of E_NOINTERFACE, since + * the latter means that an interface will *never* be supported, but it + * could be supported later when we connect to the delegate object */ + return CO_E_OBJNOTCONNECTED; } /* @@ -1530,7 +1546,9 @@ static const IAdviseSinkVtbl DefaultHandler_IAdviseSink_VTable = */ static DefaultHandler* DefaultHandler_Construct( REFCLSID clsid, - LPUNKNOWN pUnkOuter) + LPUNKNOWN pUnkOuter, + DWORD flags, + IClassFactory *pCF) { DefaultHandler* This = NULL; @@ -1548,6 +1566,8 @@ static DefaultHandler* DefaultHandler_Construct( This->lpvtblIRunnableObject = &DefaultHandler_IRunnableObject_VTable; This->lpvtblIAdviseSink = &DefaultHandler_IAdviseSink_VTable; + This->inproc_server = (flags & EMBDHLP_INPROC_SERVER) ? TRUE : FALSE; + /* * Start with one reference count. The caller of this function * must release the interface pointer when it is done. @@ -1590,6 +1610,27 @@ static DefaultHandler* DefaultHandler_Construct( This->dwAdvConn = 0; + if (This->inproc_server && !(flags & EMBDHLP_DELAYCREATE)) + { + HRESULT hr; + This->pCFObject = NULL; + if (pCF) + hr = IClassFactory_CreateInstance(pCF, NULL, &IID_IOleObject, (void **)&This->pOleDelegate); + else + hr = CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER, + &IID_IOleObject, (void **)&This->pOleDelegate); + if (SUCCEEDED(hr)) + hr = IUnknown_QueryInterface(This->pOleDelegate, &IID_IDataObject, (void **)&This->pDataDelegate); + if (FAILED(hr)) + WARN("object creation failed with error 0x%x\n", hr); + } + else + { + This->pCFObject = pCF; + if (pCF) + IClassFactory_AddRef(pCF); + } + return This; } @@ -1638,18 +1679,22 @@ static void DefaultHandler_Destroy( } /****************************************************************************** - * OleCreateDefaultHandler [OLE32.@] + * OleCreateEmbeddingHelper [OLE32.@] */ -HRESULT WINAPI OleCreateDefaultHandler( +HRESULT WINAPI OleCreateEmbeddingHelper( REFCLSID clsid, LPUNKNOWN pUnkOuter, + DWORD flags, + IClassFactory *pCF, 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); + TRACE("(%s, %p, 0x%x, %p, %s, %p)\n", debugstr_guid(clsid), pUnkOuter, flags, pCF, debugstr_guid(riid), ppvObj); + + /* FIXME: verify flags */ /* * Sanity check @@ -1671,7 +1716,7 @@ HRESULT WINAPI OleCreateDefaultHandler( /* * Try to construct a new instance of the class. */ - newHandler = DefaultHandler_Construct(clsid, pUnkOuter); + newHandler = DefaultHandler_Construct(clsid, pUnkOuter, flags, pCF); if (!newHandler) return E_OUTOFMEMORY; @@ -1689,3 +1734,17 @@ HRESULT WINAPI OleCreateDefaultHandler( return hr; } + +/****************************************************************************** + * OleCreateDefaultHandler [OLE32.@] + */ +HRESULT WINAPI OleCreateDefaultHandler( + REFCLSID clsid, + LPUNKNOWN pUnkOuter, + REFIID riid, + LPVOID* ppvObj) +{ + TRACE("(%s, %p, %s, %p)\n", debugstr_guid(clsid), pUnkOuter, debugstr_guid(riid), ppvObj); + return OleCreateEmbeddingHelper(clsid, pUnkOuter, + EMBDHLP_INPROC_HANDLER | EMBDHLP_CREATENOW, NULL, riid, ppvObj); +} diff --git a/dlls/ole32/ole2.c b/dlls/ole32/ole2.c index 8b61ac648dc..d9f782ec400 100644 --- a/dlls/ole32/ole2.c +++ b/dlls/ole32/ole2.c @@ -1701,9 +1701,8 @@ BOOL WINAPI IsAccelerator(HACCEL hAccel, int cAccelEntries, LPMSG lpMsg, WORD* l return FALSE; } if((lpMsg->message != WM_KEYDOWN && - lpMsg->message != WM_KEYUP && lpMsg->message != WM_SYSKEYDOWN && - lpMsg->message != WM_SYSKEYUP && + lpMsg->message != WM_SYSCHAR && lpMsg->message != WM_CHAR)) return FALSE; lpAccelTbl = HeapAlloc(GetProcessHeap(), 0, cAccelEntries * sizeof(ACCEL)); if (NULL == lpAccelTbl) @@ -2358,6 +2357,18 @@ HRESULT WINAPI OleCreate( hres = CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, riid, (LPVOID*)&pUnk); + /* + * If that fails, as it will most times, load the default + * OLE handler. + */ + if (FAILED(hres)) + { + hres = OleCreateDefaultHandler(rclsid, + NULL, + riid, + (void**)&pUnk); + } + if (SUCCEEDED(hres)) hres = IStorage_SetClass(pStg, rclsid); diff --git a/dlls/ole32/ole32.spec b/dlls/ole32/ole32.spec index 3ae0240bd3e..190aa2c1514 100644 --- a/dlls/ole32/ole32.spec +++ b/dlls/ole32/ole32.spec @@ -170,7 +170,7 @@ @ stub OleConvertOLESTREAMToIStorageEx @ stdcall OleCreate(ptr ptr long ptr ptr ptr ptr) @ stdcall OleCreateDefaultHandler(ptr ptr ptr ptr) -@ stub OleCreateEmbeddingHelper +@ stdcall OleCreateEmbeddingHelper(ptr ptr long ptr ptr ptr) @ stub OleCreateEx @ stdcall OleCreateFromData(ptr ptr long ptr ptr ptr ptr) @ stub OleCreateFromDataEx diff --git a/dlls/ole32/oleproxy.c b/dlls/ole32/oleproxy.c index dd12e5c3787..f6ab9a93fc2 100644 --- a/dlls/ole32/oleproxy.c +++ b/dlls/ole32/oleproxy.c @@ -59,10 +59,14 @@ #include "compobj_private.h" #include "moniker.h" +#include "comcat.h" /* FOR HACK BELOW */ + #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(ole); +#if 0 + static ULONG WINAPI RURpcProxyBufferImpl_Release(LPRPCPROXYBUFFER iface); /* From: http://msdn.microsoft.com/library/en-us/com/cmi_m_4lda.asp @@ -998,6 +1002,27 @@ static const IPSFactoryBufferVtbl psfacbufvtbl = { /* This is the whole PSFactoryBuffer object, just the vtableptr */ static const IPSFactoryBufferVtbl *lppsfac = &psfacbufvtbl; +#endif + +#include "rpcproxy.h" + +static CStdPSFactoryBuffer PSFactoryBuffer; + +CSTDSTUBBUFFERRELEASE(&PSFactoryBuffer) + +extern const ExtendedProxyFileInfo dcom_ProxyFileInfo; +extern const ExtendedProxyFileInfo objidl_ProxyFileInfo; +extern const ExtendedProxyFileInfo oleidl_ProxyFileInfo; +extern const ExtendedProxyFileInfo unknwn_ProxyFileInfo; + +const ProxyFileInfo* aProxyFileList[] = +{ + &dcom_ProxyFileInfo, + &objidl_ProxyFileInfo, + &oleidl_ProxyFileInfo, + &unknwn_ProxyFileInfo, + NULL +}; /*********************************************************************** * DllGetClassObject [OLE32.@] @@ -1006,7 +1031,8 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv) { *ppv = NULL; if (IsEqualIID(rclsid, &CLSID_PSFactoryBuffer)) - return IPSFactoryBuffer_QueryInterface((IPSFactoryBuffer *)&lppsfac, iid, ppv); + return NdrDllGetClassObject(rclsid, iid, ppv, aProxyFileList, + &CLSID_PSFactoryBuffer, &PSFactoryBuffer); if (IsEqualIID(rclsid,&CLSID_DfMarshal)&&( IsEqualIID(iid,&IID_IClassFactory) || IsEqualIID(iid,&IID_IUnknown) @@ -1026,6 +1052,18 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv) if (IsEqualCLSID(rclsid, &CLSID_ClassMoniker)) return ClassMonikerCF_Create(iid, ppv); + /* CODEWEAVERS HACK: Fix up native implementing Component Categories + * Manager in ole32 and us in comcat - we should remove this hack when + * we get around to moving our comcat implementation to ole32 */ + if (IsEqualCLSID(rclsid, &CLSID_StdComponentCategoriesMgr)) + { + HMODULE hComCat = LoadLibraryA("comcat"); + typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv); + DllGetClassObjectFunc DllGetClassObject = + (DllGetClassObjectFunc)GetProcAddress(hComCat, "DllGetClassObject"); + if (DllGetClassObject) return DllGetClassObject(rclsid, 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/dlls/ole32/rpc.c b/dlls/ole32/rpc.c index c7604b7a731..6586c804c28 100644 --- a/dlls/ole32/rpc.c +++ b/dlls/ole32/rpc.c @@ -1782,7 +1782,7 @@ static DWORD WINAPI local_server_thread(LPVOID param) hPipe = CreateNamedPipeW( pipefn, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, - 4096, 4096, 500 /* 0.5 second timeout */, NULL ); + 4096, 4096, 5000 /* 5 second timeout */, NULL ); lsp->pipe = hPipe; SetEvent(lsp->ready_event); diff --git a/dlls/ole32/stg_bigblockfile.c b/dlls/ole32/stg_bigblockfile.c index a208bb8aa10..085d8612f04 100644 --- a/dlls/ole32/stg_bigblockfile.c +++ b/dlls/ole32/stg_bigblockfile.c @@ -114,6 +114,7 @@ static MappedPage* BIGBLOCKFILE_CreatePage(LPBIGBLOCKFILE This, static DWORD BIGBLOCKFILE_GetProtectMode(DWORD openFlags); static BOOL BIGBLOCKFILE_FileInit(LPBIGBLOCKFILE This, HANDLE hFile); static BOOL BIGBLOCKFILE_MemInit(LPBIGBLOCKFILE This, ILockBytes* plkbyt); +static void BIGBLOCKFILE_DeleteList(LPBIGBLOCKFILE This, MappedPage *list); /* Note that this evaluates a and b multiple times, so don't * pass expressions with side effects. */ @@ -356,7 +357,15 @@ void BIGBLOCKFILE_SetSize(LPBIGBLOCKFILE This, ULARGE_INTEGER newSize) TRACE("from %u to %u\n", This->filesize.u.LowPart, newSize.u.LowPart); /* * unmap all views, must be done before call to SetEndFile + * + * Just ditch the victim list because there is no guarentee we will need them + * and it is not worth the performance hit to unmap and remap them all. */ + BIGBLOCKFILE_DeleteList(This, This->victimhead); + This->victimhead = NULL; + This->victimtail = NULL; + This->num_victim_pages = 0; + BIGBLOCKFILE_UnmapAllMappedPages(This); if (This->fileBased) diff --git a/dlls/ole32/usrmarshal.c b/dlls/ole32/usrmarshal.c index 1651cd7ff7a..975874eaf9a 100644 --- a/dlls/ole32/usrmarshal.c +++ b/dlls/ole32/usrmarshal.c @@ -1861,3 +1861,908 @@ void __RPC_USER SNB_UserFree(ULONG *pFlags, SNB *pSnb) { FIXME(":stub\n"); } + +HRESULT STDMETHODCALLTYPE IClassFactory_CreateInstance_Proxy( + IClassFactory * This, + /* [unique][in] */ IUnknown *pUnkOuter, + /* [in] */ REFIID riid, + /* [iid_is][out] */ void **ppvObject) +{ + TRACE("(%p, %s, %p)\n", pUnkOuter, debugstr_guid(riid), ppvObject); + + *ppvObject = NULL; + + if (pUnkOuter) + { + ERR("aggregation not allowed on remote objects\n"); + return CLASS_E_NOAGGREGATION; + } + return IClassFactory_RemoteCreateInstance_Proxy(This, riid, (IUnknown **)ppvObject); +} + +HRESULT STDMETHODCALLTYPE IClassFactory_CreateInstance_Stub( + IClassFactory * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ IUnknown **ppvObject) +{ + TRACE("\n"); + return IClassFactory_CreateInstance(This, NULL, riid, (void **)ppvObject); +} + +HRESULT STDMETHODCALLTYPE IClassFactory_LockServer_Proxy( + IClassFactory * This, + /* [in] */ BOOL fLock) +{ + TRACE("(%s)\n", fLock ? "TRUE" : "FALSE"); + return S_OK; /* like native, ignore LockServer requests */ +} + +HRESULT STDMETHODCALLTYPE IClassFactory_LockServer_Stub( + IClassFactory * This, + /* [in] */ BOOL fLock) +{ + TRACE("(%s)\n", fLock ? "TRUE" : "FALSE"); + return IClassFactory_LockServer(This, fLock); +} + +HRESULT STDMETHODCALLTYPE IOleInPlaceActiveObject_TranslateAccelerator_Proxy( + IOleInPlaceActiveObject * This, + /* [in] */ LPMSG lpmsg) +{ + WARN("(%p): doesn't work remotely\n", lpmsg); + return S_OK; /* like native, this call isn't remotable */ +} + +HRESULT STDMETHODCALLTYPE IOleInPlaceActiveObject_TranslateAccelerator_Stub( + IOleInPlaceActiveObject * This) +{ + ERR("(): shouldn't be called\n"); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE IOleInPlaceActiveObject_ResizeBorder_Proxy( + IOleInPlaceActiveObject * This, + /* [in] */ LPCRECT prcBorder, + /* [unique][in] */ IOleInPlaceUIWindow *pUIWindow, + /* [in] */ BOOL fFrameWindow) +{ + FIXME("(%p, %p, %d): stub\n", prcBorder, pUIWindow, fFrameWindow); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IOleInPlaceActiveObject_ResizeBorder_Stub( + IOleInPlaceActiveObject * This, + /* [in] */ LPCRECT prcBorder, + /* [in] */ REFIID riid, + /* [iid_is][unique][in] */ IOleInPlaceUIWindow *pUIWindow, + /* [in] */ BOOL fFrameWindow) +{ + FIXME("(%p, %s, %p, %d): stub\n", prcBorder, debugstr_guid(riid), pUIWindow, fFrameWindow); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IOleCache2_UpdateCache_Proxy( + IOleCache2 * This, + /* [in] */ LPDATAOBJECT pDataObject, + /* [in] */ DWORD grfUpdf, + /* [in] */ LPVOID pReserved) +{ + FIXME("(%p, 0x%08x, %p): check me\n", pDataObject, grfUpdf, pReserved); + return IOleCache2_RemoteUpdateCache_Proxy(This, pDataObject, grfUpdf, (LONG_PTR)pReserved); +} + +HRESULT STDMETHODCALLTYPE IOleCache2_UpdateCache_Stub( + IOleCache2 * This, + /* [in] */ LPDATAOBJECT pDataObject, + /* [in] */ DWORD grfUpdf, + /* [in] */ LONG_PTR pReserved) +{ + FIXME("(%p, 0x%08x, 0x%08lx): check me\n", pDataObject, grfUpdf, pReserved); + return IOleCache2_UpdateCache(This, pDataObject, grfUpdf, (LPVOID)pReserved); +} + +HRESULT STDMETHODCALLTYPE IEnumOLEVERB_Next_Proxy( + IEnumOLEVERB * This, + /* [in] */ ULONG celt, + /* [length_is][size_is][out] */ LPOLEVERB rgelt, + /* [out] */ ULONG *pceltFetched) +{ + ULONG fetched; + TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched); + if (!pceltFetched) + pceltFetched = &fetched; + return IEnumOLEVERB_RemoteNext_Proxy(This, celt, rgelt, pceltFetched); +} + +HRESULT STDMETHODCALLTYPE IEnumOLEVERB_Next_Stub( + IEnumOLEVERB * This, + /* [in] */ ULONG celt, + /* [length_is][size_is][out] */ LPOLEVERB rgelt, + /* [out] */ ULONG *pceltFetched) +{ + HRESULT hr; + TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched); + *pceltFetched = 0; + hr = IEnumOLEVERB_Next(This, celt, rgelt, pceltFetched); + if (hr == S_OK) *pceltFetched = celt; + return hr; +} + +HRESULT STDMETHODCALLTYPE IViewObject_Draw_Proxy( + IViewObject * This, + /* [in] */ DWORD dwDrawAspect, + /* [in] */ LONG lindex, + /* [unique][in] */ void *pvAspect, + /* [unique][in] */ DVTARGETDEVICE *ptd, + /* [in] */ HDC hdcTargetDev, + /* [in] */ HDC hdcDraw, + /* [in] */ LPCRECTL lprcBounds, + /* [unique][in] */ LPCRECTL lprcWBounds, + /* [in] */ BOOL ( STDMETHODCALLTYPE *pfnContinue )( + ULONG_PTR dwContinue), + /* [in] */ ULONG_PTR dwContinue) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IViewObject_Draw_Stub( + IViewObject * This, + /* [in] */ DWORD dwDrawAspect, + /* [in] */ LONG lindex, + /* [in] */ ULONG_PTR pvAspect, + /* [unique][in] */ DVTARGETDEVICE *ptd, + /* [in] */ ULONG_PTR hdcTargetDev, + /* [in] */ ULONG_PTR hdcDraw, + /* [in] */ LPCRECTL lprcBounds, + /* [unique][in] */ LPCRECTL lprcWBounds, + /* [in] */ IContinue *pContinue) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IViewObject_GetColorSet_Proxy( + IViewObject * This, + /* [in] */ DWORD dwDrawAspect, + /* [in] */ LONG lindex, + /* [unique][in] */ void *pvAspect, + /* [unique][in] */ DVTARGETDEVICE *ptd, + /* [in] */ HDC hicTargetDev, + /* [out] */ LOGPALETTE **ppColorSet) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IViewObject_GetColorSet_Stub( + IViewObject * This, + /* [in] */ DWORD dwDrawAspect, + /* [in] */ LONG lindex, + /* [in] */ ULONG_PTR pvAspect, + /* [unique][in] */ DVTARGETDEVICE *ptd, + /* [in] */ ULONG_PTR hicTargetDev, + /* [out] */ LOGPALETTE **ppColorSet) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IViewObject_Freeze_Proxy( + IViewObject * This, + /* [in] */ DWORD dwDrawAspect, + /* [in] */ LONG lindex, + /* [unique][in] */ void *pvAspect, + /* [out] */ DWORD *pdwFreeze) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IViewObject_Freeze_Stub( + IViewObject * This, + /* [in] */ DWORD dwDrawAspect, + /* [in] */ LONG lindex, + /* [in] */ ULONG_PTR pvAspect, + /* [out] */ DWORD *pdwFreeze) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IViewObject_GetAdvise_Proxy( + IViewObject * This, + /* [unique][out] */ DWORD *pAspects, + /* [unique][out] */ DWORD *pAdvf, + /* [out] */ IAdviseSink **ppAdvSink) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IViewObject_GetAdvise_Stub( + IViewObject * This, + /* [out] */ DWORD *pAspects, + /* [out] */ DWORD *pAdvf, + /* [out] */ IAdviseSink **ppAdvSink) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IEnumUnknown_Next_Proxy( + IEnumUnknown * This, + /* [in] */ ULONG celt, + /* [out] */ IUnknown **rgelt, + /* [out] */ ULONG *pceltFetched) +{ + ULONG fetched; + TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched); + if (!pceltFetched) + pceltFetched = &fetched; + return IEnumUnknown_RemoteNext_Proxy(This, celt, rgelt, pceltFetched); +} + +HRESULT STDMETHODCALLTYPE IEnumUnknown_Next_Stub( + IEnumUnknown * This, + /* [in] */ ULONG celt, + /* [length_is][size_is][out] */ IUnknown **rgelt, + /* [out] */ ULONG *pceltFetched) +{ + HRESULT hr; + TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched); + *pceltFetched = 0; + hr = IEnumUnknown_Next(This, celt, rgelt, pceltFetched); + if (hr == S_OK) *pceltFetched = celt; + return hr; +} + +HRESULT STDMETHODCALLTYPE IBindCtx_SetBindOptions_Proxy( + IBindCtx * This, + /* [in] */ BIND_OPTS *pbindopts) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + + +HRESULT STDMETHODCALLTYPE IBindCtx_SetBindOptions_Stub( + IBindCtx * This, + /* [in] */ BIND_OPTS2 *pbindopts) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IBindCtx_GetBindOptions_Proxy( + IBindCtx * This, + /* [out][in] */ BIND_OPTS *pbindopts) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + + +HRESULT STDMETHODCALLTYPE IBindCtx_GetBindOptions_Stub( + IBindCtx * This, + /* [out][in] */ BIND_OPTS2 *pbindopts) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IEnumMoniker_Next_Proxy( + IEnumMoniker * This, + /* [in] */ ULONG celt, + /* [length_is][size_is][out] */ IMoniker **rgelt, + /* [out] */ ULONG *pceltFetched) +{ + ULONG fetched; + TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched); + if (!pceltFetched) + pceltFetched = &fetched; + return IEnumMoniker_RemoteNext_Proxy(This, celt, rgelt, pceltFetched); +} + + +HRESULT STDMETHODCALLTYPE IEnumMoniker_Next_Stub( + IEnumMoniker * This, + /* [in] */ ULONG celt, + /* [length_is][size_is][out] */ IMoniker **rgelt, + /* [out] */ ULONG *pceltFetched) +{ + HRESULT hr; + TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched); + *pceltFetched = 0; + hr = IEnumMoniker_Next(This, celt, rgelt, pceltFetched); + if (hr == S_OK) *pceltFetched = celt; + return hr; +} + +BOOL STDMETHODCALLTYPE IRunnableObject_IsRunning_Proxy( + IRunnableObject * This) +{ + FIXME(": stub\n"); + return FALSE; +} + + +HRESULT STDMETHODCALLTYPE IRunnableObject_IsRunning_Stub( + IRunnableObject * This) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IMoniker_BindToObject_Proxy( + IMoniker * This, + /* [unique][in] */ IBindCtx *pbc, + /* [unique][in] */ IMoniker *pmkToLeft, + /* [in] */ REFIID riidResult, + /* [iid_is][out] */ void **ppvResult) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IMoniker_BindToObject_Stub( + IMoniker * This, + /* [unique][in] */ IBindCtx *pbc, + /* [unique][in] */ IMoniker *pmkToLeft, + /* [in] */ REFIID riidResult, + /* [iid_is][out] */ IUnknown **ppvResult) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IMoniker_BindToStorage_Proxy( + IMoniker * This, + /* [unique][in] */ IBindCtx *pbc, + /* [unique][in] */ IMoniker *pmkToLeft, + /* [in] */ REFIID riid, + /* [iid_is][out] */ void **ppvObj) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IMoniker_BindToStorage_Stub( + IMoniker * This, + /* [unique][in] */ IBindCtx *pbc, + /* [unique][in] */ IMoniker *pmkToLeft, + /* [in] */ REFIID riid, + /* [iid_is][out] */ IUnknown **ppvObj) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IEnumString_Next_Proxy( + IEnumString * This, + /* [in] */ ULONG celt, + /* [length_is][size_is][out] */ LPOLESTR *rgelt, + /* [out] */ ULONG *pceltFetched) +{ + ULONG fetched; + TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched); + if (!pceltFetched) + pceltFetched = &fetched; + return IEnumString_RemoteNext_Proxy(This, celt, rgelt, pceltFetched); +} + +HRESULT STDMETHODCALLTYPE IEnumString_Next_Stub( + IEnumString * This, + /* [in] */ ULONG celt, + /* [length_is][size_is][out] */ LPOLESTR *rgelt, + /* [out] */ ULONG *pceltFetched) +{ + HRESULT hr; + TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched); + *pceltFetched = 0; + hr = IEnumString_Next(This, celt, rgelt, pceltFetched); + if (hr == S_OK) *pceltFetched = celt; + return hr; +} + +HRESULT STDMETHODCALLTYPE ISequentialStream_Read_Proxy( + ISequentialStream * This, + /* [length_is][size_is][out] */ void *pv, + /* [in] */ ULONG cb, + /* [out] */ ULONG *pcbRead) +{ + ULONG cbRead; + HRESULT hr; + + TRACE("(%p, %d, %p)\n", pv, cb, pcbRead); + hr = ISequentialStream_RemoteRead_Proxy(This, pv, cb, &cbRead); + if (pcbRead) + *pcbRead = cbRead; + + return hr; +} + +HRESULT STDMETHODCALLTYPE ISequentialStream_Read_Stub( + ISequentialStream * This, + /* [length_is][size_is][out] */ byte *pv, + /* [in] */ ULONG cb, + /* [out] */ ULONG *pcbRead) +{ + HRESULT hr; + TRACE("(%p, %d, %p)\n", pv, cb, pcbRead); + hr = ISequentialStream_Read(This, pv, cb, pcbRead); + TRACE("hr = 0x%08x, *pcbRead = %d\n", hr, *pcbRead); + return hr; +} + +HRESULT STDMETHODCALLTYPE ISequentialStream_Write_Proxy( + ISequentialStream * This, + /* [size_is][in] */ const void *pv, + /* [in] */ ULONG cb, + /* [out] */ ULONG *pcbWritten) +{ + ULONG cbWritten; + HRESULT hr; + + TRACE("(%p, %d, %p)\n", pv, cb, pcbWritten); + hr = ISequentialStream_RemoteWrite_Proxy(This, (byte *)pv, cb, &cbWritten); + if (pcbWritten) + *pcbWritten = cbWritten; + + return hr; +} + +HRESULT STDMETHODCALLTYPE ISequentialStream_Write_Stub( + ISequentialStream * This, + /* [size_is][in] */ const byte *pv, + /* [in] */ ULONG cb, + /* [out] */ ULONG *pcbWritten) +{ + TRACE("(%p, %d, %p)\n", pv, cb, pcbWritten); + return ISequentialStream_Write(This, pv, cb, pcbWritten); +} + +HRESULT STDMETHODCALLTYPE IStream_Seek_Proxy( + IStream * This, + /* [in] */ LARGE_INTEGER dlibMove, + /* [in] */ DWORD dwOrigin, + /* [out] */ ULARGE_INTEGER *plibNewPosition) +{ + ULARGE_INTEGER dlibNewPosition; + HRESULT hr; + + TRACE("(%s, 0x%x, %p)\n", wine_dbgstr_longlong(dlibMove.QuadPart), dwOrigin, plibNewPosition); + + hr = IStream_RemoteSeek_Proxy(This, dlibMove, dwOrigin, &dlibNewPosition); + if (plibNewPosition) + *plibNewPosition = dlibNewPosition; + + return hr; +} + +HRESULT STDMETHODCALLTYPE IStream_Seek_Stub( + IStream * This, + /* [in] */ LARGE_INTEGER dlibMove, + /* [in] */ DWORD dwOrigin, + /* [out] */ ULARGE_INTEGER *plibNewPosition) +{ + TRACE("(%s, 0x%x, %p)\n", wine_dbgstr_longlong(dlibMove.QuadPart), dwOrigin, plibNewPosition); + + plibNewPosition->QuadPart = 0; + return IStream_Seek(This, dlibMove, dwOrigin, plibNewPosition); +} + +HRESULT STDMETHODCALLTYPE IStream_CopyTo_Proxy( + IStream * This, + /* [unique][in] */ IStream *pstm, + /* [in] */ ULARGE_INTEGER cb, + /* [out] */ ULARGE_INTEGER *pcbRead, + /* [out] */ ULARGE_INTEGER *pcbWritten) +{ + ULARGE_INTEGER cbRead; + ULARGE_INTEGER cbWritten; + HRESULT hr; + + TRACE("(%p, %s, %p, %p)\n", pstm, wine_dbgstr_longlong(cb.QuadPart), pcbRead, pcbWritten); + + hr = IStream_RemoteCopyTo_Proxy(This, pstm, cb, &cbRead, &cbWritten); + if (pcbRead) + *pcbRead = cbRead; + if (pcbWritten) + *pcbWritten = cbWritten; + + return hr; +} + +HRESULT STDMETHODCALLTYPE IStream_CopyTo_Stub( + IStream * This, + /* [unique][in] */ IStream *pstm, + /* [in] */ ULARGE_INTEGER cb, + /* [out] */ ULARGE_INTEGER *pcbRead, + /* [out] */ ULARGE_INTEGER *pcbWritten) +{ + TRACE("(%p, %s, %p, %p)\n", pstm, wine_dbgstr_longlong(cb.QuadPart), pcbRead, pcbWritten); + + pcbRead->QuadPart = 0; + pcbWritten->QuadPart = 0; + return IStream_CopyTo(This, pstm, cb, pcbRead, pcbWritten); +} + +HRESULT STDMETHODCALLTYPE IEnumSTATSTG_Next_Proxy( + IEnumSTATSTG * This, + /* [in] */ ULONG celt, + /* [length_is][size_is][out] */ STATSTG *rgelt, + /* [out] */ ULONG *pceltFetched) +{ + ULONG fetched; + TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched); + if (!pceltFetched) + pceltFetched = &fetched; + return IEnumSTATSTG_RemoteNext_Proxy(This, celt, rgelt, pceltFetched); +} + +HRESULT STDMETHODCALLTYPE IEnumSTATSTG_Next_Stub( + IEnumSTATSTG * This, + /* [in] */ ULONG celt, + /* [length_is][size_is][out] */ STATSTG *rgelt, + /* [out] */ ULONG *pceltFetched) +{ + HRESULT hr; + TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched); + *pceltFetched = 0; + hr = IEnumSTATSTG_Next(This, celt, rgelt, pceltFetched); + if (hr == S_OK) *pceltFetched = celt; + return hr; +} + +HRESULT STDMETHODCALLTYPE IStorage_OpenStream_Proxy( + IStorage * This, + /* [in] */ LPCOLESTR pwcsName, + /* [unique][in] */ void *reserved1, + /* [in] */ DWORD grfMode, + /* [in] */ DWORD reserved2, + /* [out] */ IStream **ppstm) +{ + TRACE("(%s, %p, 0x%x, 0x%x, %p)\n", debugstr_w(pwcsName), reserved1, grfMode, reserved2, ppstm); + *ppstm = NULL; + return IStorage_RemoteOpenStream_Proxy(This, pwcsName, 0, NULL, grfMode, reserved2, ppstm); +} + +HRESULT STDMETHODCALLTYPE IStorage_OpenStream_Stub( + IStorage * This, + /* [in] */ LPCOLESTR pwcsName, + /* [in] */ unsigned long cbReserved1, + /* [size_is][unique][in] */ byte *reserved1, + /* [in] */ DWORD grfMode, + /* [in] */ DWORD reserved2, + /* [out] */ IStream **ppstm) +{ + TRACE("(%s, %p, 0x%x, 0x%x, %p)\n", debugstr_w(pwcsName), reserved1, grfMode, reserved2, ppstm); + return IStorage_OpenStream(This, pwcsName, NULL, grfMode, reserved2, ppstm); +} + +HRESULT STDMETHODCALLTYPE IStorage_EnumElements_Proxy( + IStorage * This, + /* [in] */ DWORD reserved1, + /* [size_is][unique][in] */ void *reserved2, + /* [in] */ DWORD reserved3, + /* [out] */ IEnumSTATSTG **ppenum) +{ + TRACE("(0x%x, %p, 0x%x, %p)\n", reserved1, reserved2, reserved3, ppenum); + *ppenum = NULL; + return IStorage_RemoteEnumElements_Proxy(This, reserved1, 0, NULL, reserved3, ppenum); +} + +HRESULT STDMETHODCALLTYPE IStorage_EnumElements_Stub( + IStorage * This, + /* [in] */ DWORD reserved1, + /* [in] */ unsigned long cbReserved2, + /* [size_is][unique][in] */ byte *reserved2, + /* [in] */ DWORD reserved3, + /* [out] */ IEnumSTATSTG **ppenum) +{ + TRACE("(0x%x, %p, 0x%x, %p)\n", reserved1, reserved2, reserved3, ppenum); + return IStorage_EnumElements(This, reserved1, NULL, reserved3, ppenum); +} + +HRESULT STDMETHODCALLTYPE ILockBytes_ReadAt_Proxy( + ILockBytes * This, + /* [in] */ ULARGE_INTEGER ulOffset, + /* [length_is][size_is][out] */ void *pv, + /* [in] */ ULONG cb, + /* [out] */ ULONG *pcbRead) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE ILockBytes_ReadAt_Stub( + ILockBytes * This, + /* [in] */ ULARGE_INTEGER ulOffset, + /* [length_is][size_is][out] */ byte *pv, + /* [in] */ ULONG cb, + /* [out] */ ULONG *pcbRead) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE ILockBytes_WriteAt_Proxy( + ILockBytes * This, + /* [in] */ ULARGE_INTEGER ulOffset, + /* [size_is][in] */ const void *pv, + /* [in] */ ULONG cb, + /* [out] */ ULONG *pcbWritten) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE ILockBytes_WriteAt_Stub( + ILockBytes * This, + /* [in] */ ULARGE_INTEGER ulOffset, + /* [size_is][in] */ const byte *pv, + /* [in] */ ULONG cb, + /* [out] */ ULONG *pcbWritten) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IFillLockBytes_FillAppend_Proxy( + IFillLockBytes * This, + /* [size_is][in] */ const void *pv, + /* [in] */ ULONG cb, + /* [out] */ ULONG *pcbWritten) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IFillLockBytes_FillAppend_Stub( + IFillLockBytes * This, + /* [size_is][in] */ const byte *pv, + /* [in] */ ULONG cb, + /* [out] */ ULONG *pcbWritten) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IFillLockBytes_FillAt_Proxy( + IFillLockBytes * This, + /* [in] */ ULARGE_INTEGER ulOffset, + /* [size_is][in] */ const void *pv, + /* [in] */ ULONG cb, + /* [out] */ ULONG *pcbWritten) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IFillLockBytes_FillAt_Stub( + IFillLockBytes * This, + /* [in] */ ULARGE_INTEGER ulOffset, + /* [size_is][in] */ const byte *pv, + /* [in] */ ULONG cb, + /* [out] */ ULONG *pcbWritten) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IEnumFORMATETC_Next_Proxy( + IEnumFORMATETC * This, + /* [in] */ ULONG celt, + /* [length_is][size_is][out] */ FORMATETC *rgelt, + /* [out] */ ULONG *pceltFetched) +{ + ULONG fetched; + TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched); + if (!pceltFetched) + pceltFetched = &fetched; + return IEnumFORMATETC_RemoteNext_Proxy(This, celt, rgelt, pceltFetched); +} + +HRESULT STDMETHODCALLTYPE IEnumFORMATETC_Next_Stub( + IEnumFORMATETC * This, + /* [in] */ ULONG celt, + /* [length_is][size_is][out] */ FORMATETC *rgelt, + /* [out] */ ULONG *pceltFetched) +{ + HRESULT hr; + TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched); + *pceltFetched = 0; + hr = IEnumFORMATETC_Next(This, celt, rgelt, pceltFetched); + if (hr == S_OK) *pceltFetched = celt; + return hr; +} + +HRESULT STDMETHODCALLTYPE IEnumSTATDATA_Next_Proxy( + IEnumSTATDATA * This, + /* [in] */ ULONG celt, + /* [length_is][size_is][out] */ STATDATA *rgelt, + /* [out] */ ULONG *pceltFetched) +{ + ULONG fetched; + TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched); + if (!pceltFetched) + pceltFetched = &fetched; + return IEnumSTATDATA_RemoteNext_Proxy(This, celt, rgelt, pceltFetched); +} + +HRESULT STDMETHODCALLTYPE IEnumSTATDATA_Next_Stub( + IEnumSTATDATA * This, + /* [in] */ ULONG celt, + /* [length_is][size_is][out] */ STATDATA *rgelt, + /* [out] */ ULONG *pceltFetched) +{ + HRESULT hr; + TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched); + *pceltFetched = 0; + hr = IEnumSTATDATA_Next(This, celt, rgelt, pceltFetched); + if (hr == S_OK) *pceltFetched = celt; + return hr; +} + +HRESULT STDMETHODCALLTYPE IDataObject_GetData_Proxy( + IDataObject * This, + /* [unique][in] */ FORMATETC *pformatetcIn, + /* [out] */ STGMEDIUM *pmedium) +{ + TRACE("(%p, %p)\n", pformatetcIn, pmedium); + return IDataObject_RemoteGetData_Proxy(This, pformatetcIn, pmedium); +} + +HRESULT STDMETHODCALLTYPE IDataObject_GetData_Stub( + IDataObject * This, + /* [unique][in] */ FORMATETC *pformatetcIn, + /* [out] */ STGMEDIUM *pRemoteMedium) +{ + TRACE("(%p, %p)\n", pformatetcIn, pRemoteMedium); + return IDataObject_GetData(This, pformatetcIn, pRemoteMedium); +} + +HRESULT STDMETHODCALLTYPE IDataObject_GetDataHere_Proxy( + IDataObject * This, + /* [unique][in] */ FORMATETC *pformatetc, + /* [out][in] */ STGMEDIUM *pmedium) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IDataObject_GetDataHere_Stub( + IDataObject * This, + /* [unique][in] */ FORMATETC *pformatetc, + /* [out][in] */ STGMEDIUM *pRemoteMedium) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IDataObject_SetData_Proxy( + IDataObject * This, + /* [unique][in] */ FORMATETC *pformatetc, + /* [unique][in] */ STGMEDIUM *pmedium, + /* [in] */ BOOL fRelease) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IDataObject_SetData_Stub( + IDataObject * This, + /* [unique][in] */ FORMATETC *pformatetc, + /* [unique][in] */ FLAG_STGMEDIUM *pmedium, + /* [in] */ BOOL fRelease) +{ + FIXME(": stub\n"); + return E_NOTIMPL; +} + + +void STDMETHODCALLTYPE IAdviseSink_OnDataChange_Proxy( + IAdviseSink * This, + /* [unique][in] */ FORMATETC *pFormatetc, + /* [unique][in] */ STGMEDIUM *pStgmed) +{ + TRACE("(%p, %p)\n", pFormatetc, pStgmed); + IAdviseSink_RemoteOnDataChange_Proxy(This, pFormatetc, pStgmed); +} + + +HRESULT STDMETHODCALLTYPE IAdviseSink_OnDataChange_Stub( + IAdviseSink * This, + /* [unique][in] */ FORMATETC *pFormatetc, + /* [unique][in] */ ASYNC_STGMEDIUM *pStgmed) +{ + TRACE("(%p, %p)\n", pFormatetc, pStgmed); + IAdviseSink_OnDataChange(This, pFormatetc, pStgmed); + return S_OK; +} + +void STDMETHODCALLTYPE IAdviseSink_OnViewChange_Proxy( + IAdviseSink * This, + /* [in] */ DWORD dwAspect, + /* [in] */ LONG lindex) +{ + TRACE("(%d, %d)\n", dwAspect, lindex); + IAdviseSink_RemoteOnViewChange_Proxy(This, dwAspect, lindex); +} + + +HRESULT STDMETHODCALLTYPE IAdviseSink_OnViewChange_Stub( + IAdviseSink * This, + /* [in] */ DWORD dwAspect, + /* [in] */ LONG lindex) +{ + TRACE("(%d, %d)\n", dwAspect, lindex); + IAdviseSink_OnViewChange(This, dwAspect, lindex); + return S_OK; +} + +void STDMETHODCALLTYPE IAdviseSink_OnRename_Proxy( + IAdviseSink * This, + /* [in] */ IMoniker *pmk) +{ + TRACE("(%p)\n", pmk); + IAdviseSink_RemoteOnRename_Proxy(This, pmk); +} + + +HRESULT STDMETHODCALLTYPE IAdviseSink_OnRename_Stub( + IAdviseSink * This, + /* [in] */ IMoniker *pmk) +{ + TRACE("(%p)\n", pmk); + IAdviseSink_OnRename(This, pmk); + return S_OK; +} + +void STDMETHODCALLTYPE IAdviseSink_OnSave_Proxy( + IAdviseSink * This) +{ + TRACE("()\n"); + IAdviseSink_RemoteOnSave_Proxy(This); +} + +HRESULT STDMETHODCALLTYPE IAdviseSink_OnSave_Stub( + IAdviseSink * This) +{ + TRACE("()\n"); + IAdviseSink_OnSave(This); + return S_OK; +} + +void STDMETHODCALLTYPE IAdviseSink_OnClose_Proxy( + IAdviseSink * This) +{ + TRACE("()\n"); + IAdviseSink_RemoteOnClose_Proxy(This); +} + +HRESULT STDMETHODCALLTYPE IAdviseSink_OnClose_Stub( + IAdviseSink * This) +{ + TRACE("()\n"); + IAdviseSink_OnClose(This); + return S_OK; +} + +void STDMETHODCALLTYPE IAdviseSink2_OnLinkSrcChange_Proxy( + IAdviseSink2 * This, + /* [unique][in] */ IMoniker *pmk) +{ + TRACE("(%p)\n", pmk); + IAdviseSink2_RemoteOnLinkSrcChange_Proxy(This, pmk); +} + +HRESULT STDMETHODCALLTYPE IAdviseSink2_OnLinkSrcChange_Stub( + IAdviseSink2 * This, + /* [unique][in] */ IMoniker *pmk) +{ + TRACE("(%p)\n", pmk); + IAdviseSink2_OnLinkSrcChange(This, pmk); + return S_OK; +} diff --git a/dlls/oleaut32/Makefile.in b/dlls/oleaut32/Makefile.in index 0d2f99d092a..94c77e01017 100644 --- a/dlls/oleaut32/Makefile.in +++ b/dlls/oleaut32/Makefile.in @@ -14,6 +14,7 @@ C_SRCS = \ dispatch.c \ hash.c \ oaidl_p.c \ + ocidl_p.c \ oleaut.c \ olefont.c \ olepicture.c \ diff --git a/dlls/oleaut32/oaidl_p.c b/dlls/oleaut32/oaidl_p.c index c4419d7483d..d57a11b4c07 100644 --- a/dlls/oleaut32/oaidl_p.c +++ b/dlls/oleaut32/oaidl_p.c @@ -26,6 +26,7 @@ #endif +/* Begin Wine only section */ #include #define COBJMACROS @@ -34,6 +35,27 @@ #include "winbase.h" #include "objbase.h" #include "rpcproxy.h" + +#include "wine/exception.h" +#include "excpt.h" + +static WINE_EXCEPTION_FILTER(exception_filter) +{ + if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION || + GetExceptionCode() == EXCEPTION_PRIV_INSTRUCTION) + return EXCEPTION_CONTINUE_SEARCH; + return EXCEPTION_EXECUTE_HANDLER; +} +#undef RpcTryExcept +#define RpcTryExcept __TRY +#undef RpcExcept +#define RpcExcept(x) __EXCEPT(exception_filter) +#undef RpcEndExcept +#define RpcEndExcept __ENDTRY +#undef RpcExceptionCode +#define RpcExceptionCode GetExceptionCode +/* End Wine only section */ + #ifndef __RPCPROXY_H_VERSION__ #error this stub requires an updated version of #endif /* __RPCPROXY_H_VERSION__ */ diff --git a/dlls/oleaut32/oleaut.c b/dlls/oleaut32/oleaut.c index 1fe68b8d635..9fb5cba80a2 100644 --- a/dlls/oleaut32/oleaut.c +++ b/dlls/oleaut32/oleaut.c @@ -176,6 +176,8 @@ BSTR WINAPI SysAllocString(LPCOLESTR str) */ void WINAPI SysFreeString(BSTR str) { + static void *prev; + void *stored; DWORD* bufferPointer; /* NULL is a valid parameter */ @@ -190,10 +192,15 @@ void WINAPI SysFreeString(BSTR str) bufferPointer--; - /* - * Free the memory from its "real" origin. + /* Nasty hack: Quicktime accesses a string after freeing it, */ + /* so we store the pointer and only free it next time around */ + /* Ichitaro hads a bad habit of calling this twice with the same pointer + * causing us to store a pointer that has already been freed but by the time * we get to this function again may be realloced with different information + * causing a memory corruption. */ - HeapFree(GetProcessHeap(), 0, bufferPointer); + stored = InterlockedExchangePointer( &prev, bufferPointer ); + if (stored != bufferPointer) + HeapFree(GetProcessHeap(), 0, stored); } /****************************************************************************** @@ -786,7 +793,8 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv) } if (IsEqualCLSID(rclsid, &CLSID_PSTypeInfo) || IsEqualCLSID(rclsid, &CLSID_PSTypeLib) || - IsEqualCLSID(rclsid, &CLSID_PSEnumVariant)) { + IsEqualCLSID(rclsid, &CLSID_PSEnumVariant) || + IsEqualCLSID(rclsid, &CLSID_PSFactoryBuffer)) { return OLEAUTPS_DllGetClassObject(&CLSID_PSDispatch, iid, ppv); } if (IsEqualCLSID(rclsid, &CLSID_PSDispatch) && IsEqualIID(iid, &IID_IPSFactoryBuffer)) { diff --git a/dlls/oleaut32/regsvr.c b/dlls/oleaut32/regsvr.c index b1dd7140134..a8343f2a34a 100644 --- a/dlls/oleaut32/regsvr.c +++ b/dlls/oleaut32/regsvr.c @@ -448,9 +448,6 @@ static GUID const CLSID_RecordInfo = { 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", diff --git a/dlls/oleaut32/typelib.h b/dlls/oleaut32/typelib.h index fc1cba0a711..5fd5e38634f 100644 --- a/dlls/oleaut32/typelib.h +++ b/dlls/oleaut32/typelib.h @@ -610,5 +610,7 @@ DEFINE_OLEGUID( CLSID_PSTypeLib, 0x00020423, 0x0000, 0x0000 ); DEFINE_OLEGUID( CLSID_PSOAInterface, 0x00020424, 0x0000, 0x0000 ); DEFINE_OLEGUID( CLSID_PSTypeComp, 0x00020425, 0x0000, 0x0000 ); +DEFINE_GUID( CLSID_PSFactoryBuffer, 0xb196b286, 0xbab4, 0x101a, 0xb6, 0x9c, 0x00, 0xaa, 0x00, 0x34, 0x1d, 0x07 ); + /*---------------------------END--------------------------------------------*/ #endif diff --git a/dlls/oleaut32/usrmarshal.c b/dlls/oleaut32/usrmarshal.c index eea46c606bd..3c6d3f005fd 100644 --- a/dlls/oleaut32/usrmarshal.c +++ b/dlls/oleaut32/usrmarshal.c @@ -26,6 +26,8 @@ #define NONAMELESSUNION #define NONAMELESSSTRUCT +#define PROXY_DELEGATION + #include "windef.h" #include "winbase.h" #include "wingdi.h" @@ -37,6 +39,7 @@ #include "rpcproxy.h" #include "typelib.h" #include "wine/debug.h" +#include "ocidl.h" WINE_DEFAULT_DEBUG_CHANNEL(ole); @@ -48,11 +51,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); static CStdPSFactoryBuffer PSFactoryBuffer; CSTDSTUBBUFFERRELEASE(&PSFactoryBuffer) +CSTDSTUBBUFFER2RELEASE(&PSFactoryBuffer) extern const ExtendedProxyFileInfo oaidl_ProxyFileInfo; +extern const ExtendedProxyFileInfo ocidl_ProxyFileInfo; static const ProxyFileInfo *OLEAUT32_ProxyFileList[] = { &oaidl_ProxyFileInfo, + &ocidl_ProxyFileInfo, NULL }; @@ -669,6 +675,33 @@ void WINAPI VARIANT_UserFree(ULONG *pFlags, VARIANT *pvar) CoTaskMemFree(ref); } +/* HFONT */ + +ULONG WINAPI HFONT_UserSize(ULONG *pFlags, ULONG Start, HFONT *phfont) +{ + FIXME("not implemented\n"); + return 0; +} + +unsigned char * WINAPI HFONT_UserMarshal(ULONG *pFlags, unsigned char *Buffer, HFONT *phfont) +{ + FIXME("not implemented\n"); + return NULL; +} + +unsigned char * WINAPI HFONT_UserUnmarshal(ULONG *pFlags, unsigned char *Buffer, HFONT *phfont) +{ + FIXME("not implemented\n"); + return NULL; +} + +void WINAPI HFONT_UserFree(ULONG *pFlags, HFONT *phfont) +{ + FIXME("not implemented\n"); + return; +} + + /* LPSAFEARRAY */ /* Get the number of cells in a SafeArray */ @@ -1973,3 +2006,157 @@ HRESULT __RPC_STUB ITypeLib2_GetDocumentation2_Stub( FIXME("not implemented\n"); return E_FAIL; } + +HRESULT CALLBACK IClassFactory2_CreateInstanceLic_Proxy( + IClassFactory2* This, + IUnknown* pUnkOuter, + IUnknown* pUnkReserved, + REFIID riid, + BSTR bstrKey, + PVOID* ppvObj) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB IClassFactory2_CreateInstanceLic_Stub( + IClassFactory2* This, + REFIID riid, + BSTR bstrKey, + IUnknown** ppvObj) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT CALLBACK IEnumConnections_Next_Proxy( + IEnumConnections* This, + ULONG cConnections, + LPCONNECTDATA rgcd, + ULONG* pcFetched) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB IEnumConnections_Next_Stub( + IEnumConnections* This, + ULONG cConnections, + LPCONNECTDATA rgcd, + ULONG* pcFetched) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT CALLBACK IEnumConnectionPoints_Next_Proxy( + IEnumConnectionPoints* This, + ULONG cConnections, + LPCONNECTIONPOINT* ppCP, + ULONG* pcFetched) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB IEnumConnectionPoints_Next_Stub( + IEnumConnectionPoints* This, + ULONG cConnections, + LPCONNECTIONPOINT* ppCP, + ULONG* pcFetched) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT CALLBACK IPersistMemory_Load_Proxy( + IPersistMemory* This, + LPVOID pMem, + ULONG cbSize) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB IPersistMemory_Load_Stub( + IPersistMemory* This, + BYTE* pMem, + ULONG cbSize) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT CALLBACK IPersistMemory_Save_Proxy( + IPersistMemory* This, + LPVOID pMem, + BOOL fClearDirty, + ULONG cbSize) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB IPersistMemory_Save_Stub( + IPersistMemory* This, + BYTE* pMem, + BOOL fClearDirty, + ULONG cbSize) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +void CALLBACK IAdviseSinkEx_OnViewStatusChange_Proxy( + IAdviseSinkEx* This, + DWORD dwViewStatus) +{ + FIXME("not implemented\n"); + return; +} + +HRESULT __RPC_STUB IAdviseSinkEx_OnViewStatusChange_Stub( + IAdviseSinkEx* This, + DWORD dwViewStatus) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT CALLBACK IEnumOleUndoUnits_Next_Proxy( + IEnumOleUndoUnits* This, + ULONG cElt, + IOleUndoUnit** rgElt, + ULONG* pcEltFetched) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB IEnumOleUndoUnits_Next_Stub( + IEnumOleUndoUnits* This, + ULONG cElt, + IOleUndoUnit** rgElt, + ULONG* pcEltFetched) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT CALLBACK IQuickActivate_QuickActivate_Proxy( + IQuickActivate* This, + QACONTAINER* pQaContainer, + QACONTROL* pQaControl) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB IQuickActivate_QuickActivate_Stub( + IQuickActivate* This, + QACONTAINER* pQaContainer, + QACONTROL* pQaControl) +{ + FIXME("not implemented\n"); + return E_FAIL; +} diff --git a/dlls/oleaut32/vartype.c b/dlls/oleaut32/vartype.c index 54b389a6959..a6a483d4f1c 100644 --- a/dlls/oleaut32/vartype.c +++ b/dlls/oleaut32/vartype.c @@ -6772,23 +6772,34 @@ HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* p if (!pbstrOut) return E_INVALIDARG; - VARIANT_DIFromDec(pDecIn, &temp); - VARIANT_DI_tostringW(&temp, buff, 256); - - if (dwFlags & LOCALE_USE_NLS) + if (!DEC_HI32(pDecIn)) { - WCHAR numbuff[256]; + WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1; + INT scale = DEC_SCALE(pDecIn); - /* 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 = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags); + /* Create the basic number string */ + *szOut-- = '\0'; + szOut = VARIANT_WriteNumber(DEC_LO64(pDecIn), szOut); + if (DEC_SIGN(pDecIn)) + dwFlags |= VAR_NEGATIVE; + + /* modify for scale */ + if (scale) + { + WCHAR* ptr; + ptr = &szOut[strlenW(szOut)+1]; + while (ptr != &szOut[scale]) + { + *(ptr+1) = *ptr; + ptr --; + } + *(ptr+1) = *ptr; + *ptr = '.'; + } + + *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut); + TRACE("returning %s\n", debugstr_w(*pbstrOut)); + return *pbstrOut ? S_OK : E_OUTOFMEMORY; } TRACE("returning %s\n", debugstr_w(*pbstrOut)); diff --git a/dlls/opengl32/wgl.c b/dlls/opengl32/wgl.c index a23cd83c6d6..6cb4e41e06b 100644 --- a/dlls/opengl32/wgl.c +++ b/dlls/opengl32/wgl.c @@ -82,6 +82,7 @@ void (*wine_tsx11_unlock_ptr)(void) = NULL; static HMODULE opengl32_handle; static char internal_gl_disabled_extensions[512]; +static BOOL wowhack = FALSE; static char* internal_gl_extensions = NULL; typedef struct wine_glcontext { @@ -107,6 +108,18 @@ void enter_gl(void) return; } +/* + * 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, (LPBYTE)buffer, &size )) return 0; + if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0; + return ERROR_FILE_NOT_FOUND; +} + const GLubyte * WINAPI wine_glGetString( GLenum name ); /*********************************************************************** @@ -684,13 +697,22 @@ void WINAPI wine_glGetIntegerv( GLenum pname, GLint* params ) #define SONAME_LIBGL "libGL.so" #endif +#define IS_OPTION_TRUE(ch) \ + ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1') +#define IS_OPTION_FALSE(ch) \ + ((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0') + /* This is for brain-dead applications that use OpenGL functions before even creating a rendering context.... */ static BOOL process_attach(void) { HMODULE mod_x11, mod_gdi32; DWORD size = sizeof(internal_gl_disabled_extensions); + char tmp[32]; HKEY hkey = 0; + HKEY appkey = 0; + char buffer[MAX_PATH+10]; + DWORD len; GetDesktopWindow(); /* make sure winex11 is loaded (FIXME) */ mod_x11 = GetModuleHandleA( "winex11.drv" ); @@ -716,11 +738,41 @@ static BOOL process_attach(void) wine_wgl.p_wglViewport = (void *)wine_wgl.p_wglGetProcAddress("wglViewport"); internal_gl_disabled_extensions[0] = 0; - if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\OpenGL", &hkey)) { - if (!RegQueryValueExA( hkey, "DisabledExtensions", 0, NULL, (LPBYTE)internal_gl_disabled_extensions, &size)) { + + /* @@ Wine registry key: HKLM\Software\Wine\OpenGL */ + if ( RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\OpenGL", &hkey) ) hkey = 0; + + len = GetModuleFileNameA( 0, buffer, MAX_PATH ); + if (len && len < MAX_PATH) + { + HKEY tmpkey; + /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\OpenGL */ + if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey )) + { + char *p, *appname = buffer; + if ((p = strrchr( appname, '/' ))) appname = p + 1; + if ((p = strrchr( appname, '\\' ))) appname = p + 1; + strcat( appname, "\\OpenGL" ); + TRACE("appname = [%s]\n", appname); + if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0; + RegCloseKey( tmpkey ); + } + } + + if ( 0 != hkey || 0 != appkey ) { + if ( !get_config_key( hkey, appkey, "DisabledExtensions", internal_gl_disabled_extensions, size) ) { TRACE("found DisabledExtensions=\"%s\"\n", internal_gl_disabled_extensions); } - RegCloseKey(hkey); + size = sizeof(tmp); + if ( !get_config_key( hkey, appkey, "wowhack", tmp, size) ) { + TRACE("found wowhack=\"%s\"\n", tmp); + if(IS_OPTION_TRUE(tmp[0])) wowhack = TRUE; + } + + if (appkey) + RegCloseKey( appkey ); + if (hkey) + RegCloseKey( hkey ); } return TRUE; diff --git a/dlls/pstorec/pstorec.c b/dlls/pstorec/pstorec.c index 6e2b5a59c2b..1ae39bb3142 100644 --- a/dlls/pstorec/pstorec.c +++ b/dlls/pstorec/pstorec.c @@ -19,14 +19,21 @@ */ #include +#include #define COBJMACROS #include "windef.h" #include "winbase.h" +#include "winreg.h" +#include "winerror.h" #include "winuser.h" +#include "winnls.h" #include "ole2.h" +#include "shlwapi.h" + #include "pstore.h" +#include "wine/unicode.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(pstores); @@ -37,21 +44,35 @@ typedef struct LONG ref; } PStore_impl; -BOOL WINAPI DllMain(HINSTANCE hinst, DWORD fdwReason, LPVOID fImpLoad) + +static const WCHAR szPStoresKey[] = { + 'S','o','f','t','w','a','r','e','\\', + 'W','i','n','e','\\','W','i','n','e','\\', + 'p','s','t','o','r','e','s',0 +}; + +/* convert a guid to a wide character string */ +static void IPStore_guid2wstr( const GUID *guid, LPWSTR wstr ) { - TRACE("%p %x %p\n", hinst, fdwReason, fImpLoad); + char str[40]; + + sprintf(str, "{%08X-%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 ); +} - switch (fdwReason) +static LONG IPStore_OpenRoot( PST_KEY Key, HKEY *hkey ) +{ + switch( Key ) { - case DLL_WINE_PREATTACH: - return FALSE; /* prefer native version */ - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(hinst); - break; - case DLL_PROCESS_DETACH: - break; + case PST_KEY_CURRENT_USER: + return RegCreateKeyW( HKEY_CURRENT_USER, szPStoresKey, hkey ); + case PST_KEY_LOCAL_MACHINE: + return RegCreateKeyW( HKEY_LOCAL_MACHINE, szPStoresKey, hkey ); } - return TRUE; + return ERROR_INVALID_PARAMETER; } /************************************************************************** @@ -64,7 +85,7 @@ static HRESULT WINAPI PStore_fnQueryInterface( { PStore_impl *This = (PStore_impl *)iface; - TRACE("%p %s\n",This,debugstr_guid(riid)); + TRACE("(%p)->(\n\tIID:\t%s)\n",This,debugstr_guid(riid)); *ppvObj = NULL; @@ -117,7 +138,7 @@ static ULONG WINAPI PStore_fnRelease(IPStore* iface) static HRESULT WINAPI PStore_fnGetInfo( IPStore* iface, PPST_PROVIDERINFO* ppProperties) { FIXME("\n"); - return E_NOTIMPL; + return E_FAIL; } /****************************************************************************** @@ -127,7 +148,7 @@ static HRESULT WINAPI PStore_fnGetProvParam( IPStore* iface, DWORD dwParam, DWORD* pcbData, BYTE** ppbData, DWORD dwFlags) { FIXME("\n"); - return E_NOTIMPL; + return E_FAIL; } /****************************************************************************** @@ -137,7 +158,7 @@ static HRESULT WINAPI PStore_fnSetProvParam( IPStore* This, DWORD dwParam, DWORD cbData, BYTE* pbData, DWORD* dwFlags) { FIXME("\n"); - return E_NOTIMPL; + return E_FAIL; } /****************************************************************************** @@ -146,10 +167,38 @@ static HRESULT WINAPI PStore_fnSetProvParam( IPStore* This, static HRESULT WINAPI PStore_fnCreateType( IPStore* This, PST_KEY Key, const GUID* pType, PPST_TYPEINFO pInfo, DWORD dwFlags) { - FIXME("%p %08x %s %p(%d,%s) %08x\n", This, Key, debugstr_guid(pType), + LONG r; + HKEY hkey, hkeytype; + WCHAR szGuid[40]; + HRESULT hres = E_FAIL; + DWORD dwCreated = 0; + + TRACE("%p %08x %s %p(%d,%s) %08x\n", This, Key, debugstr_guid(pType), pInfo, pInfo->cbSize, debugstr_w(pInfo->szDisplayName), dwFlags); - return E_NOTIMPL; + r = IPStore_OpenRoot( Key, &hkey ); + if( r ) + return hres; + + IPStore_guid2wstr( pType, szGuid ); + r = RegCreateKeyExW( hkey, szGuid, 0, NULL, REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS, NULL, &hkeytype, &dwCreated ); + if( r == ERROR_SUCCESS ) + { + if( dwCreated == REG_CREATED_NEW_KEY ) + { + r = RegSetValueW( hkeytype, NULL, REG_SZ, + pInfo->szDisplayName, strlenW( pInfo->szDisplayName ) ); + if( r == ERROR_SUCCESS ) + hres = PST_E_OK; + RegCloseKey( hkeytype ); + } + else + hres = PST_E_TYPE_EXISTS; + } + RegCloseKey( hkey ); + + return hres; } /****************************************************************************** @@ -159,7 +208,7 @@ static HRESULT WINAPI PStore_fnGetTypeInfo( IPStore* This, PST_KEY Key, const GUID* pType, PPST_TYPEINFO** ppInfo, DWORD dwFlags) { FIXME("\n"); - return E_NOTIMPL; + return E_FAIL; } /****************************************************************************** @@ -168,8 +217,24 @@ static HRESULT WINAPI PStore_fnGetTypeInfo( IPStore* This, static HRESULT WINAPI PStore_fnDeleteType( IPStore* This, PST_KEY Key, const GUID* pType, DWORD dwFlags) { - FIXME("%p %d %s %08x\n", This, Key, debugstr_guid(pType), dwFlags); - return E_NOTIMPL; + LONG r; + HKEY hkey; + WCHAR szGuid[40]; + HRESULT hres = E_FAIL; + + TRACE("%p %d %s %08x\n", This, Key, debugstr_guid(pType), dwFlags); + + r = IPStore_OpenRoot( Key, &hkey ); + if( r ) + return hres; + + IPStore_guid2wstr( pType, szGuid ); + r = SHDeleteKeyW( hkey, szGuid ); + if( r == ERROR_SUCCESS ) + hres = PST_E_OK; + RegCloseKey( hkey ); + + return hres; } /****************************************************************************** @@ -179,9 +244,40 @@ static HRESULT WINAPI PStore_fnCreateSubtype( IPStore* This, PST_KEY Key, const GUID* pType, const GUID* pSubtype, PPST_TYPEINFO pInfo, PPST_ACCESSRULESET pRules, DWORD dwFlags) { - FIXME("%p %08x %s %s %p %p %08x\n", This, Key, debugstr_guid(pType), + LONG r; + HKEY hkey, hkeysubtype; + WCHAR szGuid[80]; + HRESULT hres = E_FAIL; + DWORD dwCreated = 0; + + TRACE("%p %08x %s %s %p %p %08x\n", This, Key, debugstr_guid(pType), debugstr_guid(pSubtype), pInfo, pRules, dwFlags); - return E_NOTIMPL; + + r = IPStore_OpenRoot( Key, &hkey ); + if( r ) + return E_FAIL; + + IPStore_guid2wstr( pType, szGuid ); + szGuid[38] = '\\'; + IPStore_guid2wstr( pSubtype, &szGuid[39] ); + r = RegCreateKeyExW( hkey, szGuid, 0, NULL, REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS, NULL, &hkeysubtype, &dwCreated ); + if( r == ERROR_SUCCESS ) + { + if( dwCreated == REG_CREATED_NEW_KEY ) + { + r = RegSetValueW( hkeysubtype, NULL, REG_SZ, + pInfo->szDisplayName, strlenW( pInfo->szDisplayName ) ); + if( r == ERROR_SUCCESS ) + hres = S_OK; + RegCloseKey( hkeysubtype ); + } + else + hres = PST_E_TYPE_EXISTS; + } + RegCloseKey( hkey ); + + return hres; } /****************************************************************************** @@ -192,7 +288,7 @@ static HRESULT WINAPI PStore_fnGetSubtypeInfo( IPStore* This, PPST_TYPEINFO** ppInfo, DWORD dwFlags) { FIXME("\n"); - return E_NOTIMPL; + return E_FAIL; } /****************************************************************************** @@ -201,9 +297,31 @@ static HRESULT WINAPI PStore_fnGetSubtypeInfo( IPStore* This, static HRESULT WINAPI PStore_fnDeleteSubtype( IPStore* This, PST_KEY Key, const GUID* pType, const GUID* pSubtype, DWORD dwFlags) { - FIXME("%p %u %s %s %08x\n", This, Key, + LONG r; + HKEY hkey, hkeytype; + WCHAR szGuid[40]; + HRESULT hres = E_FAIL; + + TRACE("%p %u %s %s %08x\n", This, Key, debugstr_guid(pType), debugstr_guid(pSubtype), dwFlags); - return E_NOTIMPL; + + r = IPStore_OpenRoot( Key, &hkey ); + if( r ) + return hres; + + IPStore_guid2wstr( pType, szGuid ); + r = RegOpenKeyW( hkey, szGuid, &hkeytype ); + if( r == ERROR_SUCCESS ) + { + IPStore_guid2wstr( pSubtype, szGuid ); + r = SHDeleteKeyW( hkeytype, szGuid ); + if( r == ERROR_SUCCESS ) + hres = PST_E_OK; + RegCloseKey( hkeytype ); + } + RegCloseKey( hkey ); + + return hres; } /****************************************************************************** @@ -214,7 +332,7 @@ static HRESULT WINAPI PStore_fnReadAccessRuleset( IPStore* This, PPST_ACCESSRULESET** ppRules, DWORD dwFlags) { FIXME("\n"); - return E_NOTIMPL; + return E_FAIL; } /****************************************************************************** @@ -225,7 +343,7 @@ static HRESULT WINAPI PStore_fnWriteAccessRuleset( IPStore* This, PPST_TYPEINFO pInfo, PPST_ACCESSRULESET pRules, DWORD dwFlags) { FIXME("\n"); - return E_NOTIMPL; + return E_FAIL; } /****************************************************************************** @@ -235,7 +353,7 @@ static HRESULT WINAPI PStore_fnEnumTypes( IPStore* This, PST_KEY Key, DWORD dwFlags, IEnumPStoreTypes** ppenum) { FIXME("\n"); - return E_NOTIMPL; + return E_FAIL; } /****************************************************************************** @@ -245,7 +363,7 @@ static HRESULT WINAPI PStore_fnEnumSubtypes( IPStore* This, PST_KEY Key, const GUID* pType, DWORD dwFlags, IEnumPStoreTypes** ppenum) { FIXME("\n"); - return E_NOTIMPL; + return E_FAIL; } /****************************************************************************** @@ -256,7 +374,7 @@ static HRESULT WINAPI PStore_fnDeleteItem( IPStore* This, PST_KEY Key, PPST_PROMPTINFO pPromptInfo, DWORD dwFlags) { FIXME("\n"); - return E_NOTIMPL; + return E_FAIL; } /****************************************************************************** @@ -266,10 +384,44 @@ static HRESULT WINAPI PStore_fnReadItem( IPStore* This, PST_KEY Key, const GUID* pItemType, const GUID* pItemSubtype, LPCWSTR szItemName, DWORD *cbData, BYTE** pbData, PPST_PROMPTIFO pPromptInfo, DWORD dwFlags) { - FIXME("%p %08x %s %s %s %p %p %p %08x\n", This, Key, - debugstr_guid(pItemType), debugstr_guid(pItemSubtype), - debugstr_w(szItemName), cbData, pbData, pPromptInfo, dwFlags); - return E_NOTIMPL; + LONG r; + HKEY hkey, hkeysubtype; + WCHAR szGuid[80]; + DWORD type, sz = 0; + + TRACE("%p %08x %s %s %s %p %p %p %08x\n", This, Key, + debugstr_guid(pItemType), debugstr_guid(pItemSubtype), + debugstr_w(szItemName), cbData, pbData, pPromptInfo, dwFlags); + + *pbData = NULL; + *cbData = 0; + + r = IPStore_OpenRoot( Key, &hkey ); + if( r ) + return E_FAIL; + + IPStore_guid2wstr( pItemType, szGuid ); + szGuid[38] = '\\'; + IPStore_guid2wstr( pItemSubtype, &szGuid[39] ); + r = RegOpenKeyW( hkey, szGuid, &hkeysubtype ); + if( r == ERROR_SUCCESS ) + { + type = 0; + sz = 0; + r = RegQueryValueExW( hkeysubtype, szItemName, NULL, &type, + NULL, cbData ); + if( ( r == ERROR_SUCCESS ) && ( type == REG_BINARY ) ) + { + *pbData = CoTaskMemAlloc( *cbData ); + r = RegQueryValueExW( hkeysubtype, szItemName, NULL, &type, + *pbData, cbData ); + } + RegCloseKey( hkeysubtype ); + } + + RegCloseKey( hkey ); + + return ( r == ERROR_SUCCESS ) ? S_OK : E_FAIL; } /****************************************************************************** @@ -280,10 +432,32 @@ static HRESULT WINAPI PStore_fnWriteItem( IPStore* This, PST_KEY Key, DWORD cbData, BYTE* ppbData, PPST_PROMPTIFO pPromptInfo, DWORD dwDefaultConfirmationStyle, DWORD dwFlags) { - FIXME("%p %08x %s %s %s %d %p %p %08x\n", This, Key, - debugstr_guid(pItemType), debugstr_guid(pItemSubtype), - debugstr_w(szItemName), cbData, ppbData, pPromptInfo, dwFlags); - return E_NOTIMPL; + LONG r; + HKEY hkey, hkeysubtype; + WCHAR szGuid[80]; + + TRACE("%p %08x %s %s %s %d %p %p %08x\n", This, Key, + debugstr_guid(pItemType), debugstr_guid(pItemSubtype), + debugstr_w(szItemName), cbData, ppbData, pPromptInfo, dwFlags); + + r = IPStore_OpenRoot( Key, &hkey ); + if( r ) + return E_FAIL; + + IPStore_guid2wstr( pItemType, szGuid ); + szGuid[38] = '\\'; + IPStore_guid2wstr( pItemSubtype, &szGuid[39] ); + r = RegOpenKeyW( hkey, szGuid, &hkeysubtype ); + if( r == ERROR_SUCCESS ) + { + r = RegSetValueExW( hkeysubtype, szItemName, 0, REG_BINARY, + ppbData, cbData ); + RegCloseKey( hkeysubtype ); + } + + RegCloseKey( hkey ); + + return ( r == ERROR_SUCCESS ) ? S_OK : E_FAIL; } /****************************************************************************** @@ -293,10 +467,37 @@ static HRESULT WINAPI PStore_fnOpenItem( IPStore* This, PST_KEY Key, const GUID* pItemType, const GUID* pItemSubtype, LPCWSTR szItemName, PST_ACCESSMODE ModeFlags, PPST_PROMPTIFO pProomptInfo, DWORD dwFlags ) { - FIXME("%p %08x %s %s %p %08x %p %08x\n", This, Key, + LONG r; + HKEY hkey, hkeysubtype; + WCHAR szGuid[80]; + + TRACE("%p %08x %s %s %p %08x %p %08x\n", This, Key, debugstr_guid(pItemType), debugstr_guid(pItemSubtype), debugstr_w(szItemName), ModeFlags, pProomptInfo, dwFlags); - return E_NOTIMPL; + + r = IPStore_OpenRoot( Key, &hkey ); + if( r ) + return E_FAIL; + + IPStore_guid2wstr( pItemType, szGuid ); + szGuid[38] = '\\'; + IPStore_guid2wstr( pItemSubtype, &szGuid[39] ); + r = RegOpenKeyW( hkey, szGuid, &hkeysubtype ); + if( r == ERROR_SUCCESS ) + { + DWORD type; + + r = RegQueryValueExW( hkeysubtype, szItemName, NULL, &type, + NULL, NULL ); + if( ( r == ERROR_SUCCESS ) && ( type != REG_BINARY ) ) + r = ERROR_INVALID_DATA; + + RegCloseKey( hkeysubtype ); + } + + RegCloseKey( hkey ); + + return ( r == ERROR_SUCCESS ) ? S_OK : E_FAIL; } /****************************************************************************** @@ -306,8 +507,8 @@ static HRESULT WINAPI PStore_fnCloseItem( IPStore* This, PST_KEY Key, const GUID* pItemType, const GUID* pItemSubtype, LPCWSTR* szItemName, DWORD dwFlags) { - FIXME("\n"); - return E_NOTIMPL; + TRACE("\n"); + return S_OK; } /****************************************************************************** @@ -318,7 +519,7 @@ static HRESULT WINAPI PStore_fnEnumItems( IPStore* This, PST_KEY Key, IEnumPStoreItems** ppenum) { FIXME("\n"); - return E_NOTIMPL; + return E_FAIL; } @@ -369,13 +570,13 @@ HRESULT WINAPI PStoreCreateInstance( IPStore** ppProvider, HRESULT WINAPI DllRegisterServer(void) { - FIXME("\n"); + FIXME("stub\n"); return S_OK; } HRESULT WINAPI DllUnregisterServer(void) { - FIXME("\n"); + FIXME("stub\n"); return S_OK; } @@ -384,12 +585,11 @@ HRESULT WINAPI DllUnregisterServer(void) */ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv) { - FIXME("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(iid), ppv); + FIXME("(%s,%s,%p) stub\n", debugstr_guid(rclsid), debugstr_guid(iid), ppv); return CLASS_E_CLASSNOTAVAILABLE; } HRESULT WINAPI DllCanUnloadNow(void) { - FIXME("\n"); - return S_OK; + return S_FALSE; } diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c index 2e2c54911d8..83541f25599 100644 --- a/dlls/riched20/editor.c +++ b/dlls/riched20/editor.c @@ -66,7 +66,7 @@ + EM_GETSELTEXT (ANSI&Unicode) + EM_GETSCROLLPOS 3.0 (only Y value valid) ! - EM_GETTHUMB - - EM_GETTEXTEX 2.0 + + EM_GETTEXTEX 2.0 + EM_GETTEXTLENGTHEX (GTL_PRECISE unimplemented) - EM_GETTEXTMODE 2.0 ? + EM_GETTEXTRANGE (ANSI&Unicode) @@ -114,7 +114,7 @@ + EM_SETSCROLLPOS 3.0 - EM_SETTABSTOPS 3.0 - EM_SETTARGETDEVICE - + EM_SETTEXTEX 3.0 (unicode only, no rich text insertion handling, proper style?) + + EM_SETTEXTEX 3.0 (no rich text insertion handling, proper style?) - EM_SETTEXTMODE 2.0 - EM_SETTYPOGRAPHYOPTIONS 3.0 + EM_SETUNDOLIMIT 2.0 @@ -1635,17 +1635,23 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam, } case EM_SETTEXTEX: { - LPWSTR wszText = (LPWSTR)lParam; + LPWSTR wszText; SETTEXTEX *pStruct = (SETTEXTEX *)wParam; - size_t len = wszText ? lstrlenW(wszText) : 0; + size_t len; int from, to; ME_Style *style; int oldModify = editor->nModifyStep; - TRACE("EM_SETTEXTEX - %s, flags %d, cp %d\n", debugstr_w(wszText), (int)pStruct->flags, pStruct->codepage); - if (pStruct->codepage != 1200) { - FIXME("EM_SETTEXTEX only supports unicode right now!\n"); - return 0; - } + + if (!pStruct) return 0; + + TRACE("EM_SETTEXTEX - %s, flags %d, cp %d\n", + pStruct->codepage == 1200 ? debugstr_w((LPCWSTR)lParam) : debugstr_a((LPCSTR)lParam), + pStruct->flags, pStruct->codepage); + + /* FIXME: make use of pStruct->codepage in the to unicode translation */ + wszText = lParam ? ME_ToUnicode(pStruct->codepage == 1200, (void *)lParam) : NULL; + len = wszText ? lstrlenW(wszText) : 0; + /* FIXME: this should support RTF strings too, according to MSDN */ if (pStruct->flags & ST_SELECTION) { ME_GetSelection(editor, &from, &to); @@ -2001,7 +2007,7 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam, nStart = 0; nCount = ex->cb - 1; } - if (ex->codepage == 1200 || unicode) + if (ex->codepage == 1200) { nCount = min(nCount, ex->cb / sizeof(WCHAR) - 1); return ME_GetTextW(editor, (LPWSTR)lParam, nStart, nCount, ex->flags & GT_USECRLF); @@ -2018,6 +2024,7 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam, buflen = ME_GetTextW(editor, buffer, nStart, nCount, ex->flags & GT_USECRLF); rc = WideCharToMultiByte(ex->codepage, flags, buffer, -1, (LPSTR)lParam, ex->cb, ex->lpDefaultChar, ex->lpUsedDefaultChar); + if (rc) rc--; /* do not count 0 terminator */ richedit_free(buffer); return rc; diff --git a/dlls/riched20/string.c b/dlls/riched20/string.c index 4c4491158d5..2f60810ce54 100644 --- a/dlls/riched20/string.c +++ b/dlls/riched20/string.c @@ -347,6 +347,8 @@ ME_CallWordBreakProc(ME_TextEditor *editor, ME_String *str, INT start, INT code) LPWSTR ME_ToUnicode(BOOL unicode, LPVOID psz) { + assert(psz != NULL); + if (unicode) return (LPWSTR)psz; else { diff --git a/dlls/riched20/tests/editor.c b/dlls/riched20/tests/editor.c index 4f95bfe703a..d1a1fac2267 100644 --- a/dlls/riched20/tests/editor.c +++ b/dlls/riched20/tests/editor.c @@ -3,6 +3,7 @@ * * Copyright 2006 Google (Thomas Kho) * Copyright 2007 Matt Finnicum +* Copyright 2007 Dmitry Timoshkov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,11 +20,16 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include -#include +#include static HMODULE hmoduleRichEdit; @@ -1576,43 +1582,82 @@ static void test_EM_StreamIn_Undo(void) } +static BOOL is_em_settextex_supported(HWND hwnd) +{ + SETTEXTEX stex = { ST_DEFAULT, CP_ACP }; + return SendMessageA(hwnd, EM_SETTEXTEX, (WPARAM)&stex, 0) != 0; +} + static void test_unicode_conversions(void) { + static const WCHAR tW[] = {'t',0}; + static const WCHAR teW[] = {'t','e',0}; static const WCHAR textW[] = {'t','e','s','t',0}; static const char textA[] = "test"; char bufA[64]; WCHAR bufW[64]; HWND hwnd; - int is_win9x, ret; + int is_win9x, em_settextex_supported, ret; is_win9x = GetVersion() & 0x80000000; -#define set_textA(hwnd, txt) \ +#define set_textA(hwnd, wm_set_text, txt) \ do { \ - ret = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)txt); \ - ok(ret, "SendMessageA(WM_SETTEXT) error %u\n", GetLastError()); \ + SETTEXTEX stex = { ST_DEFAULT, CP_ACP }; \ + WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \ + assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \ + ret = SendMessageA(hwnd, wm_set_text, wparam, (LPARAM)txt); \ + ok(ret, "SendMessageA(%02x) error %u\n", wm_set_text, GetLastError()); \ } while(0) -#define expect_textA(hwnd, txt) \ +#define expect_textA(hwnd, wm_get_text, txt) \ do { \ + GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \ + WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \ + assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \ memset(bufA, 0xAA, sizeof(bufA)); \ - ret = SendMessageA(hwnd, WM_GETTEXT, 64, (LPARAM)bufA); \ - ok(ret, "SendMessageA(WM_GETTEXT) error %u\n", GetLastError()); \ + ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \ + ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \ ret = lstrcmpA(bufA, txt); \ - ok(!ret, "strings not match: expected %s got %s\n", txt, bufA); \ + ok(!ret, "%02x: strings do not match: expected %s got %s\n", wm_get_text, txt, bufA); \ } while(0) -#define set_textW(hwnd, txt) \ +#define set_textW(hwnd, wm_set_text, txt) \ do { \ - ret = SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)txt); \ - ok(ret, "SendMessageW(WM_SETTEXT) error %u\n", GetLastError()); \ + SETTEXTEX stex = { ST_DEFAULT, 1200 }; \ + WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \ + assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \ + ret = SendMessageW(hwnd, wm_set_text, wparam, (LPARAM)txt); \ + ok(ret, "SendMessageW(%02x) error %u\n", wm_set_text, GetLastError()); \ } while(0) -#define expect_textW(hwnd, txt) \ +#define expect_textW(hwnd, wm_get_text, txt) \ do { \ + GETTEXTEX gtex = { 64, GT_DEFAULT, 1200, NULL, NULL }; \ + WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \ + assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \ memset(bufW, 0xAA, sizeof(bufW)); \ - ret = SendMessageW(hwnd, WM_GETTEXT, 64, (LPARAM)bufW); \ - ok(ret, "SendMessageW(WM_GETTEXT) error %u\n", GetLastError()); \ + if (is_win9x) \ + { \ + assert(wm_get_text == EM_GETTEXTEX); \ + ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufW); \ + ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \ + } \ + else \ + { \ + ret = SendMessageW(hwnd, wm_get_text, wparam, (LPARAM)bufW); \ + ok(ret, "SendMessageW(%02x) error %u\n", wm_get_text, GetLastError()); \ + } \ ret = lstrcmpW(bufW, txt); \ - ok(!ret, "strings not match expected[0] %x got[0] %x\n", txt[0], bufW[0]); \ + ok(!ret, "%02x: strings do not match: expected[0] %x got[0] %x\n", wm_get_text, txt[0], bufW[0]); \ + } while(0) +#define expect_empty(hwnd, wm_get_text) \ + do { \ + GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \ + WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \ + assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \ + memset(bufA, 0xAA, sizeof(bufA)); \ + ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \ + ok(!ret, "empty richedit should return 0, got %d\n", ret); \ + ok(!*bufA, "empty richedit should return empty string, got %s\n", bufA); \ } while(0) hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP, @@ -1625,35 +1670,62 @@ static void test_unicode_conversions(void) else ok(ret, "RichEdit20W should be unicode under NT\n"); - memset(bufA, 0xAA, sizeof(bufA)); - ret = SendMessageA(hwnd, WM_GETTEXT, 64, (LPARAM)bufA); - ok(!ret, "empty richedit should return 0, got %d\n", ret); - ok(!*bufA, "empty richedit should return empty string, got %s\n", bufA); + /* EM_SETTEXTEX is supported starting from version 3.0 */ + em_settextex_supported = is_em_settextex_supported(hwnd); + trace("EM_SETTEXTEX is %ssupported on this platform\n", + em_settextex_supported ? "" : "NOT "); + + expect_empty(hwnd, WM_GETTEXT); + expect_empty(hwnd, EM_GETTEXTEX); ret = SendMessageA(hwnd, WM_CHAR, (WPARAM)textW[0], 0); ok(!ret, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret); - expect_textA(hwnd, "t"); + expect_textA(hwnd, WM_GETTEXT, "t"); + expect_textA(hwnd, EM_GETTEXTEX, "t"); + expect_textW(hwnd, EM_GETTEXTEX, tW); ret = SendMessageA(hwnd, WM_CHAR, (WPARAM)textA[1], 0); ok(!ret, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret); - expect_textA(hwnd, "te"); + expect_textA(hwnd, WM_GETTEXT, "te"); + expect_textA(hwnd, EM_GETTEXTEX, "te"); + expect_textW(hwnd, EM_GETTEXTEX, teW); - set_textA(hwnd, NULL); - memset(bufA, 0xAA, sizeof(bufA)); - ret = SendMessageA(hwnd, WM_GETTEXT, 64, (LPARAM)bufA); - ok(!ret, "empty richedit should return 0, got %d\n", ret); - ok(!*bufA, "empty richedit should return empty string, got %s\n", bufA); + set_textA(hwnd, WM_SETTEXT, NULL); + expect_empty(hwnd, WM_GETTEXT); + expect_empty(hwnd, EM_GETTEXTEX); if (is_win9x) - set_textA(hwnd, textW); + set_textA(hwnd, WM_SETTEXT, textW); else - set_textA(hwnd, textA); - expect_textA(hwnd, textA); + set_textA(hwnd, WM_SETTEXT, textA); + expect_textA(hwnd, WM_GETTEXT, textA); + expect_textA(hwnd, EM_GETTEXTEX, textA); + expect_textW(hwnd, EM_GETTEXTEX, textW); + + if (em_settextex_supported) + { + set_textA(hwnd, EM_SETTEXTEX, textA); + expect_textA(hwnd, WM_GETTEXT, textA); + expect_textA(hwnd, EM_GETTEXTEX, textA); + expect_textW(hwnd, EM_GETTEXTEX, textW); + } if (!is_win9x) { - set_textW(hwnd, textW); - expect_textW(hwnd, textW); + set_textW(hwnd, WM_SETTEXT, textW); + expect_textW(hwnd, WM_GETTEXT, textW); + expect_textA(hwnd, WM_GETTEXT, textA); + expect_textW(hwnd, EM_GETTEXTEX, textW); + expect_textA(hwnd, EM_GETTEXTEX, textA); + + if (em_settextex_supported) + { + set_textW(hwnd, EM_SETTEXTEX, textW); + expect_textW(hwnd, WM_GETTEXT, textW); + expect_textA(hwnd, WM_GETTEXT, textA); + expect_textW(hwnd, EM_GETTEXTEX, textW); + expect_textA(hwnd, EM_GETTEXTEX, textA); + } } DestroyWindow(hwnd); @@ -1664,13 +1736,35 @@ static void test_unicode_conversions(void) ret = IsWindowUnicode(hwnd); ok(!ret, "RichEdit20A should NOT be unicode\n"); - set_textA(hwnd, textA); - expect_textA(hwnd, textA); + set_textA(hwnd, WM_SETTEXT, textA); + expect_textA(hwnd, WM_GETTEXT, textA); + expect_textA(hwnd, EM_GETTEXTEX, textA); + expect_textW(hwnd, EM_GETTEXTEX, textW); + + if (em_settextex_supported) + { + set_textA(hwnd, EM_SETTEXTEX, textA); + expect_textA(hwnd, WM_GETTEXT, textA); + expect_textA(hwnd, EM_GETTEXTEX, textA); + expect_textW(hwnd, EM_GETTEXTEX, textW); + } if (!is_win9x) { - set_textW(hwnd, textW); - expect_textW(hwnd, textW); + set_textW(hwnd, WM_SETTEXT, textW); + expect_textW(hwnd, WM_GETTEXT, textW); + expect_textA(hwnd, WM_GETTEXT, textA); + expect_textW(hwnd, EM_GETTEXTEX, textW); + expect_textA(hwnd, EM_GETTEXTEX, textA); + + if (em_settextex_supported) + { + set_textW(hwnd, EM_SETTEXTEX, textW); + expect_textW(hwnd, WM_GETTEXT, textW); + expect_textA(hwnd, WM_GETTEXT, textA); + expect_textW(hwnd, EM_GETTEXTEX, textW); + expect_textA(hwnd, EM_GETTEXTEX, textA); + } } DestroyWindow(hwnd); } diff --git a/dlls/riched20/txtsrv.c b/dlls/riched20/txtsrv.c index 069c916534e..66e2d31be11 100644 --- a/dlls/riched20/txtsrv.c +++ b/dlls/riched20/txtsrv.c @@ -71,6 +71,10 @@ HRESULT WINAPI CreateTextServices(IUnknown * pUnkOuter, { ITextServicesImpl *ITextImpl; TRACE("%p %p --> %p\n", pUnkOuter, pITextHost, ppUnk); + + FIXME("Our implementation of text services is just a bunch of stubs, return E_NOTIMPL for now - this differs from WineHQ\n"); + return E_NOTIMPL; + if (pITextHost == NULL) return E_POINTER; diff --git a/dlls/rpcrt4/Makefile.in b/dlls/rpcrt4/Makefile.in index 847e88eeff6..0193fe9f31c 100644 --- a/dlls/rpcrt4/Makefile.in +++ b/dlls/rpcrt4/Makefile.in @@ -6,13 +6,14 @@ VPATH = @srcdir@ MODULE = rpcrt4.dll IMPORTLIB = librpcrt4.$(IMPLIBEXT) IMPORTS = iphlpapi advapi32 kernel32 ntdll -DELAYIMPORTS = secur32 +DELAYIMPORTS = wininet secur32 EXTRALIBS = -luuid C_SRCS = \ cproxy.c \ cpsf.c \ cstub.c \ + epm_c.c \ ndr_clientserver.c \ ndr_fullpointer.c \ ndr_marshall.c \ @@ -28,6 +29,10 @@ C_SRCS = \ RC_SRCS = version.rc +IDL_H_SRCS = \ + dcetypes.idl \ + epm.idl + @MAKE_DLL_RULES@ @DEPENDENCIES@ # everything below this line is overwritten by make depend diff --git a/dlls/rpcrt4/epm_towers.h b/dlls/rpcrt4/epm_towers.h index 7570cc2e846..3a7cbb0a071 100644 --- a/dlls/rpcrt4/epm_towers.h +++ b/dlls/rpcrt4/epm_towers.h @@ -19,6 +19,16 @@ * */ +#include "dcetypes.h" + +RPC_STATUS WINAPI TowerExplode( + const twr_t *tower, RPC_SYNTAX_IDENTIFIER *object, RPC_SYNTAX_IDENTIFIER *syntax, + char **protseq, char **endpoint, char **address); +RPC_STATUS WINAPI TowerConstruct( + const RPC_SYNTAX_IDENTIFIER *object, const RPC_SYNTAX_IDENTIFIER *syntax, + const char *protseq, const char *endpoint, const char *address, + twr_t **tower); + #define EPM_PROTOCOL_DNET_NSP 0x04 #define EPM_PROTOCOL_OSI_TP4 0x05 #define EPM_PROTOCOL_OSI_CLNS 0x06 @@ -48,10 +58,6 @@ #include -typedef unsigned char u_int8; -typedef unsigned short u_int16; -typedef unsigned int u_int32; - typedef struct { u_int16 count_lhs; diff --git a/dlls/rpcrt4/ndr_marshall.c b/dlls/rpcrt4/ndr_marshall.c index ad95b53abe2..d7c5b131221 100644 --- a/dlls/rpcrt4/ndr_marshall.c +++ b/dlls/rpcrt4/ndr_marshall.c @@ -119,6 +119,10 @@ static void WINAPI NdrBaseTypeBufferSize(PMIDL_STUB_MESSAGE, unsigned char *, PF static void WINAPI NdrBaseTypeFree(PMIDL_STUB_MESSAGE, unsigned char *, PFORMAT_STRING); static ULONG WINAPI NdrBaseTypeMemorySize(PMIDL_STUB_MESSAGE, PFORMAT_STRING); +static unsigned char *WINAPI NdrContextHandleMarshall(PMIDL_STUB_MESSAGE, unsigned char *, PFORMAT_STRING); +static void WINAPI NdrContextHandleBufferSize(PMIDL_STUB_MESSAGE, unsigned char *, PFORMAT_STRING); +static unsigned char *WINAPI NdrContextHandleUnmarshall(PMIDL_STUB_MESSAGE, unsigned char **, PFORMAT_STRING, unsigned char); + const NDR_MARSHALL NdrMarshaller[NDR_TABLE_SIZE] = { 0, NdrBaseTypeMarshall, NdrBaseTypeMarshall, NdrBaseTypeMarshall, @@ -152,9 +156,13 @@ const NDR_MARSHALL NdrMarshaller[NDR_TABLE_SIZE] = { NdrXmitOrRepAsMarshall, NdrXmitOrRepAsMarshall, /* 0x2f */ NdrInterfacePointerMarshall, - /* 0xb0 */ - 0, 0, 0, 0, - NdrUserMarshalMarshall + /* 0x30 */ + NdrContextHandleMarshall, + /* 0xb1 */ + 0, 0, 0, + NdrUserMarshalMarshall, + 0, 0, + NdrRangeMarshall }; const NDR_UNMARSHALL NdrUnmarshaller[NDR_TABLE_SIZE] = { 0, @@ -189,9 +197,13 @@ const NDR_UNMARSHALL NdrUnmarshaller[NDR_TABLE_SIZE] = { NdrXmitOrRepAsUnmarshall, NdrXmitOrRepAsUnmarshall, /* 0x2f */ NdrInterfacePointerUnmarshall, - /* 0xb0 */ - 0, 0, 0, 0, - NdrUserMarshalUnmarshall + /* 0x30 */ + NdrContextHandleUnmarshall, + /* 0xb1 */ + 0, 0, 0, + NdrUserMarshalUnmarshall, + 0, 0, + NdrRangeUnmarshall }; const NDR_BUFFERSIZE NdrBufferSizer[NDR_TABLE_SIZE] = { 0, @@ -226,9 +238,13 @@ const NDR_BUFFERSIZE NdrBufferSizer[NDR_TABLE_SIZE] = { NdrXmitOrRepAsBufferSize, NdrXmitOrRepAsBufferSize, /* 0x2f */ NdrInterfacePointerBufferSize, - /* 0xb0 */ - 0, 0, 0, 0, - NdrUserMarshalBufferSize + /* 0x30 */ + NdrContextHandleBufferSize, + /* 0xb1 */ + 0, 0, 0, + NdrUserMarshalBufferSize, + 0, 0, + NdrRangeBufferSize }; const NDR_MEMORYSIZE NdrMemorySizer[NDR_TABLE_SIZE] = { 0, @@ -265,7 +281,9 @@ const NDR_MEMORYSIZE NdrMemorySizer[NDR_TABLE_SIZE] = { NdrInterfacePointerMemorySize, /* 0xb0 */ 0, 0, 0, 0, - NdrUserMarshalMemorySize + NdrUserMarshalMemorySize, + 0, 0, + NdrRangeMemorySize }; const NDR_FREE NdrFreer[NDR_TABLE_SIZE] = { 0, @@ -301,7 +319,9 @@ const NDR_FREE NdrFreer[NDR_TABLE_SIZE] = { NdrInterfacePointerFree, /* 0xb0 */ 0, 0, 0, 0, - NdrUserMarshalFree + NdrUserMarshalFree, + 0, 0, + NdrRangeFree }; void * WINAPI NdrAllocate(MIDL_STUB_MESSAGE *pStubMsg, size_t len) @@ -813,10 +833,13 @@ static void PointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, switch (type) { case RPC_FC_RP: /* ref pointer (always non-null) */ -#if 0 /* this causes problems for InstallShield so is disabled - we need more tests */ if (!Pointer) + { + ERR("NULL ref pointer is not allowed\n"); +#if 0 /* this causes problems for InstallShield so is disabled - we need more tests */ RpcRaiseException(RPC_X_NULL_REF_POINTER); #endif + } pointer_needs_marshaling = 1; break; case RPC_FC_UP: /* unique pointer */ @@ -916,6 +939,8 @@ static void PointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, return; } + STD_OVERFLOW_CHECK(pStubMsg); + if (pointer_needs_unmarshaling) { if (attr & RPC_FC_P_DEREF) { if (!*pPointer || fMustAlloc) @@ -1101,12 +1126,20 @@ static unsigned char * EmbeddedPointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, unsigned long Offset = pStubMsg->Offset; unsigned ofs, rep, count, stride, xofs; unsigned i; + unsigned char *saved_buffer = NULL; TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); if (*pFormat != RPC_FC_PP) return NULL; pFormat += 2; + if (pStubMsg->PointerBufferMark) + { + saved_buffer = pStubMsg->Buffer; + pStubMsg->Buffer = pStubMsg->PointerBufferMark; + pStubMsg->PointerBufferMark = NULL; + } + while (pFormat[0] != RPC_FC_END) { switch (pFormat[0]) { default: @@ -1155,6 +1188,12 @@ static unsigned char * EmbeddedPointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, pFormat += 8 * count; } + if (saved_buffer) + { + pStubMsg->PointerBufferMark = pStubMsg->Buffer; + pStubMsg->Buffer = saved_buffer; + } + STD_OVERFLOW_CHECK(pStubMsg); return NULL; @@ -1172,12 +1211,20 @@ static unsigned char * EmbeddedPointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, unsigned long Offset = pStubMsg->Offset; unsigned ofs, rep, count, stride, xofs; unsigned i; + unsigned char *saved_buffer = NULL; TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); if (*pFormat != RPC_FC_PP) return NULL; pFormat += 2; + if (pStubMsg->PointerBufferMark) + { + saved_buffer = pStubMsg->Buffer; + pStubMsg->Buffer = pStubMsg->PointerBufferMark; + pStubMsg->PointerBufferMark = NULL; + } + while (pFormat[0] != RPC_FC_END) { TRACE("pFormat[0] = 0x%x\n", pFormat[0]); switch (pFormat[0]) { @@ -1217,12 +1264,19 @@ static unsigned char * EmbeddedPointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, for (u=0; uPointerBufferMark = pStubMsg->Buffer; + pStubMsg->Buffer = saved_buffer; + } + return NULL; } @@ -1236,6 +1290,7 @@ static void EmbeddedPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned long Offset = pStubMsg->Offset; unsigned ofs, rep, count, stride, xofs; unsigned i; + ULONG saved_buffer_length = 0; TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); @@ -1244,6 +1299,13 @@ static void EmbeddedPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, if (*pFormat != RPC_FC_PP) return; pFormat += 2; + if (pStubMsg->PointerLength) + { + saved_buffer_length = pStubMsg->BufferLength; + pStubMsg->BufferLength = pStubMsg->PointerLength; + pStubMsg->PointerLength = 0; + } + while (pFormat[0] != RPC_FC_END) { switch (pFormat[0]) { default: @@ -1289,6 +1351,12 @@ static void EmbeddedPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, } pFormat += 8 * count; } + + if (saved_buffer_length) + { + pStubMsg->PointerLength = pStubMsg->BufferLength; + pStubMsg->BufferLength = saved_buffer_length; + } } /*********************************************************************** @@ -1302,6 +1370,10 @@ static unsigned long EmbeddedPointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, unsigned ofs, rep, count, stride, xofs; unsigned i; + TRACE("(%p,%p)\n", pStubMsg, pFormat); + + if (pStubMsg->IgnoreEmbeddedPointers) return 0; + FIXME("(%p,%p): stub\n", pStubMsg, pFormat); if (*pFormat != RPC_FC_PP) return 0; @@ -1437,6 +1509,8 @@ unsigned char * WINAPI NdrPointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, else Buffer = pStubMsg->Buffer; + STD_OVERFLOW_CHECK(pStubMsg); + PointerMarshall(pStubMsg, Buffer, pMemory, pFormat); STD_OVERFLOW_CHECK(pStubMsg); @@ -1456,6 +1530,8 @@ unsigned char * WINAPI NdrPointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + STD_OVERFLOW_CHECK(pStubMsg); + /* incremement the buffer here instead of in PointerUnmarshall, * as that is used by embedded pointers which already handle the incrementing * the buffer, and shouldn't read any additional pointer data from the @@ -1469,6 +1545,8 @@ unsigned char * WINAPI NdrPointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, else Buffer = pStubMsg->Buffer; + STD_OVERFLOW_CHECK(pStubMsg); + PointerUnmarshall(pStubMsg, Buffer, ppMemory, pFormat, fMustAlloc); return NULL; @@ -1552,6 +1630,8 @@ unsigned char * WINAPI NdrSimpleStructMarshall(PMIDL_STUB_MESSAGE pStubMsg, pStubMsg->BufferMark = pStubMsg->Buffer; pStubMsg->Buffer += size; + STD_OVERFLOW_CHECK(pStubMsg); + if (pFormat[0] != RPC_FC_STRUCT) EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat+4); @@ -1573,7 +1653,10 @@ unsigned char * WINAPI NdrSimpleStructUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, ALIGN_POINTER(pStubMsg->Buffer, pFormat[1] + 1); - if (fMustAlloc) { + /* CODEWEAVERS HACK: Huw has a test that shows this is wrong - it is likely + * that PointerMarshall has set fMustAlloc to 1 in certain circumstances, + * but I haven't worked out what they are yet */ + if (fMustAlloc || !*ppMemory) { *ppMemory = NdrAllocate(pStubMsg, size); memcpy(*ppMemory, pStubMsg->Buffer, size); } else { @@ -1656,6 +1739,13 @@ static unsigned long EmbeddedComplexSize(PMIDL_STUB_MESSAGE pStubMsg, return *(const WORD*)&pFormat[2]; case RPC_FC_USER_MARSHAL: return *(const WORD*)&pFormat[4]; + case RPC_FC_RANGE: { + unsigned long ret; + unsigned char *saved_buffer = pStubMsg->Buffer; + ret = NdrRangeMemorySize(pStubMsg, pFormat); + pStubMsg->Buffer = saved_buffer; + return ret; + } case RPC_FC_NON_ENCAPSULATED_UNION: pFormat += 2; if (pStubMsg->fHasNewCorrDesc) @@ -1732,11 +1822,30 @@ static unsigned char * ComplexMarshall(PMIDL_STUB_MESSAGE pStubMsg, pMemory += 8; break; case RPC_FC_POINTER: + { + unsigned char *saved_buffer; + int pointer_buffer_mark_set = 0; TRACE("pointer=%p <= %p\n", *(unsigned char**)pMemory, pMemory); - NdrPointerMarshall(pStubMsg, *(unsigned char**)pMemory, pPointer); + saved_buffer = pStubMsg->Buffer; + if (pStubMsg->PointerBufferMark) + { + pStubMsg->Buffer = pStubMsg->PointerBufferMark; + pStubMsg->PointerBufferMark = NULL; + pointer_buffer_mark_set = 1; + } + else + pStubMsg->Buffer += 4; /* for pointer ID */ + PointerMarshall(pStubMsg, saved_buffer, *(unsigned char**)pMemory, pPointer); + if (pointer_buffer_mark_set) + { + STD_OVERFLOW_CHECK(pStubMsg); + pStubMsg->PointerBufferMark = pStubMsg->Buffer; + pStubMsg->Buffer = saved_buffer + 4; + } pPointer += 4; pMemory += 4; break; + } case RPC_FC_ALIGNM4: ALIGN_POINTER(pMemory, 4); break; @@ -1759,7 +1868,17 @@ static unsigned char * ComplexMarshall(PMIDL_STUB_MESSAGE pStubMsg, 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); + if (m) + { + /* for some reason interface pointers aren't generated as + * RPC_FC_POINTER, but instead as RPC_FC_EMBEDDED_COMPLEX, yet + * they still need the derefencing treatment that pointers are + * given */ + if (*desc == RPC_FC_IP) + m(pStubMsg, *(unsigned char **)pMemory, desc); + else + m(pStubMsg, pMemory, desc); + } else FIXME("no marshaller for embedded type %02x\n", *desc); pMemory += size; pFormat += 2; @@ -1818,11 +1937,33 @@ static unsigned char * ComplexUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, pMemory += 8; break; case RPC_FC_POINTER: + { + unsigned char *saved_buffer; + int pointer_buffer_mark_set = 0; + *(unsigned char**)pMemory = NULL; TRACE("pointer => %p\n", pMemory); - NdrPointerUnmarshall(pStubMsg, (unsigned char**)pMemory, pPointer, TRUE); + ALIGN_POINTER(pStubMsg->Buffer, 4); + saved_buffer = pStubMsg->Buffer; + if (pStubMsg->PointerBufferMark) + { + pStubMsg->Buffer = pStubMsg->PointerBufferMark; + pStubMsg->PointerBufferMark = NULL; + pointer_buffer_mark_set = 1; + } + else + pStubMsg->Buffer += 4; /* for pointer ID */ + + PointerUnmarshall(pStubMsg, saved_buffer, (unsigned char**)pMemory, pPointer, TRUE); + if (pointer_buffer_mark_set) + { + STD_OVERFLOW_CHECK(pStubMsg); + pStubMsg->PointerBufferMark = pStubMsg->Buffer; + pStubMsg->Buffer = saved_buffer + 4; + } pPointer += 4; pMemory += 4; break; + } case RPC_FC_ALIGNM4: ALIGN_POINTER(pMemory, 4); break; @@ -1846,7 +1987,17 @@ static unsigned char * ComplexUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, 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, FALSE); + if (m) + { + /* for some reason interface pointers aren't generated as + * RPC_FC_POINTER, but instead as RPC_FC_EMBEDDED_COMPLEX, yet + * they still need the derefencing treatment that pointers are + * given */ + if (*desc == RPC_FC_IP) + m(pStubMsg, (unsigned char **)pMemory, desc, FALSE); + else + m(pStubMsg, &pMemory, desc, FALSE); + } else FIXME("no unmarshaller for embedded type %02x\n", *desc); pMemory += size; pFormat += 2; @@ -1897,7 +2048,18 @@ static unsigned char * ComplexBufferSize(PMIDL_STUB_MESSAGE pStubMsg, pMemory += 8; break; case RPC_FC_POINTER: - NdrPointerBufferSize(pStubMsg, *(unsigned char**)pMemory, pPointer); + if (!pStubMsg->IgnoreEmbeddedPointers) + { + int saved_buffer_length = pStubMsg->BufferLength; + pStubMsg->BufferLength = pStubMsg->PointerLength; + pStubMsg->PointerLength = 0; + if(!pStubMsg->BufferLength) + ERR("BufferLength == 0??\n"); + PointerBufferSize(pStubMsg, *(unsigned char**)pMemory, pPointer); + pStubMsg->PointerLength = pStubMsg->BufferLength; + pStubMsg->BufferLength = saved_buffer_length; + } + pStubMsg->BufferLength += 4; pPointer += 4; pMemory += 4; break; @@ -1922,7 +2084,17 @@ static unsigned char * ComplexBufferSize(PMIDL_STUB_MESSAGE pStubMsg, desc = pFormat + *(const SHORT*)pFormat; size = EmbeddedComplexSize(pStubMsg, desc); m = NdrBufferSizer[*desc & NDR_TABLE_MASK]; - if (m) m(pStubMsg, pMemory, desc); + if (m) + { + /* for some reason interface pointers aren't generated as + * RPC_FC_POINTER, but instead as RPC_FC_EMBEDDED_COMPLEX, yet + * they still need the derefencing treatment that pointers are + * given */ + if (*desc == RPC_FC_IP) + m(pStubMsg, *(unsigned char **)pMemory, desc); + else + m(pStubMsg, pMemory, desc); + } else FIXME("no buffersizer for embedded type %02x\n", *desc); pMemory += size; pFormat += 2; @@ -1994,7 +2166,17 @@ static unsigned char * ComplexFree(PMIDL_STUB_MESSAGE pStubMsg, desc = pFormat + *(const SHORT*)pFormat; size = EmbeddedComplexSize(pStubMsg, desc); m = NdrFreer[*desc & NDR_TABLE_MASK]; - if (m) m(pStubMsg, pMemory, desc); + if (m) + { + /* for some reason interface pointers aren't generated as + * RPC_FC_POINTER, but instead as RPC_FC_EMBEDDED_COMPLEX, yet + * they still need the derefencing treatment that pointers are + * given */ + if (*desc == RPC_FC_IP) + m(pStubMsg, *(unsigned char **)pMemory, desc); + else + m(pStubMsg, pMemory, desc); + } else FIXME("no freer for embedded type %02x\n", *desc); pMemory += size; pFormat += 2; @@ -2044,6 +2226,13 @@ static unsigned long ComplexStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg, case RPC_FC_POINTER: size += 4; pStubMsg->Buffer += 4; + if (!pStubMsg->IgnoreEmbeddedPointers) +#if 0 + /* FIXME: we don't pass pPointer into this function at the moment */ + PointerMemorySize(pStubMsg, pPointer); +#else + FIXME("embedded pointers\n"); +#endif break; case RPC_FC_ALIGNM4: ALIGN_LENGTH(size, 4); @@ -2090,9 +2279,32 @@ unsigned char * WINAPI NdrComplexStructMarshall(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING conf_array = NULL; PFORMAT_STRING pointer_desc = NULL; unsigned char *OldMemory = pStubMsg->Memory; + int pointer_buffer_mark_set = 0; TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (!pStubMsg->PointerBufferMark) + { + int saved_ignore_embedded = pStubMsg->IgnoreEmbeddedPointers; + /* save buffer length */ + unsigned long saved_buffer_length = pStubMsg->BufferLength; + + /* get the buffer pointer after complex array data, but before + * pointer data */ + pStubMsg->BufferLength = pStubMsg->Buffer - pStubMsg->BufferStart; + pStubMsg->IgnoreEmbeddedPointers = 1; + NdrComplexStructBufferSize(pStubMsg, pMemory, pFormat); + pStubMsg->IgnoreEmbeddedPointers = saved_ignore_embedded; + + /* save it for use by embedded pointer code later */ + pStubMsg->PointerBufferMark = pStubMsg->BufferStart + pStubMsg->BufferLength; + TRACE("difference = 0x%x\n", pStubMsg->PointerBufferMark - pStubMsg->Buffer); + pointer_buffer_mark_set = 1; + + /* restore the original buffer length */ + pStubMsg->BufferLength = saved_buffer_length; + } + ALIGN_POINTER(pStubMsg->Buffer, pFormat[1] + 1); pFormat += 4; @@ -2110,6 +2322,12 @@ unsigned char * WINAPI NdrComplexStructMarshall(PMIDL_STUB_MESSAGE pStubMsg, pStubMsg->Memory = OldMemory; + if (pointer_buffer_mark_set) + { + pStubMsg->Buffer = pStubMsg->PointerBufferMark; + pStubMsg->PointerBufferMark = NULL; + } + STD_OVERFLOW_CHECK(pStubMsg); return NULL; @@ -2127,9 +2345,31 @@ unsigned char * WINAPI NdrComplexStructUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING conf_array = NULL; PFORMAT_STRING pointer_desc = NULL; unsigned char *pMemory; + int pointer_buffer_mark_set = 0; TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + if (!pStubMsg->PointerBufferMark) + { + int saved_ignore_embedded = pStubMsg->IgnoreEmbeddedPointers; + /* save buffer pointer */ + unsigned char *saved_buffer = pStubMsg->Buffer; + + /* get the buffer pointer after complex array data, but before + * pointer data */ + pStubMsg->IgnoreEmbeddedPointers = 1; + NdrComplexStructMemorySize(pStubMsg, pFormat); + pStubMsg->IgnoreEmbeddedPointers = saved_ignore_embedded; + + /* save it for use by embedded pointer code later */ + pStubMsg->PointerBufferMark = pStubMsg->Buffer; + TRACE("difference = 0x%lx\n", (unsigned long)(pStubMsg->PointerBufferMark - saved_buffer)); + pointer_buffer_mark_set = 1; + + /* restore the original buffer */ + pStubMsg->Buffer = saved_buffer; + } + ALIGN_POINTER(pStubMsg->Buffer, pFormat[1] + 1); if (fMustAlloc || !*ppMemory) @@ -2149,6 +2389,12 @@ unsigned char * WINAPI NdrComplexStructUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, if (conf_array) NdrConformantArrayUnmarshall(pStubMsg, &pMemory, conf_array, fMustAlloc); + if (pointer_buffer_mark_set) + { + pStubMsg->Buffer = pStubMsg->PointerBufferMark; + pStubMsg->PointerBufferMark = NULL; + } + return NULL; } @@ -2162,11 +2408,32 @@ void WINAPI NdrComplexStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING conf_array = NULL; PFORMAT_STRING pointer_desc = NULL; unsigned char *OldMemory = pStubMsg->Memory; + int pointer_length_set = 0; TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); ALIGN_LENGTH(pStubMsg->BufferLength, pFormat[1] + 1); + if(!pStubMsg->IgnoreEmbeddedPointers && !pStubMsg->PointerLength) + { + int saved_ignore_embedded = pStubMsg->IgnoreEmbeddedPointers; + unsigned long saved_buffer_length = pStubMsg->BufferLength; + + /* get the buffer length after complex struct data, but before + * pointer data */ + pStubMsg->IgnoreEmbeddedPointers = 1; + NdrComplexStructBufferSize(pStubMsg, pMemory, pFormat); + pStubMsg->IgnoreEmbeddedPointers = saved_ignore_embedded; + + /* save it for use by embedded pointer code later */ + pStubMsg->PointerLength = pStubMsg->BufferLength; + pointer_length_set = 1; + TRACE("difference = 0x%lx\n", pStubMsg->PointerLength - saved_buffer_length); + + /* restore the original buffer length */ + pStubMsg->BufferLength = saved_buffer_length; + } + pFormat += 4; if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat; pFormat += 2; @@ -2181,6 +2448,13 @@ void WINAPI NdrComplexStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, NdrConformantArrayBufferSize(pStubMsg, pMemory, conf_array); pStubMsg->Memory = OldMemory; + + if(pointer_length_set) + { + pStubMsg->BufferLength = pStubMsg->PointerLength; + pStubMsg->PointerLength = 0; + } + } /*********************************************************************** @@ -2531,6 +2805,7 @@ unsigned char * WINAPI NdrComplexArrayMarshall(PMIDL_STUB_MESSAGE pStubMsg, ULONG i, count, def; BOOL variance_present; unsigned char alignment; + int pointer_buffer_mark_set = 0; TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); @@ -2543,6 +2818,35 @@ unsigned char * WINAPI NdrComplexArrayMarshall(PMIDL_STUB_MESSAGE pStubMsg, alignment = pFormat[1] + 1; + if (!pStubMsg->PointerBufferMark) + { + /* save buffer fields that may be changed by buffer sizer functions + * and that may be needed later on */ + int saved_ignore_embedded = pStubMsg->IgnoreEmbeddedPointers; + unsigned long saved_buffer_length = pStubMsg->BufferLength; + unsigned long saved_max_count = pStubMsg->MaxCount; + unsigned long saved_offset = pStubMsg->Offset; + unsigned long saved_actual_count = pStubMsg->ActualCount; + + /* get the buffer pointer after complex array data, but before + * pointer data */ + pStubMsg->BufferLength = pStubMsg->Buffer - pStubMsg->BufferStart; + pStubMsg->IgnoreEmbeddedPointers = 1; + NdrComplexArrayBufferSize(pStubMsg, pMemory, pFormat); + pStubMsg->IgnoreEmbeddedPointers = saved_ignore_embedded; + + /* save it for use by embedded pointer code later */ + pStubMsg->PointerBufferMark = pStubMsg->BufferStart + pStubMsg->BufferLength; + TRACE("difference = 0x%x\n", pStubMsg->Buffer - pStubMsg->BufferStart); + pointer_buffer_mark_set = 1; + + /* restore fields */ + pStubMsg->ActualCount = saved_actual_count; + pStubMsg->Offset = saved_offset; + pStubMsg->MaxCount = saved_max_count; + pStubMsg->BufferLength = saved_buffer_length; + } + def = *(const WORD*)&pFormat[2]; pFormat += 4; @@ -2565,6 +2869,12 @@ unsigned char * WINAPI NdrComplexArrayMarshall(PMIDL_STUB_MESSAGE pStubMsg, STD_OVERFLOW_CHECK(pStubMsg); + if (pointer_buffer_mark_set) + { + pStubMsg->Buffer = pStubMsg->PointerBufferMark; + pStubMsg->PointerBufferMark = NULL; + } + return NULL; } @@ -2576,10 +2886,12 @@ unsigned char * WINAPI NdrComplexArrayUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat, unsigned char fMustAlloc) { - ULONG i, count, esize, memsize; + ULONG i, count, size; unsigned char alignment; unsigned char *pMemory; - unsigned char *Buffer; + unsigned char *saved_buffer; + int pointer_buffer_mark_set = 0; + int saved_ignore_embedded; TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); @@ -2592,22 +2904,36 @@ unsigned char * WINAPI NdrComplexArrayUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, alignment = pFormat[1] + 1; + saved_ignore_embedded = pStubMsg->IgnoreEmbeddedPointers; + /* save buffer pointer */ + saved_buffer = pStubMsg->Buffer; + /* get the buffer pointer after complex array data, but before + * pointer data */ + pStubMsg->IgnoreEmbeddedPointers = 1; + pStubMsg->MemorySize = 0; + NdrComplexArrayMemorySize(pStubMsg, pFormat); + size = pStubMsg->MemorySize; + pStubMsg->IgnoreEmbeddedPointers = saved_ignore_embedded; + + TRACE("difference = 0x%lx\n", (unsigned long)(pStubMsg->Buffer - saved_buffer)); + if (!pStubMsg->PointerBufferMark) + { + /* save it for use by embedded pointer code later */ + pStubMsg->PointerBufferMark = pStubMsg->Buffer; + pointer_buffer_mark_set = 1; + } + /* restore the original buffer */ + pStubMsg->Buffer = saved_buffer; + pFormat += 4; pFormat = ReadConformance(pStubMsg, pFormat); pFormat = ReadVariance(pStubMsg, pFormat, pStubMsg->MaxCount); - Buffer = pStubMsg->Buffer; - pStubMsg->MemorySize = 0; - esize = ComplexStructMemorySize(pStubMsg, pFormat); - pStubMsg->Buffer = Buffer; - - /* do multiply here instead of inside if block to verify MaxCount */ - memsize = safe_multiply(esize, pStubMsg->MaxCount); if (fMustAlloc || !*ppMemory) { - *ppMemory = NdrAllocate(pStubMsg, memsize); - memset(*ppMemory, 0, memsize); + *ppMemory = NdrAllocate(pStubMsg, size); + memset(*ppMemory, 0, size); } ALIGN_POINTER(pStubMsg->Buffer, alignment); @@ -2617,6 +2943,12 @@ unsigned char * WINAPI NdrComplexArrayUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, for (i = 0; i < count; i++) pMemory = ComplexUnmarshall(pStubMsg, pMemory, pFormat, NULL); + if (pointer_buffer_mark_set) + { + pStubMsg->Buffer = pStubMsg->PointerBufferMark; + pStubMsg->PointerBufferMark = NULL; + } + return NULL; } @@ -2630,6 +2962,7 @@ void WINAPI NdrComplexArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, ULONG i, count, def; unsigned char alignment; BOOL variance_present; + int pointer_length_set = 0; TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); @@ -2642,6 +2975,32 @@ void WINAPI NdrComplexArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, alignment = pFormat[1] + 1; + if (!pStubMsg->IgnoreEmbeddedPointers && !pStubMsg->PointerLength) + { + /* save buffer fields that may be changed by buffer sizer functions + * and that may be needed later on */ + int saved_ignore_embedded = pStubMsg->IgnoreEmbeddedPointers; + unsigned long saved_buffer_length = pStubMsg->BufferLength; + unsigned long saved_max_count = pStubMsg->MaxCount; + unsigned long saved_offset = pStubMsg->Offset; + unsigned long saved_actual_count = pStubMsg->ActualCount; + + /* get the buffer pointer after complex array data, but before + * pointer data */ + pStubMsg->IgnoreEmbeddedPointers = 1; + NdrComplexArrayBufferSize(pStubMsg, pMemory, pFormat); + pStubMsg->IgnoreEmbeddedPointers = saved_ignore_embedded; + + /* save it for use by embedded pointer code later */ + pStubMsg->PointerLength = pStubMsg->BufferLength; + pointer_length_set = 1; + + /* restore fields */ + pStubMsg->ActualCount = saved_actual_count; + pStubMsg->Offset = saved_offset; + pStubMsg->MaxCount = saved_max_count; + pStubMsg->BufferLength = saved_buffer_length; + } def = *(const WORD*)&pFormat[2]; pFormat += 4; @@ -2661,6 +3020,12 @@ void WINAPI NdrComplexArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, count = pStubMsg->ActualCount; for (i = 0; i < count; i++) pMemory = ComplexBufferSize(pStubMsg, pMemory, pFormat, NULL); + + if(pointer_length_set) + { + pStubMsg->BufferLength = pStubMsg->PointerLength; + pStubMsg->PointerLength = 0; + } } /*********************************************************************** @@ -2694,11 +3059,10 @@ ULONG WINAPI NdrComplexArrayMemorySize(PMIDL_STUB_MESSAGE pStubMsg, SavedMemorySize = pStubMsg->MemorySize; Buffer = pStubMsg->Buffer; - pStubMsg->MemorySize = 0; esize = ComplexStructMemorySize(pStubMsg, pFormat); pStubMsg->Buffer = Buffer; - MemorySize = safe_multiply(pStubMsg->MaxCount, esize); + MemorySize = esize * pStubMsg->MaxCount; count = pStubMsg->ActualCount; for (i = 0; i < count; i++) @@ -2761,6 +3125,7 @@ unsigned char * WINAPI NdrUserMarshalMarshall(PMIDL_STUB_MESSAGE pStubMsg, { unsigned flags = pFormat[1]; unsigned index = *(const WORD*)&pFormat[2]; + unsigned char *saved_buffer = NULL; ULONG uflag = UserMarshalFlags(pStubMsg); TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); TRACE("index=%d\n", index); @@ -2770,6 +3135,12 @@ unsigned char * WINAPI NdrUserMarshalMarshall(PMIDL_STUB_MESSAGE pStubMsg, ALIGN_POINTER(pStubMsg->Buffer, 4); NDR_LOCAL_UINT32_WRITE(pStubMsg->Buffer, USER_MARSHAL_PTR_PREFIX); pStubMsg->Buffer += 4; + if (pStubMsg->PointerBufferMark) + { + saved_buffer = pStubMsg->Buffer; + pStubMsg->Buffer = pStubMsg->PointerBufferMark; + pStubMsg->PointerBufferMark = NULL; + } ALIGN_POINTER(pStubMsg->Buffer, 8); } else @@ -2779,6 +3150,13 @@ unsigned char * WINAPI NdrUserMarshalMarshall(PMIDL_STUB_MESSAGE pStubMsg, pStubMsg->StubDesc->aUserMarshalQuadruple[index].pfnMarshall( &uflag, pStubMsg->Buffer, pMemory); + if (saved_buffer) + { + STD_OVERFLOW_CHECK(pStubMsg); + pStubMsg->PointerBufferMark = pStubMsg->Buffer; + pStubMsg->Buffer = saved_buffer; + } + STD_OVERFLOW_CHECK(pStubMsg); return NULL; @@ -2795,6 +3173,7 @@ unsigned char * WINAPI NdrUserMarshalUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, unsigned flags = pFormat[1]; unsigned index = *(const WORD*)&pFormat[2]; DWORD memsize = *(const WORD*)&pFormat[4]; + unsigned char *saved_buffer = NULL; ULONG uflag = UserMarshalFlags(pStubMsg); TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); TRACE("index=%d\n", index); @@ -2804,6 +3183,12 @@ unsigned char * WINAPI NdrUserMarshalUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, ALIGN_POINTER(pStubMsg->Buffer, 4); /* skip pointer prefix */ pStubMsg->Buffer += 4; + if (pStubMsg->PointerBufferMark) + { + saved_buffer = pStubMsg->Buffer; + pStubMsg->Buffer = pStubMsg->PointerBufferMark; + pStubMsg->PointerBufferMark = NULL; + } ALIGN_POINTER(pStubMsg->Buffer, 8); } else @@ -2816,6 +3201,13 @@ unsigned char * WINAPI NdrUserMarshalUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, pStubMsg->StubDesc->aUserMarshalQuadruple[index].pfnUnmarshall( &uflag, pStubMsg->Buffer, *ppMemory); + if (saved_buffer) + { + STD_OVERFLOW_CHECK(pStubMsg); + pStubMsg->PointerBufferMark = pStubMsg->Buffer; + pStubMsg->Buffer = saved_buffer; + } + return NULL; } @@ -2830,6 +3222,7 @@ void WINAPI NdrUserMarshalBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned index = *(const WORD*)&pFormat[2]; DWORD bufsize = *(const WORD*)&pFormat[6]; ULONG uflag = UserMarshalFlags(pStubMsg); + unsigned long saved_buffer_length = 0; TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); TRACE("index=%d\n", index); @@ -2838,6 +3231,14 @@ void WINAPI NdrUserMarshalBufferSize(PMIDL_STUB_MESSAGE pStubMsg, ALIGN_LENGTH(pStubMsg->BufferLength, 4); /* skip pointer prefix */ pStubMsg->BufferLength += 4; + if (pStubMsg->IgnoreEmbeddedPointers) + return; + if (pStubMsg->PointerLength) + { + saved_buffer_length = pStubMsg->BufferLength; + pStubMsg->BufferLength = pStubMsg->PointerLength; + pStubMsg->PointerLength = 0; + } ALIGN_LENGTH(pStubMsg->BufferLength, 8); } else @@ -2846,12 +3247,18 @@ void WINAPI NdrUserMarshalBufferSize(PMIDL_STUB_MESSAGE pStubMsg, if (bufsize) { TRACE("size=%d\n", bufsize); pStubMsg->BufferLength += bufsize; - return; + } + else + pStubMsg->BufferLength = + pStubMsg->StubDesc->aUserMarshalQuadruple[index].pfnBufferSize( + &uflag, pStubMsg->BufferLength, pMemory); + + if (saved_buffer_length) + { + pStubMsg->PointerLength = pStubMsg->BufferLength; + pStubMsg->BufferLength = saved_buffer_length; } - pStubMsg->BufferLength = - pStubMsg->StubDesc->aUserMarshalQuadruple[index].pfnBufferSize( - &uflag, pStubMsg->BufferLength, pMemory); } /*********************************************************************** @@ -2875,11 +3282,16 @@ ULONG WINAPI NdrUserMarshalMemorySize(PMIDL_STUB_MESSAGE pStubMsg, ALIGN_POINTER(pStubMsg->Buffer, 4); /* skip pointer prefix */ pStubMsg->Buffer += 4; + if (pStubMsg->IgnoreEmbeddedPointers) + return pStubMsg->MemorySize; ALIGN_POINTER(pStubMsg->Buffer, 8); } else ALIGN_POINTER(pStubMsg->Buffer, (flags & 0xf) + 1); + if (!bufsize) + FIXME("not implemented for varying buffer size\n"); + pStubMsg->Buffer += bufsize; return pStubMsg->MemorySize; @@ -4148,15 +4560,31 @@ unsigned char * WINAPI NdrNonEncapsulatedUnionMarshall(PMIDL_STUB_MESSAGE pStub if (m) { unsigned char *saved_buffer = NULL; + int pointer_buffer_mark_set = 0; switch(*desc) { case RPC_FC_RP: case RPC_FC_UP: case RPC_FC_OP: case RPC_FC_FP: + ALIGN_POINTER(pStubMsg->Buffer, 4); saved_buffer = pStubMsg->Buffer; - pStubMsg->Buffer += 4; /* for pointer ID */ + if (pStubMsg->PointerBufferMark) + { + pStubMsg->Buffer = pStubMsg->PointerBufferMark; + pStubMsg->PointerBufferMark = NULL; + pointer_buffer_mark_set = 1; + } + else + pStubMsg->Buffer += 4; /* for pointer ID */ + PointerMarshall(pStubMsg, saved_buffer, *(unsigned char **)pMemory, desc); + if (pointer_buffer_mark_set) + { + STD_OVERFLOW_CHECK(pStubMsg); + pStubMsg->PointerBufferMark = pStubMsg->Buffer; + pStubMsg->Buffer = saved_buffer + 4; + } break; default: m(pStubMsg, pMemory, desc); @@ -4164,6 +4592,7 @@ unsigned char * WINAPI NdrNonEncapsulatedUnionMarshall(PMIDL_STUB_MESSAGE pStub } else FIXME("no marshaller for embedded type %02x\n", *desc); } + STD_OVERFLOW_CHECK(pStubMsg); return NULL; } @@ -4249,16 +4678,32 @@ unsigned char * WINAPI NdrNonEncapsulatedUnionUnmarshall(PMIDL_STUB_MESSAGE pSt if (m) { unsigned char *saved_buffer = NULL; + int pointer_buffer_mark_set = 0; switch(*desc) { case RPC_FC_RP: case RPC_FC_UP: case RPC_FC_OP: case RPC_FC_FP: + **(void***)ppMemory = NULL; ALIGN_POINTER(pStubMsg->Buffer, 4); saved_buffer = pStubMsg->Buffer; - pStubMsg->Buffer += 4; /* for pointer ID */ - PointerUnmarshall(pStubMsg, saved_buffer, *(unsigned char ***)ppMemory, desc, TRUE); + if (pStubMsg->PointerBufferMark) + { + pStubMsg->Buffer = pStubMsg->PointerBufferMark; + pStubMsg->PointerBufferMark = NULL; + pointer_buffer_mark_set = 1; + } + else + pStubMsg->Buffer += 4; /* for pointer ID */ + + PointerUnmarshall(pStubMsg, saved_buffer, *(unsigned char ***)ppMemory, desc, fMustAlloc); + if (pointer_buffer_mark_set) + { + STD_OVERFLOW_CHECK(pStubMsg); + pStubMsg->PointerBufferMark = pStubMsg->Buffer; + pStubMsg->Buffer = saved_buffer + 4; + } break; default: m(pStubMsg, ppMemory, desc, fMustAlloc); @@ -4314,7 +4759,17 @@ void WINAPI NdrNonEncapsulatedUnionBufferSize(PMIDL_STUB_MESSAGE pStubMsg, case RPC_FC_FP: ALIGN_LENGTH(pStubMsg->BufferLength, 4); pStubMsg->BufferLength += 4; /* for pointer ID */ - PointerBufferSize(pStubMsg, *(unsigned char **)pMemory, desc); + if (!pStubMsg->IgnoreEmbeddedPointers) + { + int saved_buffer_length = pStubMsg->BufferLength; + pStubMsg->BufferLength = pStubMsg->PointerLength; + pStubMsg->PointerLength = 0; + if(!pStubMsg->BufferLength) + ERR("BufferLength == 0??\n"); + PointerBufferSize(pStubMsg, *(unsigned char **)pMemory, desc); + pStubMsg->PointerLength = pStubMsg->BufferLength; + pStubMsg->BufferLength = saved_buffer_length; + } break; default: m(pStubMsg, pMemory, desc); @@ -4373,7 +4828,8 @@ ULONG WINAPI NdrNonEncapsulatedUnionMemorySize(PMIDL_STUB_MESSAGE pStubMsg, pStubMsg->Buffer += 4; ALIGN_LENGTH(pStubMsg->MemorySize, 4); pStubMsg->MemorySize += 4; - PointerMemorySize(pStubMsg, saved_buffer, pFormat); + if (!pStubMsg->IgnoreEmbeddedPointers) + PointerMemorySize(pStubMsg, saved_buffer, pFormat); break; default: return m(pStubMsg, desc); @@ -4502,6 +4958,187 @@ void WINAPI NdrXmitOrRepAsFree(PMIDL_STUB_MESSAGE pStubMsg, FIXME("stub\n"); } +#include "pshpack1.h" +typedef struct +{ + unsigned char type; + unsigned char flags_type; /* flags in upper nibble, type in lower nibble */ + ULONG low_value; + ULONG high_value; +} NDR_RANGE; +#include "poppack.h" + +/*********************************************************************** + * NdrRangeMarshall [internal] + */ +unsigned char *WINAPI NdrRangeMarshall( + PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + NDR_RANGE *pRange = (NDR_RANGE *)pFormat; + unsigned char base_type; + + TRACE("pStubMsg %p, pMemory %p, type 0x%02x\n", pStubMsg, pMemory, *pFormat); + + if (pRange->type != RPC_FC_RANGE) + { + ERR("invalid format type %x\n", pRange->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + + base_type = pRange->flags_type & 0xf; + + return NdrBaseTypeMarshall(pStubMsg, pMemory, &base_type); +} + +/*********************************************************************** + * NdrRangeUnmarshall + */ +unsigned char *WINAPI NdrRangeUnmarshall( + PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + NDR_RANGE *pRange = (NDR_RANGE *)pFormat; + unsigned char base_type; + + TRACE("pStubMsg: %p, ppMemory: %p, type: 0x%02x, fMustAlloc: %s\n", pStubMsg, ppMemory, *pFormat, fMustAlloc ? "true" : "false"); + + if (pRange->type != RPC_FC_RANGE) + { + ERR("invalid format type %x\n", pRange->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + base_type = pRange->flags_type & 0xf; + + TRACE("base_type = 0x%02x, low_value = %d, high_value = %d\n", + base_type, pRange->low_value, pRange->high_value); + +#define RANGE_UNMARSHALL(type, format_spec) \ + do \ + { \ + ALIGN_POINTER(pStubMsg->Buffer, sizeof(type)); \ + if (fMustAlloc || !*ppMemory) \ + *ppMemory = NdrAllocate(pStubMsg, sizeof(type)); \ + if ((*(type *)pStubMsg->Buffer < (type)pRange->low_value) || \ + (*(type *)pStubMsg->Buffer > (type)pRange->high_value)) \ + { \ + ERR("value exceeded bounds: " format_spec ", low: " format_spec ", high: " format_spec "\n", \ + *(type *)pStubMsg->Buffer, (type)pRange->low_value, \ + (type)pRange->high_value); \ + RpcRaiseException(RPC_S_INVALID_BOUND); \ + return NULL; \ + } \ + TRACE("*ppMemory: %p\n", *ppMemory); \ + **(type **)ppMemory = *(type *)pStubMsg->Buffer; \ + pStubMsg->Buffer += sizeof(type); \ + } while (0) + + switch(base_type) + { + case RPC_FC_CHAR: + case RPC_FC_SMALL: + RANGE_UNMARSHALL(UCHAR, "%d"); + TRACE("value: 0x%02x\n", **(UCHAR **)ppMemory); + break; + case RPC_FC_BYTE: + case RPC_FC_USMALL: + RANGE_UNMARSHALL(CHAR, "%u"); + TRACE("value: 0x%02x\n", **(UCHAR **)ppMemory); + break; + case RPC_FC_WCHAR: /* FIXME: valid? */ + case RPC_FC_USHORT: + RANGE_UNMARSHALL(USHORT, "%u"); + TRACE("value: 0x%04x\n", **(USHORT **)ppMemory); + break; + case RPC_FC_SHORT: + RANGE_UNMARSHALL(SHORT, "%d"); + TRACE("value: 0x%04x\n", **(USHORT **)ppMemory); + break; + case RPC_FC_LONG: + RANGE_UNMARSHALL(LONG, "%d"); + TRACE("value: 0x%08x\n", **(ULONG **)ppMemory); + break; + case RPC_FC_ULONG: + RANGE_UNMARSHALL(ULONG, "%u"); + TRACE("value: 0x%08x\n", **(ULONG **)ppMemory); + break; + case RPC_FC_ENUM16: + case RPC_FC_ENUM32: + FIXME("Unhandled enum type\n"); + break; + case RPC_FC_ERROR_STATUS_T: /* FIXME: valid? */ + case RPC_FC_FLOAT: + case RPC_FC_DOUBLE: + case RPC_FC_HYPER: + default: + ERR("invalid range base type: 0x%02x\n", base_type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + } + + return NULL; +} + +/*********************************************************************** + * NdrRangeBufferSize [internal] + */ +void WINAPI NdrRangeBufferSize( + PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + NDR_RANGE *pRange = (NDR_RANGE *)pFormat; + unsigned char base_type; + + TRACE("pStubMsg %p, pMemory %p, type 0x%02x\n", pStubMsg, pMemory, *pFormat); + + if (pRange->type != RPC_FC_RANGE) + { + ERR("invalid format type %x\n", pRange->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + } + base_type = pRange->flags_type & 0xf; + + NdrBaseTypeBufferSize(pStubMsg, pMemory, &base_type); +} + +/*********************************************************************** + * NdrRangeMemorySize [internal] + */ +ULONG WINAPI NdrRangeMemorySize( + PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + NDR_RANGE *pRange = (NDR_RANGE *)pFormat; + unsigned char base_type; + + if (pRange->type != RPC_FC_RANGE) + { + ERR("invalid format type %x\n", pRange->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return 0; + } + base_type = pRange->flags_type & 0xf; + + return NdrBaseTypeMemorySize(pStubMsg, &base_type); +} + +/*********************************************************************** + * NdrRangeFree [internal] + */ +void WINAPI NdrRangeFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + TRACE("pStubMsg %p pMemory %p type 0x%02x\n", pStubMsg, pMemory, *pFormat); + + /* nothing to do */ +} + /*********************************************************************** * NdrBaseTypeMarshall [internal] */ @@ -4766,6 +5403,70 @@ static void WINAPI NdrBaseTypeFree(PMIDL_STUB_MESSAGE pStubMsg, } /*********************************************************************** + * NdrContextHandleBufferSize [internal] + */ +static void WINAPI NdrContextHandleBufferSize( + PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + TRACE("pStubMsg %p, pMemory %p, type 0x%02x\n", pStubMsg, pMemory, *pFormat); + + if (*pFormat != RPC_FC_BIND_CONTEXT) + { + ERR("invalid format type %x\n", *pFormat); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + } + ALIGN_LENGTH(pStubMsg->BufferLength, 4); + pStubMsg->BufferLength += cbNDRContext; +} + +/*********************************************************************** + * NdrContextHandleMarshall [internal] + */ +static unsigned char *WINAPI NdrContextHandleMarshall( + PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + TRACE("pStubMsg %p, pMemory %p, type 0x%02x\n", pStubMsg, pMemory, *pFormat); + + if (*pFormat != RPC_FC_BIND_CONTEXT) + { + ERR("invalid format type %x\n", *pFormat); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + } + + if (pFormat[1] & 0x80) + NdrClientContextMarshall(pStubMsg, *(NDR_CCONTEXT **)pMemory, FALSE); + else + NdrClientContextMarshall(pStubMsg, (NDR_CCONTEXT *)pMemory, FALSE); + + return NULL; +} + +/*********************************************************************** + * NdrContextHandleUnmarshall [internal] + */ +static unsigned char *WINAPI NdrContextHandleUnmarshall( + PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + if (*pFormat != RPC_FC_BIND_CONTEXT) + { + ERR("invalid format type %x\n", *pFormat); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + } + + **(NDR_CCONTEXT **)ppMemory = NULL; + NdrClientContextUnmarshall(pStubMsg, *(NDR_CCONTEXT **)ppMemory, pStubMsg->RpcMsg->Handle); + + return NULL; +} + +/*********************************************************************** * NdrClientContextMarshall [RPCRT4.@] */ void WINAPI NdrClientContextMarshall(PMIDL_STUB_MESSAGE pStubMsg, diff --git a/dlls/rpcrt4/ndr_stubless.c b/dlls/rpcrt4/ndr_stubless.c index dbe500ef7b6..fab29b5142f 100644 --- a/dlls/rpcrt4/ndr_stubless.c +++ b/dlls/rpcrt4/ndr_stubless.c @@ -122,6 +122,7 @@ static inline unsigned long call_memory_sizer(PMIDL_STUB_MESSAGE pStubMsg, PFORM #define STUBLESS_CALCSIZE 3 #define STUBLESS_GETBUFFER 4 #define STUBLESS_MARSHAL 5 +#define STUBLESS_FREE 6 /* From http://msdn.microsoft.com/library/default.asp?url=/library/en-us/rpc/rpc/parameter_descriptors.asp */ typedef struct _NDR_PROC_HEADER @@ -1259,7 +1260,7 @@ LONG WINAPI NdrStubCall2( * 4. STUBLESS_GETBUFFER - allocate [out] buffer * 5. STUBLESS_MARHSAL - marshal [out] params to buffer */ - for (phase = STUBLESS_UNMARSHAL; phase <= STUBLESS_MARSHAL; phase++) + for (phase = STUBLESS_UNMARSHAL; phase <= STUBLESS_FREE; phase++) { TRACE("phase = %d\n", phase); switch (phase) @@ -1317,6 +1318,7 @@ LONG WINAPI NdrStubCall2( case STUBLESS_MARSHAL: case STUBLESS_UNMARSHAL: case STUBLESS_CALCSIZE: + case STUBLESS_FREE: current_offset = parameter_start_offset; current_stack_offset = 0; @@ -1340,10 +1342,6 @@ LONG WINAPI NdrStubCall2( TRACE("\tstack_offset: 0x%x\n", current_stack_offset); TRACE("\tmemory addr (before): %p -> %p\n", pArg, *(unsigned char **)pArg); - if (pParam->param_attributes.ServerAllocSize) - FIXME("ServerAllocSize of %d ignored for parameter %d\n", - pParam->param_attributes.ServerAllocSize * 8, i); - if (pParam->param_attributes.IsBasetype) { const unsigned char *pTypeFormat = @@ -1361,9 +1359,17 @@ LONG WINAPI NdrStubCall2( else call_marshaller(&stubMsg, pArg, pTypeFormat); } + break; + case STUBLESS_FREE: + if (pParam->param_attributes.ServerAllocSize) + HeapFree(GetProcessHeap(), 0, *(void **)pArg); /* FIXME: call call_freer here */ break; case STUBLESS_UNMARSHAL: + if (pParam->param_attributes.ServerAllocSize) + *(void **)pArg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + pParam->param_attributes.ServerAllocSize * 8); + if (pParam->param_attributes.IsIn) { if (pParam->param_attributes.IsSimpleRef) @@ -1410,14 +1416,35 @@ LONG WINAPI NdrStubCall2( if (pParam->param_attributes.IsByValue) call_marshaller(&stubMsg, pArg, pTypeFormat); else - { call_marshaller(&stubMsg, *(unsigned char **)pArg, pTypeFormat); - stubMsg.pfnFree(*(void **)pArg); - } } - /* FIXME: call call_freer here for IN types */ + break; + case STUBLESS_FREE: + if (pParam->param_attributes.MustFree) + { + if (pParam->param_attributes.IsByValue) + call_freer(&stubMsg, pArg, pTypeFormat); + else + call_freer(&stubMsg, *(unsigned char **)pArg, pTypeFormat); + } + + if (pParam->param_attributes.IsOut && + !pParam->param_attributes.IsIn && + !pParam->param_attributes.IsByValue && + !pParam->param_attributes.ServerAllocSize) + { + stubMsg.pfnFree(*(void **)pArg); + } + + if (pParam->param_attributes.ServerAllocSize) + HeapFree(GetProcessHeap(), 0, *(void **)pArg); + /* FIXME: call call_freer here for IN types with MustFree set */ break; case STUBLESS_UNMARSHAL: + if (pParam->param_attributes.ServerAllocSize) + *(void **)pArg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + pParam->param_attributes.ServerAllocSize * 8); + if (pParam->param_attributes.IsIn) { if (pParam->param_attributes.IsByValue) @@ -1426,6 +1453,7 @@ LONG WINAPI NdrStubCall2( call_unmarshaller(&stubMsg, (unsigned char **)pArg, pTypeFormat, 0); } else if (pParam->param_attributes.IsOut && + !pParam->param_attributes.ServerAllocSize && !pParam->param_attributes.IsByValue) { DWORD size = calc_arg_size(&stubMsg, pTypeFormat); @@ -1486,6 +1514,10 @@ LONG WINAPI NdrStubCall2( if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE) call_marshaller(&stubMsg, pArg, pTypeFormat); break; + case STUBLESS_FREE: + if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE) + call_freer(&stubMsg, pArg, pTypeFormat); + break; case STUBLESS_UNMARSHAL: if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE) call_unmarshaller(&stubMsg, &pArg, pTypeFormat, 0); @@ -1521,6 +1553,13 @@ LONG WINAPI NdrStubCall2( pParam->param_direction == RPC_FC_RETURN_PARAM) call_marshaller(&stubMsg, *(unsigned char **)pArg, pTypeFormat); break; + case STUBLESS_FREE: + if (pParam->param_direction == RPC_FC_IN_OUT_PARAM || + pParam->param_direction == RPC_FC_IN_PARAM) + call_freer(&stubMsg, *(unsigned char **)pArg, pTypeFormat); + else if (pParam->param_direction == RPC_FC_OUT_PARAM) + stubMsg.pfnFree(*(void **)pArg); + break; case STUBLESS_UNMARSHAL: if (pParam->param_direction == RPC_FC_IN_OUT_PARAM || pParam->param_direction == RPC_FC_IN_PARAM) @@ -1589,3 +1628,18 @@ void WINAPI NdrServerCall2(PRPC_MESSAGE pRpcMsg) DWORD dwPhase; NdrStubCall2(NULL, NULL, pRpcMsg, &dwPhase); } + +LONG_PTR WINAPIV NdrAsyncClientCall(PMIDL_STUB_DESC pStubDesc, + PFORMAT_STRING pFormat, ...) +{ + FIXME("unimplemented, expect crash!\n"); + return 0; +} + +RPCRTAPI LONG RPC_ENTRY NdrAsyncStubCall(struct IRpcStubBuffer* pThis, + struct IRpcChannelBuffer* pChannel, PRPC_MESSAGE pRpcMsg, + DWORD * pdwStubPhase) +{ + FIXME("unimplemented, expect crash!\n"); + return 0; +} diff --git a/dlls/rpcrt4/rpc_binding.c b/dlls/rpcrt4/rpc_binding.c index ad96ac6496e..e68764458b6 100644 --- a/dlls/rpcrt4/rpc_binding.c +++ b/dlls/rpcrt4/rpc_binding.c @@ -295,6 +295,7 @@ RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection, Binding->AuthInfo, Binding->QOS, Binding); if (status != RPC_S_OK) return status; + *Connection = NewConnection; status = RPCRT4_OpenClientConnection(NewConnection); if (status != RPC_S_OK) @@ -325,25 +326,24 @@ RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection, status = RPCRT4_Receive(NewConnection, &response_hdr, &msg); if (status != RPC_S_OK) { ERR("receive failed\n"); - RPCRT4_DestroyConnection(NewConnection); + RPCRT4_DestroyConnection(*Connection); return status; } - if (response_hdr->common.ptype != PKT_BIND_ACK || - response_hdr->bind_ack.max_tsize < RPC_MIN_PACKET_SIZE) { + if (response_hdr->common.ptype != PKT_BIND_ACK) { ERR("failed to bind for interface %s, %d.%d\n", debugstr_guid(&InterfaceId->SyntaxGUID), InterfaceId->SyntaxVersion.MajorVersion, InterfaceId->SyntaxVersion.MinorVersion); RPCRT4_FreeHeader(response_hdr); - RPCRT4_DestroyConnection(NewConnection); + RPCRT4_DestroyConnection(*Connection); return RPC_S_PROTOCOL_ERROR; } /* FIXME: do more checks? */ - NewConnection->MaxTransmissionSize = response_hdr->bind_ack.max_tsize; - NewConnection->ActiveInterface = *InterfaceId; + (*Connection)->MaxTransmissionSize = response_hdr->bind_ack.max_tsize; + (*Connection)->ActiveInterface = *InterfaceId; RPCRT4_FreeHeader(response_hdr); } @@ -1154,6 +1154,15 @@ RPC_STATUS WINAPI RpcRevertToSelf(void) } /*********************************************************************** + * RpcBindingSetOption (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingSetOption(RPC_BINDING_HANDLE BindingHandle, ULONG Option, ULONG OptionValue) +{ + FIXME("(%p, %d, %d): stub\n", BindingHandle, Option, OptionValue); + return RPC_S_OK; +} + +/*********************************************************************** * RpcMgmtSetComTimeout (RPCRT4.@) */ RPC_STATUS WINAPI RpcMgmtSetComTimeout(RPC_BINDING_HANDLE BindingHandle, unsigned int Timeout) @@ -1349,6 +1358,14 @@ RpcBindingSetAuthInfoExW( RPC_BINDING_HANDLE Binding, RPC_WSTR ServerPrincName, TRACE("%p %s %u %u %p %u %p\n", Binding, debugstr_w((const WCHAR*)ServerPrincName), AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr, SecurityQos); + /* CODEWEAVERS HACK FOR OUTLOOK 2003: we only really know now to do NT authentication */ + if ((AuthnSvc == RPC_C_AUTHN_GSS_NEGOTIATE) || + (AuthnSvc == RPC_C_AUTHN_GSS_KERBEROS)) + { + FIXME("converting level %u to RPC_C_AUTHN_WINNT\n", AuthnSvc); + AuthnSvc = RPC_C_AUTHN_WINNT; + } + if (SecurityQos) { RPC_STATUS status; @@ -1468,12 +1485,3 @@ RpcBindingSetAuthInfoW( RPC_BINDING_HANDLE Binding, RPC_WSTR ServerPrincName, UL AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr); return RpcBindingSetAuthInfoExW(Binding, ServerPrincName, AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr, NULL); } - -/*********************************************************************** - * RpcBindingSetOption (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcBindingSetOption(RPC_BINDING_HANDLE BindingHandle, ULONG Option, ULONG OptionValue) -{ - FIXME("(%p, %d, %d): stub\n", BindingHandle, Option, OptionValue); - return RPC_S_OK; -} diff --git a/dlls/rpcrt4/rpc_defs.h b/dlls/rpcrt4/rpc_defs.h index 7499dcd1c1d..4506ca31139 100644 --- a/dlls/rpcrt4/rpc_defs.h +++ b/dlls/rpcrt4/rpc_defs.h @@ -122,6 +122,14 @@ typedef struct } protocols[1]; } RpcPktBindNAckHdr; +/* undocumented packet sent during RPC over HTTP */ +typedef struct +{ + RpcPktCommonHdr common; + unsigned short flags; + unsigned short num_data_items; +} RpcPktHttpHdr; + /* Union representing all possible packet headers */ typedef union { @@ -132,6 +140,7 @@ typedef union RpcPktBindHdr bind; RpcPktBindAckHdr bind_ack; RpcPktBindNAckHdr bind_nack; + RpcPktHttpHdr http; } RpcPktHdr; typedef struct @@ -176,6 +185,7 @@ typedef struct #define PKT_SHUTDOWN 17 #define PKT_CO_CANCEL 18 #define PKT_ORPHANED 19 +#define PKT_HTTP 20 #define RESULT_ACCEPT 0 diff --git a/dlls/rpcrt4/rpc_epmap.c b/dlls/rpcrt4/rpc_epmap.c index 45471c175b7..b23e2f65ca3 100644 --- a/dlls/rpcrt4/rpc_epmap.c +++ b/dlls/rpcrt4/rpc_epmap.c @@ -36,6 +36,7 @@ #include "wine/debug.h" #include "rpc_binding.h" +#include "epm.h" #include "epm_towers.h" WINE_DEFAULT_DEBUG_CHANNEL(ole); @@ -44,8 +45,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); * * ncadg_ip_udp: 135 * ncacn_ip_tcp: 135 - * ncacn_np: \\pipe\epmapper (?) + * ncacn_np: \\pipe\epmapper * ncalrpc: epmapper + * ncacn_http: 593 * * If the user's machine ran a DCE RPC daemon, it would * probably be possible to connect to it, but there are many @@ -207,6 +209,19 @@ RPC_STATUS WINAPI RpcEpUnregister( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *Bin return rslt; } +static const struct epm_endpoints +{ + const char *protseq; + const char *endpoint; +} epm_endpoints[] = +{ + { "ncacn_np", "\\pipe\\epmapper" }, + { "ncacn_ip_tcp", "135" }, + { "ncacn_ip_udp", "135" }, + { "ncalprc", "epmapper" }, + { "ncacn_http", "593" }, +}; + /*********************************************************************** * RpcEpResolveBinding (RPCRT4.@) */ @@ -220,14 +235,87 @@ RPC_STATUS WINAPI RpcEpResolveBinding( RPC_BINDING_HANDLE Binding, RPC_IF_HANDLE TRACE("(%p,%p)\n", Binding, IfSpec); TRACE(" protseq=%s\n", debugstr_a(bind->Protseq)); TRACE(" obj=%s\n", debugstr_guid(&bind->ObjectUuid)); + TRACE(" networkaddr=%s\n", debugstr_a(bind->NetworkAddr)); 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; + /* non-local resolve */ + if (bind->NetworkAddr && bind->NetworkAddr[0]) + { + RPC_STATUS status; + error_status_t status2; + handle_t handle; + ept_lookup_handle_t entry_handle = NULL; + const char * pszEndpoint = NULL; + twr_t *tower; + twr_t *towers[4]; + unsigned32 num_towers, i; + GUID uuid = GUID_NULL; + char *resolved_endpoint = NULL; + RpcBinding* newbind; + + for (i = 0; i < sizeof(epm_endpoints)/sizeof(epm_endpoints[0]); i++) + if (!strcmp(bind->Protseq, epm_endpoints[i].protseq)) + pszEndpoint = epm_endpoints[i].endpoint; + + if (!pszEndpoint) + { + FIXME("no endpoint for the endpoint-mapper found for protseq %s\n", debugstr_a(bind->Protseq)); + return RPC_S_PROTSEQ_NOT_SUPPORTED; + } + + status = RpcBindingCopy(Binding, &handle); + newbind = (RpcBinding*)handle; + /* don't bother with authenticating against the EPM by default + * (see EnableAuthEpResolution registry value) */ + RpcAuthInfo_Release(newbind->AuthInfo); + newbind->AuthInfo = NULL; + RPCRT4_ResolveBinding(newbind, pszEndpoint); + + status = TowerConstruct(&If->InterfaceId, &If->TransferSyntax, bind->Protseq, pszEndpoint, bind->NetworkAddr, &tower); + if (status != RPC_S_OK) + { + WARN("couldn't get tower\n"); + RpcBindingFree(&handle); + return status; + } + + ept_map(handle, &uuid, tower, &entry_handle, sizeof(towers)/sizeof(towers[0]), &num_towers, towers, &status2); + RpcBindingFree(&handle); + I_RpcFree(tower); + + if (status2 != RPC_S_OK) + { + ERR("ept_map failed for ifid %s, protseq %s, networkaddr %s\n", debugstr_guid(&If->TransferSyntax.SyntaxGUID), bind->Protseq, bind->NetworkAddr); + return status2; + } + + for (i = 0; i < num_towers; i++) + { + /* only parse the tower if we haven't already found a suitable + * endpoint, otherwise just free the tower */ + if (!resolved_endpoint) + { + status = TowerExplode(towers[i], NULL, NULL, NULL, &resolved_endpoint, NULL); + TRACE("status = %ld\n", status); + } + I_RpcFree(towers[i]); + } + + if (resolved_endpoint) + { + RPCRT4_ResolveBinding(Binding, resolved_endpoint); + I_RpcFree(resolved_endpoint); + return RPC_S_OK; + } + + WARN("couldn't find an endpoint\n"); + return EPT_S_NOT_REGISTERED; + } + /* construct the message to rpcss */ msg.message_type = RPCSS_NP_MESSAGE_TYPEID_RESOLVEEPMSG; msg.message.resolveepmsg.iface = If->InterfaceId; @@ -241,22 +329,15 @@ RPC_STATUS WINAPI RpcEpResolveBinding( RPC_BINDING_HANDLE Binding, RPC_IF_HANDLE /* empty-string result means not registered */ if (reply.as_string[0] == '\0') + { + FIXME("GUID %s not registered\n", debugstr_guid(&If->InterfaceId.SyntaxGUID)); return EPT_S_NOT_REGISTERED; + } /* otherwise we fully bind the handle & return RPC_S_OK */ return RPCRT4_ResolveBinding(Binding, reply.as_string); } -typedef unsigned int unsigned32; -typedef struct twr_t - { - unsigned32 tower_length; - /* [size_is] */ BYTE tower_octet_string[ 1 ]; - } twr_t; - -/*********************************************************************** - * TowerExplode (RPCRT4.@) - */ RPC_STATUS WINAPI TowerExplode( const twr_t *tower, PRPC_SYNTAX_IDENTIFIER object, PRPC_SYNTAX_IDENTIFIER syntax, char **protseq, char **endpoint, char **address) @@ -383,3 +464,13 @@ RPC_STATUS WINAPI TowerConstruct( } return RPC_S_OK; } + +void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t len) +{ + return HeapAlloc(GetProcessHeap(), 0, len); +} + +void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr) +{ + HeapFree(GetProcessHeap(), 0, ptr); +} diff --git a/dlls/rpcrt4/rpc_message.c b/dlls/rpcrt4/rpc_message.c index 10866020dd4..af487b3d8a6 100644 --- a/dlls/rpcrt4/rpc_message.c +++ b/dlls/rpcrt4/rpc_message.c @@ -65,7 +65,7 @@ static DWORD RPCRT4_GetHeaderSize(const RpcPktHdr *Header) 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 + 0, 0, 0, 0, 0, 0, sizeof(Header->http) }; ULONG ret = 0; @@ -76,7 +76,7 @@ static DWORD RPCRT4_GetHeaderSize(const RpcPktHdr *Header) if (Header->common.flags & RPC_FLG_OBJECT_UUID) ret += sizeof(UUID); } else { - TRACE("invalid packet type\n"); + WARN("invalid packet type %u\n", Header->common.ptype); } return ret; @@ -278,11 +278,326 @@ RpcPktHdr *RPCRT4_BuildBindAckHeader(unsigned long DataRepresentation, return header; } +RpcPktHdr *RPCRT4_BuildHttpHeader(unsigned long DataRepresentation, + unsigned short flags, + unsigned short num_data_items, + unsigned int payload_size) +{ + RpcPktHdr *header; + + header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->http) + payload_size); + if (header == NULL) { + ERR("failed to allocate memory\n"); + return NULL; + } + + RPCRT4_BuildCommonHeader(header, PKT_HTTP, DataRepresentation); + /* since the packet isn't current sent using RPCRT4_Send, set the flags + * manually here */ + header->common.flags = RPC_FLG_FIRST|RPC_FLG_LAST; + header->common.call_id = 0; + header->common.frag_len = sizeof(header->http) + payload_size; + header->http.flags = flags; + header->http.num_data_items = num_data_items; + + return header; +} + +#define WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, type, value) \ + do { \ + *(unsigned int *)(payload) = (type); \ + (payload) += 4; \ + *(unsigned int *)(payload) = (value); \ + (payload) += 4; \ + } while (0) + +#define WRITE_HTTP_PAYLOAD_FIELD_UUID(payload, type, uuid) \ + do { \ + *(unsigned int *)(payload) = (type); \ + (payload) += 4; \ + *(UUID *)(payload) = (uuid); \ + (payload) += sizeof(UUID); \ + } while (0) + +#define WRITE_HTTP_PAYLOAD_FIELD_FLOW_CONTROL(payload, bytes_transmitted, flow_control_increment, uuid) \ + do { \ + *(unsigned int *)(payload) = 0x00000001; \ + (payload) += 4; \ + *(unsigned int *)(payload) = (bytes_transmitted); \ + (payload) += 4; \ + *(unsigned int *)(payload) = (flow_control_increment); \ + (payload) += 4; \ + *(UUID *)(payload) = (uuid); \ + (payload) += sizeof(UUID); \ + } while (0) + +RpcPktHdr *RPCRT4_BuildHttpConnectHeader(unsigned short flags, int out_pipe, + const UUID *connection_uuid, + const UUID *pipe_uuid) +{ + RpcPktHdr *header; + unsigned int size; + char *payload; + + size = 8 + 4 + sizeof(UUID) + 4 + sizeof(UUID) + 8; + if (!out_pipe) + size += 8 + 4 + sizeof(UUID); + + header = RPCRT4_BuildHttpHeader(NDR_LOCAL_DATA_REPRESENTATION, flags, + out_pipe ? 4 : 6, size); + if (!header) return NULL; + payload = (char *)(&header->http+1); + + /* FIXME: what does this part of the payload do? */ + WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x00000006, 0x00000001); + + WRITE_HTTP_PAYLOAD_FIELD_UUID(payload, 0x00000003, *connection_uuid); + WRITE_HTTP_PAYLOAD_FIELD_UUID(payload, 0x00000003, *pipe_uuid); + + if (out_pipe) + /* FIXME: what does this part of the payload do? */ + WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x00000000, 0x00010000); + else + { + UUID unknown_uuid; + + /* FIXME: what does this part of the payload do? */ + WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x00000004, 0x40000000); + /* FIXME: what does this part of the payload do? */ + WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x00000005, 0x000493e0); + + UuidCreate(&unknown_uuid); + WRITE_HTTP_PAYLOAD_FIELD_UUID(payload, 0x0000000c, unknown_uuid); + } + + return header; +} + +RpcPktHdr *RPCRT4_BuildHttpFlowControlHeader(BOOL server, ULONG bytes_transmitted, + ULONG flow_control_increment, + const UUID *pipe_uuid) +{ + RpcPktHdr *header; + char *payload; + + header = RPCRT4_BuildHttpHeader(NDR_LOCAL_DATA_REPRESENTATION, 0x2, 2, + 5 * sizeof(ULONG) + sizeof(UUID)); + if (!header) return NULL; + payload = (char *)(&header->http+1); + + WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x0000000d, (server ? 0x0 : 0x3)); + + WRITE_HTTP_PAYLOAD_FIELD_FLOW_CONTROL(payload, bytes_transmitted, + flow_control_increment, *pipe_uuid); + return header; +} + VOID RPCRT4_FreeHeader(RpcPktHdr *Header) { HeapFree(GetProcessHeap(), 0, Header); } + +/* assumes the common header fields have already been validated */ +BOOL RPCRT4_IsValidHttpPacket(RpcPktHdr *hdr, unsigned char *data, + unsigned short data_len) +{ + unsigned short i; + BYTE *p = data; + + for (i = 0; i < hdr->http.num_data_items; i++) + { + ULONG type; + + if (data_len < sizeof(ULONG)) + return FALSE; + + type = *(ULONG *)p; + p += sizeof(ULONG); + data_len -= sizeof(ULONG); + + switch (type) + { + case 0x3: + case 0xc: + if (data_len < sizeof(GUID)) + return FALSE; + p += sizeof(GUID); + data_len -= sizeof(GUID); + break; + case 0x0: + case 0x2: + case 0x4: + case 0x5: + case 0x6: + case 0xd: + if (data_len < sizeof(ULONG)) + return FALSE; + p += sizeof(ULONG); + data_len -= sizeof(ULONG); + break; + case 0x1: + if (data_len < 24) + return FALSE; + p += 24; + data_len -= 24; + break; + default: + FIXME("unimplemented type 0x%x\n", type); + break; + } + } + return TRUE; +} + +/* assumes the HTTP packet has been validated */ +unsigned char *RPCRT4_NextHttpHeaderField(unsigned char *data) +{ + ULONG type; + + type = *(ULONG *)data; + data += sizeof(ULONG); + + switch (type) + { + case 0x3: + case 0xc: + return data + sizeof(GUID); + case 0x0: + case 0x2: + case 0x4: + case 0x5: + case 0x6: + case 0xd: + return data + sizeof(ULONG); + case 0x1: + return data + 24; + default: + FIXME("unimplemented type 0x%x\n", type); + return data; + } +} + +#define READ_HTTP_PAYLOAD_FIELD_TYPE(data) *(ULONG *)(data) +#define GET_HTTP_PAYLOAD_FIELD_DATA(data) ((data) + sizeof(ULONG)) + +/* assumes the HTTP packet has been validated */ +RPC_STATUS RPCRT4_ParseHttpPrepareHeader1(RpcPktHdr *header, + unsigned char *data, ULONG *field1) +{ + ULONG type; + if (header->http.flags != 0x0) + { + ERR("invalid flags 0x%x\n", header->http.flags); + return RPC_S_PROTOCOL_ERROR; + } + if (header->http.num_data_items != 1) + { + ERR("invalid number of data items %d\n", header->http.num_data_items); + return RPC_S_PROTOCOL_ERROR; + } + type = READ_HTTP_PAYLOAD_FIELD_TYPE(data); + if (type != 0x00000002) + { + ERR("invalid type 0x%08x\n", type); + return RPC_S_PROTOCOL_ERROR; + } + *field1 = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data); + return RPC_S_OK; +} + +/* assumes the HTTP packet has been validated */ +RPC_STATUS RPCRT4_ParseHttpPrepareHeader2(RpcPktHdr *header, + unsigned char *data, ULONG *field1, + ULONG *bytes_until_next_packet, + ULONG *field3) +{ + ULONG type; + if (header->http.flags != 0x0) + { + ERR("invalid flags 0x%x\n", header->http.flags); + return RPC_S_PROTOCOL_ERROR; + } + if (header->http.num_data_items != 3) + { + ERR("invalid number of data items %d\n", header->http.num_data_items); + return RPC_S_PROTOCOL_ERROR; + } + + type = READ_HTTP_PAYLOAD_FIELD_TYPE(data); + if (type != 0x00000006) + { + ERR("invalid type for field 1: 0x%08x\n", type); + return RPC_S_PROTOCOL_ERROR; + } + *field1 = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data); + data = RPCRT4_NextHttpHeaderField(data); + + type = READ_HTTP_PAYLOAD_FIELD_TYPE(data); + if (type != 0x00000000) + { + ERR("invalid type for field 2: 0x%08x\n", type); + return RPC_S_PROTOCOL_ERROR; + } + *bytes_until_next_packet = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data); + data = RPCRT4_NextHttpHeaderField(data); + + type = READ_HTTP_PAYLOAD_FIELD_TYPE(data); + if (type != 0x00000002) + { + ERR("invalid type for field 3: 0x%08x\n", type); + return RPC_S_PROTOCOL_ERROR; + } + *field3 = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data); + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_ParseHttpFlowControlHeader(RpcPktHdr *header, + unsigned char *data, BOOL server, + ULONG *bytes_transmitted, + ULONG *flow_control_increment, + UUID *pipe_uuid) +{ + ULONG type; + if (header->http.flags != 0x2) + { + ERR("invalid flags 0x%x\n", header->http.flags); + return RPC_S_PROTOCOL_ERROR; + } + if (header->http.num_data_items != 2) + { + ERR("invalid number of data items %d\n", header->http.num_data_items); + return RPC_S_PROTOCOL_ERROR; + } + + type = READ_HTTP_PAYLOAD_FIELD_TYPE(data); + if (type != 0x0000000d) + { + ERR("invalid type for field 1: 0x%08x\n", type); + return RPC_S_PROTOCOL_ERROR; + } + if (*(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data) != (server ? 0x3 : 0x0)) + { + ERR("invalid type for 0xd field data: 0x%08x\n", *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data)); + return RPC_S_PROTOCOL_ERROR; + } + data = RPCRT4_NextHttpHeaderField(data); + + type = READ_HTTP_PAYLOAD_FIELD_TYPE(data); + if (type != 0x00000001) + { + ERR("invalid type for field 2: 0x%08x\n", type); + return RPC_S_PROTOCOL_ERROR; + } + *bytes_transmitted = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data); + *flow_control_increment = *(ULONG *)(GET_HTTP_PAYLOAD_FIELD_DATA(data) + 4); + *pipe_uuid = *(UUID *)(GET_HTTP_PAYLOAD_FIELD_DATA(data) + 8); + + return RPC_S_OK; +} + + static RPC_STATUS RPCRT4_SecurePacket(RpcConnection *Connection, enum secure_packet_direction dir, RpcPktHdr *hdr, unsigned int hdr_size, @@ -327,6 +642,14 @@ static RPC_STATUS RPCRT4_SecurePacket(RpcConnection *Connection, sec_status = MakeSignature(&Connection->ctx, 0, &message, 0 /* FIXME */); if (sec_status != SEC_E_OK) { + /* FIXME: hack - work around lack of MakeSignature support in + * the version of secur32 in CXOFFICE-6.0 */ + { + memset(auth_value, 0, auth_value_size); + auth_value[0] = 1; /* version number lsb */ + return RPC_S_OK; + } + ERR("MakeSignature failed with 0x%08x\n", sec_status); return RPC_S_SEC_PKG_ERROR; } @@ -994,6 +1317,7 @@ RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg) if (status != RPC_S_OK) return status; } +receive: status = RPCRT4_Receive(conn, &hdr, pMsg); if (status != RPC_S_OK) { WARN("receive failed with error %lx\n", status); @@ -1013,7 +1337,49 @@ RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg) pMsg->RpcFlags |= WINE_RPCFLAG_EXCEPTION; ERR ("we got fault packet with status 0x%lx\n", hdr->fault.status); status = hdr->fault.status; /* FIXME: do translation from nca error codes */ + /* FIXME: hack - only translates one nca error code */ + if (status == 0x1c010002) + status = RPC_S_PROCNUM_OUT_OF_RANGE; goto fail; + case PKT_HTTP: + if (!RPCRT4_IsValidHttpPacket(hdr, pMsg->Buffer, pMsg->BufferLength)) + { + ERR("invalid http packet of length %d bytes\n", hdr->common.frag_len); + goto fail; + } + if (hdr->http.flags == 0x0001) + { + TRACE("http idle packet, waiting for real packet\n"); + if (hdr->http.num_data_items != 0) + { + ERR("HTTP idle packet should have no data items instead of %d\n", hdr->http.num_data_items); + goto fail; + } + } + else if (hdr->http.flags == 0x0002) + { + ULONG bytes_transmitted; + ULONG flow_control_increment; + UUID pipe_uuid; + status = RPCRT4_ParseHttpFlowControlHeader(hdr, pMsg->Buffer, + bind->server, + &bytes_transmitted, + &flow_control_increment, + &pipe_uuid); + if (status != RPC_S_OK) + goto fail; + TRACE("received http flow control header (0x%x, 0x%x, %s)\n", + bytes_transmitted, flow_control_increment, debugstr_guid(&pipe_uuid)); + /* FIXME: do something with parsed data */ + } + else + { + FIXME("unrecognised http packet with flags 0x%04x\n", hdr->http.flags); + goto fail; + } + I_RpcFreeBuffer(pMsg); + RPCRT4_FreeHeader(hdr); + goto receive; default: WARN("bad packet type %d\n", hdr->common.ptype); goto fail; diff --git a/dlls/rpcrt4/rpc_message.h b/dlls/rpcrt4/rpc_message.h index 97defb38871..bc9ecd627cb 100644 --- a/dlls/rpcrt4/rpc_message.h +++ b/dlls/rpcrt4/rpc_message.h @@ -28,8 +28,17 @@ RpcPktHdr *RPCRT4_BuildFaultHeader(unsigned long DataRepresentation, RPC_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); +RpcPktHdr *RPCRT4_BuildHttpHeader(unsigned long DataRepresentation, unsigned short flags, unsigned short num_data_items, unsigned int payload_size); +RpcPktHdr *RPCRT4_BuildHttpConnectHeader(unsigned short flags, int out_pipe, const UUID *connection_uuid, const UUID *pipe_uuid); +RpcPktHdr *RPCRT4_BuildHttpFlowControlHeader(BOOL server, ULONG bytes_transmitted, ULONG flow_control_increment, const UUID *pipe_uuid); 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); +BOOL RPCRT4_IsValidHttpPacket(RpcPktHdr *hdr, unsigned char *data, unsigned short data_len); +unsigned char *RPCRT4_NextHttpHeaderField(unsigned char *data); +RPC_STATUS RPCRT4_ParseHttpPrepareHeader1(RpcPktHdr *header, unsigned char *data, ULONG *field1); +RPC_STATUS RPCRT4_ParseHttpPrepareHeader2(RpcPktHdr *header, unsigned char *data, ULONG *field1, ULONG *bytes_until_next_packet, ULONG *field3); +RPC_STATUS RPCRT4_ParseHttpFlowControlHeader(RpcPktHdr *header, unsigned char *data, BOOL server, ULONG *bytes_transmitted, ULONG *flow_control_increment, UUID *pipe_uuid); + #endif diff --git a/dlls/rpcrt4/rpc_transport.c b/dlls/rpcrt4/rpc_transport.c index b4af8e95bed..a36937069f8 100644 --- a/dlls/rpcrt4/rpc_transport.c +++ b/dlls/rpcrt4/rpc_transport.c @@ -61,6 +61,7 @@ #include "winnls.h" #include "winerror.h" #include "winreg.h" +#include "wininet.h" #include "winternl.h" #include "wine/unicode.h" @@ -970,9 +971,10 @@ static int rpcrt4_conn_tcp_close(RpcConnection *Connection) return 0; } -static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data, - const char *networkaddr, - const char *endpoint) +static size_t rpcrt4_ip_tcp_get_top_of_tower(unsigned char *tower_data, + const char *networkaddr, + unsigned char tcp_protid, + const char *endpoint) { twr_tcp_floor_t *tcp_floor; twr_ipv4_floor_t *ipv4_floor; @@ -992,7 +994,7 @@ static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data, ipv4_floor = (twr_ipv4_floor_t *)tower_data; tcp_floor->count_lhs = sizeof(tcp_floor->protid); - tcp_floor->protid = EPM_PROTOCOL_TCP; + tcp_floor->protid = tcp_protid; tcp_floor->count_rhs = sizeof(tcp_floor->port); ipv4_floor->count_lhs = sizeof(ipv4_floor->protid); @@ -1037,10 +1039,19 @@ static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data, return size; } -static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data, - size_t tower_size, - char **networkaddr, - char **endpoint) +static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data, + const char *networkaddr, + const char *endpoint) +{ + return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr, + EPM_PROTOCOL_TCP, endpoint); +} + +static RPC_STATUS rpcrt4_ip_tcp_parse_top_of_tower(const unsigned char *tower_data, + size_t tower_size, + char **networkaddr, + unsigned char tcp_protid, + char **endpoint) { const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data; const twr_ipv4_floor_t *ipv4_floor; @@ -1060,7 +1071,7 @@ static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *to ipv4_floor = (const twr_ipv4_floor_t *)tower_data; if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) || - (tcp_floor->protid != EPM_PROTOCOL_TCP) || + (tcp_floor->protid != tcp_protid) || (tcp_floor->count_rhs != sizeof(tcp_floor->port)) || (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) || (ipv4_floor->protid != EPM_PROTOCOL_IP) || @@ -1243,6 +1254,602 @@ static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq return 1; } +static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data, + size_t tower_size, + char **networkaddr, + char **endpoint) +{ + return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size, + networkaddr, EPM_PROTOCOL_TCP, + endpoint); +} + +/**** ncacn_http support ****/ + +/* 60 seconds is the period native uses */ +#define HTTP_IDLE_TIME 60000 + +typedef struct _RpcConnection_http +{ + RpcConnection common; + HINTERNET in_request; + HINTERNET out_request; + HANDLE timer_cancelled; + DWORD last_sent_time; + ULONG bytes_received; + ULONG flow_control_mark; /* send a control packet to the server when this many bytes received */ + ULONG flow_control_increment; /* number of bytes to increment flow_control_mark by */ + UUID connection_uuid; + UUID in_pipe_uuid; + UUID out_pipe_uuid; +} RpcConnection_http; + +static RpcConnection *rpcrt4_ncacn_http_alloc(void) +{ + RpcConnection_http *httpc; + httpc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*httpc)); + return &httpc->common; +} + +typedef struct _HttpTimerThreadData +{ + PVOID timer_param; + DWORD *last_sent_time; + HANDLE timer_cancelled; +} HttpTimerThreadData; + +static VOID CALLBACK rpcrt4_http_keep_connection_active_timer_proc(PVOID param, BOOLEAN dummy) +{ + HINTERNET in_request = param; + RpcPktHdr *idle_pkt; + + idle_pkt = RPCRT4_BuildHttpHeader(NDR_LOCAL_DATA_REPRESENTATION, 0x0001, + 0, 0); + if (idle_pkt) + { + DWORD bytes_written; + InternetWriteFile(in_request, idle_pkt, idle_pkt->common.frag_len, &bytes_written); + RPCRT4_FreeHeader(idle_pkt); + } +} + +static inline DWORD rpcrt4_http_timer_calc_timeout(DWORD *last_sent_time) +{ + DWORD cur_time = GetTickCount(); + DWORD cached_last_sent_time = *last_sent_time; + return HTTP_IDLE_TIME - (cur_time - cached_last_sent_time > HTTP_IDLE_TIME ? 0 : cur_time - cached_last_sent_time); +} + +static DWORD CALLBACK rpcrt4_http_timer_thread(PVOID param) +{ + HttpTimerThreadData *data_in = param; + HttpTimerThreadData data; + DWORD timeout; + + data = *data_in; + HeapFree(GetProcessHeap(), 0, data_in); + + for (timeout = HTTP_IDLE_TIME; + WaitForSingleObject(data.timer_cancelled, timeout) == WAIT_TIMEOUT; + timeout = rpcrt4_http_timer_calc_timeout(data.last_sent_time)) + { + /* are we too soon after last send? */ + if (GetTickCount() - HTTP_IDLE_TIME < *data.last_sent_time) + continue; + rpcrt4_http_keep_connection_active_timer_proc(data.timer_param, TRUE); + } + + CloseHandle(data.timer_cancelled); + return 0; +} + +static RPC_STATUS rpcrt4_http_check_response(HINTERNET hor) +{ + BOOL ret; + DWORD status_code; + DWORD size; + DWORD index; + WCHAR status_text[32]; + + TRACE("\n"); + + index = 0; + size = sizeof(status_code); + ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status_code, &size, &index); + if (!ret) + return GetLastError(); + if (status_code < 400) + return RPC_S_OK; + index = 0; + size = sizeof(status_text); + ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index); + if (!ret) + return GetLastError(); + ERR("server returned: %d %s\n", status_code, debugstr_w(status_text)); + if (status_code == HTTP_STATUS_DENIED) + return ERROR_ACCESS_DENIED; + return RPC_S_SERVER_UNAVAILABLE; +} + +static RPC_STATUS rpcrt4_http_internet_connect(RpcConnection_http *httpc, HINTERNET *hi, HINTERNET *hic) +{ + static const WCHAR wszUserAgent[] = {'M','S','R','P','C',0}; + LPWSTR proxy = NULL; + LPWSTR user = NULL; + LPWSTR password = NULL; + LPWSTR servername = NULL; + const WCHAR *option; + INTERNET_PORT port = INTERNET_INVALID_PORT_NUMBER; /* use default port */ + + *hic = NULL; + + if (httpc->common.QOS && + (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP)) + { + const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_cred = httpc->common.QOS->qos->u.HttpCredentials; + if (http_cred->TransportCredentials) + { + WCHAR *p; + const SEC_WINNT_AUTH_IDENTITY_W *cred = http_cred->TransportCredentials; + ULONG len = cred->DomainLength + 1 + cred->UserLength; + user = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); + if (!user) + return RPC_S_OUT_OF_RESOURCES; + p = user; + if (cred->DomainLength) + { + memcpy(p, cred->Domain, cred->DomainLength * sizeof(WCHAR)); + p += cred->DomainLength; + *p = '\\'; + p++; + } + memcpy(p, cred->User, cred->UserLength * sizeof(WCHAR)); + p[cred->UserLength] = 0; + + password = RPCRT4_strndupW(cred->Password, cred->PasswordLength); + } + } + + for (option = httpc->common.NetworkOptions; option; + option = (strchrW(option, ',') ? strchrW(option, ',')+1 : NULL)) + { + static const WCHAR wszRpcProxy[] = {'R','p','c','P','r','o','x','y','=',0}; + static const WCHAR wszHttpProxy[] = {'H','t','t','p','P','r','o','x','y','=',0}; + + if (!strncmpiW(option, wszRpcProxy, sizeof(wszRpcProxy)/sizeof(wszRpcProxy[0])-1)) + { + const WCHAR *value_start = option + sizeof(wszRpcProxy)/sizeof(wszRpcProxy[0])-1; + const WCHAR *value_end; + const WCHAR *p; + + value_end = strchrW(option, ','); + if (!value_end) + value_end = value_start + strlenW(value_start); + for (p = value_start; p < value_end; p++) + if (*p == ':') + { + port = atoiW(p+1); + value_end = p; + break; + } + TRACE("RpcProxy value is %s\n", debugstr_wn(value_start, value_end-value_start)); + servername = RPCRT4_strndupW(value_start, value_end-value_start); + } + else if (!strncmpiW(option, wszHttpProxy, sizeof(wszHttpProxy)/sizeof(wszHttpProxy[0])-1)) + { + const WCHAR *value_start = option + sizeof(wszHttpProxy)/sizeof(wszHttpProxy[0])-1; + const WCHAR *value_end; + + value_end = strchrW(option, ','); + if (!value_end) + value_end = value_start + strlenW(value_start); + TRACE("HttpProxy value is %s\n", debugstr_wn(value_start, value_end-value_start)); + proxy = RPCRT4_strndupW(value_start, value_end-value_start); + } + else + FIXME("unhandled option %s\n", debugstr_w(option)); + } + + *hi = InternetOpenW(wszUserAgent, proxy ? INTERNET_OPEN_TYPE_PROXY : INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); + if (!*hi) + { + HeapFree(GetProcessHeap(), 0, password); + HeapFree(GetProcessHeap(), 0, user); + ERR("InternetOpenW failed with error %d\n", GetLastError()); + return RPC_S_SERVER_UNAVAILABLE; + } + + /* if no RpcProxy option specified, set the HTTP server address to the + * RPC server address */ + if (!servername) + { + servername = HeapAlloc(GetProcessHeap(), 0, (strlen(httpc->common.NetworkAddr) + 1)*sizeof(WCHAR)); + if (!servername) + { + HeapFree(GetProcessHeap(), 0, password); + HeapFree(GetProcessHeap(), 0, user); + return RPC_S_OUT_OF_RESOURCES; + } + MultiByteToWideChar(CP_ACP, 0, httpc->common.NetworkAddr, -1, servername, strlen(httpc->common.NetworkAddr) + 1); + } + + *hic = InternetConnectW(*hi, servername, port, user, password, + INTERNET_SERVICE_HTTP, 0, 0); + + HeapFree(GetProcessHeap(), 0, password); + HeapFree(GetProcessHeap(), 0, user); + HeapFree(GetProcessHeap(), 0, servername); + + if (!*hic) + { + InternetCloseHandle(*hi); + ERR("InternetConnectW failed with error %d\n", GetLastError()); + return RPC_S_SERVER_UNAVAILABLE; + } + + return RPC_S_OK; +} + +/* prepare the in pipe for use by RPC packets */ +static RPC_STATUS rpcrt4_http_prepare_in_pipe(HINTERNET in_request, const UUID *connection_uuid, const UUID *in_pipe_uuid) +{ + BYTE packet[44]; + BOOL ret; + RPC_STATUS status; + RpcPktHdr *hdr; + INTERNET_BUFFERSW buffers_in; + DWORD bytes_read, bytes_written; + + /* prepare in pipe */ + ret = HttpSendRequestW(in_request, NULL, 0, NULL, 0); + if (!ret) + { + ERR("HttpSendRequestW failed with error %d\n", GetLastError()); + return RPC_S_SERVER_UNAVAILABLE; + } + status = rpcrt4_http_check_response(in_request); + if (status != RPC_S_OK) return status; + + InternetReadFile(in_request, packet, 20, &bytes_read); + /* FIXME: do something with retrieved data */ + + memset(&buffers_in, 0, sizeof(buffers_in)); + buffers_in.dwStructSize = sizeof(buffers_in); + /* FIXME: get this from the registry */ + buffers_in.dwBufferTotal = 1024 * 1024 * 1024; /* 1Gb */ + ret = HttpSendRequestExW(in_request, &buffers_in, NULL, 0, 0); + if (!ret) + { + ERR("HttpSendRequestExW failed with error %d\n", GetLastError()); + return RPC_S_SERVER_UNAVAILABLE; + } + + TRACE("sending HTTP connect header to server\n"); + hdr = RPCRT4_BuildHttpConnectHeader(0, FALSE, connection_uuid, in_pipe_uuid); + if (!hdr) return RPC_S_OUT_OF_RESOURCES; + ret = InternetWriteFile(in_request, hdr, hdr->common.frag_len, &bytes_written); + RPCRT4_FreeHeader(hdr); + if (!ret) + { + ERR("InternetWriteFile failed with error %d\n", GetLastError()); + return RPC_S_SERVER_UNAVAILABLE; + } + + return RPC_S_OK; +} + +static RPC_STATUS rpcrt4_http_read_http_packet(HINTERNET request, RpcPktHdr *hdr, BYTE **data) +{ + BOOL ret; + DWORD bytes_read; + unsigned short data_len; + + ret = InternetReadFile(request, hdr, sizeof(hdr->common), &bytes_read); + if (!ret) + return RPC_S_SERVER_UNAVAILABLE; + if (hdr->common.ptype != PKT_HTTP || hdr->common.frag_len < sizeof(hdr->http)) + { + ERR("wrong packet type received %d or wrong frag_len %d\n", + hdr->common.ptype, hdr->common.frag_len); + return RPC_S_PROTOCOL_ERROR; + } + + ret = InternetReadFile(request, &hdr->common + 1, sizeof(hdr->http) - sizeof(hdr->common), &bytes_read); + if (!ret) + return RPC_S_SERVER_UNAVAILABLE; + + data_len = hdr->common.frag_len - sizeof(hdr->http); + if (data_len) + { + *data = HeapAlloc(GetProcessHeap(), 0, data_len); + if (!*data) + return RPC_S_OUT_OF_RESOURCES; + ret = InternetReadFile(request, *data, data_len, &bytes_read); + if (!ret) + { + HeapFree(GetProcessHeap(), 0, *data); + return RPC_S_SERVER_UNAVAILABLE; + } + } + else + *data = NULL; + + if (!RPCRT4_IsValidHttpPacket(hdr, *data, data_len)) + { + ERR("invalid http packet\n"); + return RPC_S_PROTOCOL_ERROR; + } + + return RPC_S_OK; +} + +/* prepare the out pipe for use by RPC packets */ +static RPC_STATUS rpcrt4_http_prepare_out_pipe(HINTERNET out_request, + const UUID *connection_uuid, + const UUID *out_pipe_uuid, + ULONG *flow_control_increment) +{ + BYTE packet[20]; + BOOL ret; + RPC_STATUS status; + RpcPktHdr *hdr; + DWORD bytes_read; + BYTE *data_from_server; + RpcPktHdr pkt_from_server; + ULONG field1, field3; + + ret = HttpSendRequestW(out_request, NULL, 0, NULL, 0); + if (!ret) + { + ERR("HttpSendRequestW failed with error %d\n", GetLastError()); + return RPC_S_SERVER_UNAVAILABLE; + } + status = rpcrt4_http_check_response(out_request); + if (status != RPC_S_OK) return status; + + InternetReadFile(out_request, packet, 20, &bytes_read); + /* FIXME: do something with retrieved data */ + + hdr = RPCRT4_BuildHttpConnectHeader(0, TRUE, connection_uuid, out_pipe_uuid); + if (!hdr) return RPC_S_OUT_OF_RESOURCES; + ret = HttpSendRequestW(out_request, NULL, 0, hdr, hdr->common.frag_len); + RPCRT4_FreeHeader(hdr); + if (!ret) + { + ERR("HttpSendRequestW failed with error %d\n", GetLastError()); + return RPC_S_SERVER_UNAVAILABLE; + } + status = rpcrt4_http_check_response(out_request); + if (status != RPC_S_OK) return status; + + status = rpcrt4_http_read_http_packet(out_request, &pkt_from_server, + &data_from_server); + if (status != RPC_S_OK) return status; + status = RPCRT4_ParseHttpPrepareHeader1(&pkt_from_server, data_from_server, + &field1); + HeapFree(GetProcessHeap(), 0, data_from_server); + if (status != RPC_S_OK) return status; + TRACE("received (%d) from first prepare header\n", field1); + + status = rpcrt4_http_read_http_packet(out_request, &pkt_from_server, + &data_from_server); + if (status != RPC_S_OK) return status; + status = RPCRT4_ParseHttpPrepareHeader2(&pkt_from_server, data_from_server, + &field1, flow_control_increment, + &field3); + HeapFree(GetProcessHeap(), 0, data_from_server); + if (status != RPC_S_OK) return status; + TRACE("received (0x%08x 0x%08x %d) from second prepare header\n", field1, *flow_control_increment, field3); + + return RPC_S_OK; +} + +static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection) +{ + RpcConnection_http *httpc = (RpcConnection_http *)Connection; + static const WCHAR wszVerbIn[] = {'R','P','C','_','I','N','_','D','A','T','A',0}; + static const WCHAR wszVerbOut[] = {'R','P','C','_','O','U','T','_','D','A','T','A',0}; + static const WCHAR wszRpcProxyPrefix[] = {'/','r','p','c','/','r','p','c','p','r','o','x','y','.','d','l','l','?',0}; + static const WCHAR wszColon[] = {':',0}; + static const WCHAR wszAcceptType[] = {'a','p','p','l','i','c','a','t','i','o','n','/','r','p','c',0}; + LPCWSTR wszAcceptTypes[] = { wszAcceptType, NULL }; + HINTERNET hi; + HINTERNET hic; + WCHAR *url; + RPC_STATUS status; + BOOL secure; + HttpTimerThreadData *timer_data; + HANDLE thread; + + TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint); + + if (Connection->server) + { + ERR("ncacn_http servers not supported yet\n"); + return RPC_S_SERVER_UNAVAILABLE; + } + + if (httpc->in_request) + return RPC_S_OK; + + status = UuidCreate(&httpc->connection_uuid); + status = UuidCreate(&httpc->in_pipe_uuid); + status = UuidCreate(&httpc->out_pipe_uuid); + + status = rpcrt4_http_internet_connect(httpc, &hi, &hic); + if (status != RPC_S_OK) + return status; + InternetCloseHandle(hi); + + url = HeapAlloc(GetProcessHeap(), 0, sizeof(wszRpcProxyPrefix) + (strlen(Connection->NetworkAddr) + 1 + strlen(Connection->Endpoint))*sizeof(WCHAR)); + if (!url) + { + InternetCloseHandle(hic); + return RPC_S_OUT_OF_MEMORY; + } + memcpy(url, wszRpcProxyPrefix, sizeof(wszRpcProxyPrefix)); + MultiByteToWideChar(CP_ACP, 0, Connection->NetworkAddr, -1, url+sizeof(wszRpcProxyPrefix)/sizeof(wszRpcProxyPrefix[0])-1, strlen(Connection->NetworkAddr)+1); + strcatW(url, wszColon); + MultiByteToWideChar(CP_ACP, 0, Connection->Endpoint, -1, url+strlenW(url), strlen(Connection->Endpoint)+1); + + secure = httpc->common.QOS && + (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) && + (httpc->common.QOS->qos->u.HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL); + + httpc->in_request = HttpOpenRequestW(hic, wszVerbIn, url, NULL, NULL, + wszAcceptTypes, + (secure ? INTERNET_FLAG_SECURE : 0)|INTERNET_FLAG_KEEP_CONNECTION|INTERNET_FLAG_PRAGMA_NOCACHE, + 0); + if (!httpc->in_request) + { + ERR("HttpOpenRequestW failed with error %d\n", GetLastError()); + InternetCloseHandle(hic); + return RPC_S_SERVER_UNAVAILABLE; + } + httpc->out_request = HttpOpenRequestW(hic, wszVerbOut, url, NULL, NULL, + wszAcceptTypes, + (secure ? INTERNET_FLAG_SECURE : 0)|INTERNET_FLAG_KEEP_CONNECTION|INTERNET_FLAG_PRAGMA_NOCACHE, + 0); + InternetCloseHandle(hic); + if (!httpc->in_request) + { + ERR("HttpOpenRequestW failed with error %d\n", GetLastError()); + InternetCloseHandle(httpc->in_request); + httpc->in_request = NULL; + return RPC_S_SERVER_UNAVAILABLE; + } + + status = rpcrt4_http_prepare_in_pipe(httpc->in_request, + &httpc->connection_uuid, + &httpc->in_pipe_uuid); + if (status != RPC_S_OK) + goto error; + + status = rpcrt4_http_prepare_out_pipe(httpc->out_request, &httpc->connection_uuid, + &httpc->out_pipe_uuid, + &httpc->flow_control_increment); + if (status != RPC_S_OK) + goto error; + + httpc->flow_control_mark = httpc->flow_control_increment / 2; + httpc->last_sent_time = GetTickCount(); + httpc->timer_cancelled = CreateEventW(NULL, FALSE, FALSE, NULL); + + timer_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*timer_data)); + timer_data->timer_param = httpc->in_request; + timer_data->last_sent_time = &httpc->last_sent_time; + timer_data->timer_cancelled = httpc->timer_cancelled; + /* FIXME: should use CreateTimerQueueTimer when implemented */ + thread = CreateThread(NULL, 0, rpcrt4_http_timer_thread, timer_data, 0, NULL); + CloseHandle(thread); + + return RPC_S_OK; + +error: + InternetCloseHandle(httpc->in_request); + httpc->in_request = NULL; + InternetCloseHandle(httpc->out_request); + httpc->out_request = NULL; + return status; +} + +static RPC_STATUS rpcrt4_ncacn_http_handoff(RpcConnection *old_conn, RpcConnection *new_conn) +{ + assert(0); + return RPC_S_SERVER_UNAVAILABLE; +} + +static int rpcrt4_ncacn_http_read(RpcConnection *Connection, + void *buffer, unsigned int count) +{ + RpcConnection_http *httpc = (RpcConnection_http *) Connection; + char *buf = buffer; + BOOL ret = TRUE; + unsigned int bytes_left = count; + + while (bytes_left) + { + DWORD bytes_read; + ret = InternetReadFile(httpc->out_request, buf, bytes_left, &bytes_read); + if (!ret || !bytes_read) + break; + bytes_left -= bytes_read; + buf += bytes_read; + } + TRACE("%p %p %u -> %s\n", httpc->out_request, buffer, count, ret ? "TRUE" : "FALSE"); + if (ret) httpc->bytes_received += count; + + TRACE("httpc->bytes_received = 0x%x\n", httpc->bytes_received); + /* FIXME: we should be more careful not to send this packet in the middle of receiving a fragment */ + if (httpc->bytes_received > httpc->flow_control_mark) + { + RpcPktHdr *hdr = RPCRT4_BuildHttpFlowControlHeader(httpc->common.server, + httpc->bytes_received, + httpc->flow_control_increment, + &httpc->out_pipe_uuid); + if (hdr) + { + DWORD bytes_written; + BOOL ret2; + TRACE("sending flow control packet at 0x%x\n", httpc->bytes_received); + ret2 = InternetWriteFile(httpc->in_request, hdr, hdr->common.frag_len, &bytes_written); + RPCRT4_FreeHeader(hdr); + if (ret2) + httpc->flow_control_mark = httpc->bytes_received + httpc->flow_control_increment / 2; + } + } + return ret ? count : -1; +} + +static int rpcrt4_ncacn_http_write(RpcConnection *Connection, + const void *buffer, unsigned int count) +{ + RpcConnection_http *httpc = (RpcConnection_http *) Connection; + DWORD bytes_written; + BOOL ret; + + httpc->last_sent_time = ~0UL; /* disable idle packet sending */ + ret = InternetWriteFile(httpc->in_request, buffer, count, &bytes_written); + httpc->last_sent_time = GetTickCount(); + TRACE("%p %p %u -> %s\n", httpc->in_request, buffer, count, ret ? "TRUE" : "FALSE"); + return ret ? bytes_written : -1; +} + +static int rpcrt4_ncacn_http_close(RpcConnection *Connection) +{ + RpcConnection_http *httpc = (RpcConnection_http *) Connection; + + TRACE("\n"); + + SetEvent(httpc->timer_cancelled); + if (httpc->in_request) + InternetCloseHandle(httpc->in_request); + httpc->in_request = NULL; + if (httpc->out_request) + InternetCloseHandle(httpc->out_request); + httpc->out_request = NULL; + + return 0; +} + +static size_t rpcrt4_ncacn_http_get_top_of_tower(unsigned char *tower_data, + const char *networkaddr, + const char *endpoint) +{ + return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr, + EPM_PROTOCOL_HTTP, endpoint); +} + +static RPC_STATUS rpcrt4_ncacn_http_parse_top_of_tower(const unsigned char *tower_data, + size_t tower_size, + char **networkaddr, + char **endpoint) +{ + return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size, + networkaddr, EPM_PROTOCOL_HTTP, + endpoint); +} + static const struct connection_ops conn_protseq_list[] = { { "ncacn_np", { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB }, @@ -1276,7 +1883,18 @@ static const struct connection_ops conn_protseq_list[] = { rpcrt4_conn_tcp_close, rpcrt4_ncacn_ip_tcp_get_top_of_tower, rpcrt4_ncacn_ip_tcp_parse_top_of_tower, - } + }, + { "ncacn_http", + { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP }, + rpcrt4_ncacn_http_alloc, + rpcrt4_ncacn_http_open, + rpcrt4_ncacn_http_handoff, + rpcrt4_ncacn_http_read, + rpcrt4_ncacn_http_write, + rpcrt4_ncacn_http_close, + rpcrt4_ncacn_http_get_top_of_tower, + rpcrt4_ncacn_http_parse_top_of_tower, + }, }; diff --git a/dlls/rpcrt4/rpcrt4.spec b/dlls/rpcrt4/rpcrt4.spec index c5498d7037a..f1425ce1325 100644 --- a/dlls/rpcrt4/rpcrt4.spec +++ b/dlls/rpcrt4/rpcrt4.spec @@ -148,8 +148,9 @@ @ stdcall NDRSContextUnmarshallEx(ptr ptr ptr) @ stub NDRcopy @ stdcall NdrAllocate(ptr long) -@ stub NdrAsyncClientCall +@ varargs NdrAsyncClientCall(ptr ptr) @ stub NdrAsyncServerCall +@ stdcall NdrAsyncStubCall(ptr ptr ptr ptr) @ stdcall NdrByteCountPointerBufferSize(ptr ptr ptr) @ stdcall NdrByteCountPointerFree(ptr ptr ptr) @ stdcall NdrByteCountPointerMarshall(ptr ptr ptr) diff --git a/dlls/rpcrt4/tests/ndr_marshall.c b/dlls/rpcrt4/tests/ndr_marshall.c index 41008221645..163ef9eaae6 100644 --- a/dlls/rpcrt4/tests/ndr_marshall.c +++ b/dlls/rpcrt4/tests/ndr_marshall.c @@ -32,6 +32,7 @@ #include "rpc.h" #include "rpcdce.h" #include "rpcproxy.h" +#include "oaidl.h" static int my_alloc_called; @@ -731,6 +732,283 @@ static void test_simple_struct(void) } } +static void test_complex_struct(void) +{ + RPC_MESSAGE RpcMessage; + MIDL_STUB_MESSAGE StubMsg; + MIDL_STUB_DESC StubDesc; + void *memsrc, *ptr; + FUNCDESC fd; + ELEMDESC params[2]; + TYPEDESC td[4]; + FUNCDESC *dst; + + static const unsigned char fmtstr_funcdesc[] = + { +/* 0 */ 0x11, 0x14, /* FC_RP [alloced_on_stack] */ +/* 2 */ NdrFcShort( 0x2 ), /* Offset= 2 (4) */ +/* 4 */ 0x13, 0x0, /* FC_OP */ +/* 6 */ NdrFcShort( 0xaa ), /* Offset= 170 (176) */ + +/** TYPEDESC union **/ +/* 8 */ 0x2b, /* FC_NON_ENCAPSULATED_UNION */ + 0x7, /* FC_USHORT */ +/* 10 */ 0x7, /* Corr desc: FC_USHORT */ + 0x0, /* */ +/* 12 */ NdrFcShort( 0x4 ), /* 4 */ +/* 14 */ NdrFcShort( 0x2 ), /* Offset= 2 (16) */ +/* 16 */ NdrFcShort( 0x4 ), /* 4 */ +/* 18 */ NdrFcShort( 0x4 ), /* 4 */ +/* 20 */ NdrFcLong( 0x1a ), /* 26 */ +/* 24 */ NdrFcShort( 0x16 ), /* Offset= 22 (46) */ +/* 26 */ NdrFcLong( 0x1b ), /* 27 */ +/* 30 */ NdrFcShort( 0x10 ), /* Offset= 16 (46) */ +/* 32 */ NdrFcLong( 0x1c ), /* 28 */ +/* 36 */ NdrFcShort( 0xe ), /* Offset= 14 (50) */ +/* 38 */ NdrFcLong( 0x1d ), /* 29 */ +/* 42 */ NdrFcShort( 0x8008 ), /* Simple arm type: FC_LONG */ +/* 44 */ NdrFcShort( 0x0 ), /* Offset= 0 */ +/* 46 */ 0x13, 0x0, /* FC_OP */ +/* 48 */ NdrFcShort( 0x24 ), /* Offset= 36 (84) */ +/* 50 */ 0x13, 0x0, /* FC_OP */ +/* 52 */ NdrFcShort( 0x10 ), /* Offset= 16 (68) */ + +/** ARRAYDESC carray **/ +/* 54 */ 0x1b, /* FC_CARRAY */ + 0x3, /* 3 */ +/* 56 */ NdrFcShort( 0x8 ), /* 8 */ +/* 58 */ 0x7, /* Corr desc: FC_USHORT */ + 0x0, /* */ +/* 60 */ NdrFcShort( 0xfffc ), /* -4 */ +/* 62 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 64 */ NdrFcShort( 0x92 ), /* Offset= 146 (210) */ +/* 66 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ + +/** ARRADESC **/ +/* 68 */ 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 70 */ NdrFcShort( 0x4 ), /* 4 */ +/* 72 */ NdrFcShort( 0xffffffee ), /* Offset= -18 (54) */ +/* 74 */ NdrFcShort( 0x0 ), /* Offset= 0 */ +/* 76 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 78 */ NdrFcShort( 0x6 ), /* Offset= 6 (84) */ +/* 80 */ 0x6, /* FC_SHORT */ + 0x3e, /* FC_STRUCTPAD2 */ +/* 82 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ + +/** TYPEDESC **/ +/* 84 */ 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 86 */ NdrFcShort( 0x8 ), /* 8 */ +/* 88 */ NdrFcShort( 0x0 ), /* 0 */ +/* 90 */ NdrFcShort( 0x0 ), /* Offset= 0 */ +/* 92 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 94 */ NdrFcShort( 0xffffffaa ), /* Offset= -86 (8) */ +/* 96 */ 0x6, /* FC_SHORT */ + 0x3e, /* FC_STRUCTPAD2 */ +/* 98 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ + +/** PARAMDESCEX **/ + +/* 100 */ 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 102 */ NdrFcShort( 0x18 ), /* 24 */ +/* 104 */ NdrFcShort( 0x0 ), /* 0 */ +/* 106 */ NdrFcShort( 0x0 ), /* Offset= 0 */ +/* 108 */ 0x8, /* FC_LONG */ + 0x4c, /* FC_EMBEDDED_COMPLEX */ +/* 110 */ 0x4, /* 4 */ + NdrFcShort( 0xffffff01 ), /* Offset= -255 (1110) */ /* FIXME!! */ + 0x5b, /* FC_END */ + + +/** PARAMDESC **/ +/* 114 */ 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 116 */ NdrFcShort( 0x8 ), /* 8 */ +/* 118 */ NdrFcShort( 0x0 ), /* 0 */ +/* 120 */ NdrFcShort( 0x6 ), /* Offset= 6 (126) */ +/* 122 */ 0x36, /* FC_POINTER */ + 0x6, /* FC_SHORT */ +/* 124 */ 0x3e, /* FC_STRUCTPAD2 */ + 0x5b, /* FC_END */ +/* 126 */ + 0x13, 0x0, /* FC_OP */ +/* 128 */ NdrFcShort( 0xffffffe4 ), /* Offset= -28 (100) */ + +/** ELEMDESC **/ +/* 130 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 132 */ NdrFcShort( 0x10 ), /* 16 */ +/* 134 */ NdrFcShort( 0x0 ), /* 0 */ +/* 136 */ NdrFcShort( 0x0 ), /* 0 */ +/* 138 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 140 */ NdrFcShort( 0xffffffc8 ), /* Offset= -56 (84) */ +/* 142 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 144 */ NdrFcShort( 0xffffffe2 ), /* Offset= -30 (114) */ +/* 146 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ + + +/* 148 */ + 0x1b, /* FC_CARRAY */ + 0x3, /* 3 */ +/* 150 */ NdrFcShort( 0x4 ), /* 4 */ +/* 152 */ 0x16, /* Corr desc: field pointer, FC_SHORT */ + 0x0, /* */ +/* 154 */ NdrFcShort( 0x1e ), /* 30 */ +/* 156 */ 0x8, /* FC_LONG */ + 0x5b, /* FC_END */ + +/* 158 */ + 0x21, /* FC_BOGUS_ARRAY */ + 0x3, /* 3 */ +/* 160 */ NdrFcShort( 0x0 ), /* 0 */ +/* 162 */ 0x16, /* Corr desc: field pointer, FC_SHORT */ + 0x0, /* */ +/* 164 */ NdrFcShort( 0x18 ), /* 24 */ +/* 166 */ NdrFcLong( 0xffffffff ), /* -1 */ +/* 170 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 172 */ NdrFcShort( 0xffffffd6 ), /* Offset= -42 (130) */ +/* 174 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/** FUNCDESC **/ +/* 176 */ 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 178 */ NdrFcShort( 0x34 ), /* 52 */ +/* 180 */ NdrFcShort( 0x0 ), /* 0 */ +/* 182 */ NdrFcShort( 0x14 ), /* Offset= 20 (202) */ +/* 184 */ 0x8, /* FC_LONG */ + 0x36, /* FC_POINTER */ +/* 186 */ 0x36, /* FC_POINTER */ + 0xe, /* FC_ENUM32 */ +/* 188 */ 0xe, /* FC_ENUM32 */ + 0xe, /* FC_ENUM32 */ +/* 190 */ 0x6, /* FC_SHORT */ + 0x6, /* FC_SHORT */ +/* 192 */ 0x6, /* FC_SHORT */ + 0x6, /* FC_SHORT */ +/* 194 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 196 */ NdrFcShort( 0xffffffbe ), /* Offset= -66 (130) */ +/* 198 */ 0x6, /* FC_SHORT */ + 0x3e, /* FC_STRUCTPAD2 */ +/* 200 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 202 */ + 0x13, 0x0, /* FC_OP */ +/* 204 */ NdrFcShort( 0xffffffc8 ), /* Offset= -56 (148) */ +/* 206 */ + 0x13, 0x0, /* FC_OP */ +/* 208 */ NdrFcShort( 0xffffffce ), /* Offset= -50 (158) */ + +/** SAFEARRAYBOUND **/ +/* 210 */ + 0x15, /* FC_STRUCT */ + 0x3, /* 3 */ +/* 212 */ NdrFcShort( 0x8 ), /* 8 */ +/* 214 */ 0x8, /* FC_LONG */ + 0x8, /* FC_LONG */ +/* 216 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ + }; + + StubDesc = Object_StubDesc; + StubDesc.pFormatTypes = fmtstr_funcdesc; + + memsrc = &fd; + memset(&fd, 0, sizeof(fd)); + + fd.memid = 0xcafebabe; + fd.lprgscode = NULL; + fd.lprgelemdescParam = params; + params[0].tdesc.vt = VT_PTR; + U(params[0].tdesc).lptdesc = &td[0]; + U(params[0].tdesc).lptdesc->vt = VT_SAFEARRAY; + U(*U(params[0].tdesc).lptdesc).lptdesc = &td[1]; + U(*U(params[0].tdesc).lptdesc).lptdesc->vt = VT_R8; + U(params[0]).paramdesc.pparamdescex = NULL; + U(params[0]).paramdesc.wParamFlags = 0xbeef; + + params[1].tdesc.vt = VT_I4; + /* U(params[1].tdesc).vt = VT_PTR; + U(params[1].tdesc).lptdesc = &td[2]; + U(params[1].tdesc).lptdesc->vt = VT_SAFEARRAY; + U(*U(params[1].tdesc).lptdesc).lptdesc = &td[3]; + U(*U(params[1].tdesc).lptdesc).lptdesc->vt = VT_R8;*/ + U(params[1]).paramdesc.pparamdescex = NULL; + U(params[1]).paramdesc.wParamFlags = 0xdead; + fd.funckind = 0; + fd.invkind = 1; + fd.callconv = 4; + fd.cParams = 2; + fd.cParamsOpt = 0; + fd.oVft = 8; + fd.cScodes = 0; + fd.elemdescFunc.tdesc.vt = VT_R8; + U(fd.elemdescFunc).paramdesc.pparamdescex = NULL; + U(fd.elemdescFunc).paramdesc.wParamFlags = 0xcafe; + fd.wFuncFlags = 0; + + NdrClientInitializeNew(&RpcMessage, &StubMsg, &StubDesc, 0); + + StubMsg.BufferLength = 0; + StubMsg.PointerLength = 0; + + NdrComplexStructBufferSize( &StubMsg, (unsigned char *)memsrc, fmtstr_funcdesc + 176 ); + ok(StubMsg.BufferLength >= 96, "buffer size %d\n", StubMsg.BufferLength); + + StubMsg.RpcMsg->Buffer = StubMsg.BufferStart = StubMsg.Buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, StubMsg.BufferLength); + StubMsg.BufferEnd = StubMsg.BufferStart + StubMsg.BufferLength; + + ptr = NdrComplexStructMarshall( &StubMsg, memsrc, fmtstr_funcdesc + 176 ); + + ok(StubMsg.Buffer - StubMsg.BufferStart == 96, "marshaled length %d\n", StubMsg.Buffer - StubMsg.BufferStart); + + /* Compare upto the first embedded union (elemdescFunc) */ + ok(!memcmp(StubMsg.BufferStart, &fd, 32), "top level differ\n"); + /* discriminant */ + ok(!memcmp(StubMsg.BufferStart + 32, &fd.elemdescFunc.tdesc.vt, sizeof(short)), "discrimants differ\n"); + /* now the vt itself */ + ok(!memcmp(StubMsg.BufferStart + 34, &fd.elemdescFunc.tdesc.vt, sizeof(short)), "vts differ\n"); + /* paramdesc */ + ok(!memcmp(StubMsg.BufferStart + 36, &U(fd.elemdescFunc).paramdesc, sizeof(PARAMDESC)), "paramdesc differ\n"); + /* param array discrim */ + ok(!memcmp(StubMsg.BufferStart + 44, &fd.cParams, sizeof(short)), "param array discrim differs\n"); + + ok(!memcmp(StubMsg.BufferStart + 48, ¶ms[0].tdesc.vt, sizeof(short)), "param[0] first vt differ\n"); + ok(!memcmp(StubMsg.BufferStart + 52, ¶ms[0].tdesc, 6), "param[0] first tdesc differ\n"); + ok(!memcmp(StubMsg.BufferStart + 60, &U(params[0]).paramdesc, 6), "param[0] paramdesc differ\n"); + + ok(!memcmp(StubMsg.BufferStart + 68, ¶ms[1].tdesc.vt, sizeof(short)), "param[1] first vt differ\n"); + ok(!memcmp(StubMsg.BufferStart + 70, ¶ms[1].tdesc.vt, sizeof(short)), "param[1] first tdesc differ\n"); + ok(!memcmp(StubMsg.BufferStart + 72, &U(params[1]).paramdesc, 6), "param[1] paramdesc differ\n"); + + ok(!memcmp(StubMsg.BufferStart + 80, &U(params[0].tdesc).lptdesc->vt, sizeof(short)), "param[0] 2nd vt differ\n"); + ok(!memcmp(StubMsg.BufferStart + 84, U(params[0].tdesc).lptdesc, 6), "param[0] 2nd tdesc differ\n"); + + ok(!memcmp(StubMsg.BufferStart + 92, &U(*U(params[0].tdesc).lptdesc).lptdesc->vt, sizeof(short)), "param[0] 3rd vt differ\n"); + ok(!memcmp(StubMsg.BufferStart + 94, &U(*U(params[0].tdesc).lptdesc).lptdesc->vt, 2), "param[0] 3rd tdesc differ\n"); + + StubMsg.Buffer = StubMsg.BufferStart; + StubMsg.MemorySize = 0; + + dst = HeapAlloc(GetProcessHeap(), 0, 1000); + NdrComplexStructUnmarshall( &StubMsg, (void*)&dst, fmtstr_funcdesc + 176, 1); + ok(dst->cParams == fd.cParams, "params not right\n"); + ok(U(*U(dst->lprgelemdescParam[0].tdesc).lptdesc).lptdesc->vt == U(*U(params[0].tdesc).lptdesc).lptdesc->vt, "param[0] tdesc differ\n"); +} + static void test_fullpointer_xlat(void) { PFULL_PTR_XLAT_TABLES pXlatTables; @@ -1104,6 +1382,7 @@ START_TEST( ndr_marshall ) test_ndr_simple_type(); test_simple_types(); test_simple_struct(); + test_complex_struct(); test_fullpointer_xlat(); test_client_init(); test_ndr_allocate(); diff --git a/dlls/sane.ds/capability.c b/dlls/sane.ds/capability.c index 6d237db83dd..61131e7a07f 100644 --- a/dlls/sane.ds/capability.c +++ b/dlls/sane.ds/capability.c @@ -69,7 +69,6 @@ TW_UINT16 SANE_SaneCapability (pTW_CAPABILITY pCapability, TW_UINT16 action) case ICAP_PLANARCHUNKY: case ICAP_BITORDERCODES: case ICAP_CCITTKFACTOR: - case ICAP_COMPRESSION: case ICAP_JPEGPIXELTYPE: /*case ICAP_JPEGQUALITY:*/ case ICAP_PIXELFLAVORCODES: @@ -86,7 +85,6 @@ TW_UINT16 SANE_SaneCapability (pTW_CAPABILITY pCapability, TW_UINT16 action) case ICAP_OVERSCAN: case ICAP_PHYSICALHEIGHT: case ICAP_PHYSICALWIDTH: - case ICAP_UNITS: case ICAP_ZOOMFACTOR: case CAP_PRINTER: case CAP_PRINTERENABLED: @@ -112,7 +110,6 @@ TW_UINT16 SANE_SaneCapability (pTW_CAPABILITY pCapability, TW_UINT16 action) case ICAP_CUSTHALFTONE: case ICAP_HALFTONES: case ICAP_PIXELFLAVOR: - case ICAP_PIXELTYPE: case ICAP_THRESHOLD: case CAP_LANGUAGE: case ICAP_FRAMES: @@ -146,12 +143,14 @@ TW_UINT16 SANE_SaneCapability (pTW_CAPABILITY pCapability, TW_UINT16 action) case ICAP_YRESOLUTION: twCC = TWCC_CAPUNSUPPORTED; break; + case ICAP_COMPRESSION: + case ICAP_PIXELTYPE: + case ICAP_UNITS: case CAP_XFERCOUNT: - /* This is a required capability that every source need to - support but we havev't implemented yet. */ + /* These are required capabilities that every source needs to + support but we haven't implemented yet. */ twCC = TWCC_SUCCESS; break; - /*case ICAP_COMPRESSION:*/ case ICAP_IMAGEFILEFORMAT: case ICAP_TILES: twCC = TWCC_CAPUNSUPPORTED; diff --git a/dlls/secur32/dispatcher.c b/dlls/secur32/dispatcher.c index 5d821727313..3f424a44bc0 100644 --- a/dlls/secur32/dispatcher.c +++ b/dlls/secur32/dispatcher.c @@ -264,7 +264,7 @@ void cleanup_helper(PNegoHelper helper) close(helper->pipe_out); close(helper->pipe_in); - waitpid(helper->helper_pid, NULL, 0); + kill(helper->helper_pid, SIGTERM); helper->helper_pid = 0; HeapFree(GetProcessHeap(), 0, helper); diff --git a/dlls/secur32/ntlm.c b/dlls/secur32/ntlm.c index 574483027ac..00c9821bfb5 100644 --- a/dlls/secur32/ntlm.c +++ b/dlls/secur32/ntlm.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "windef.h" #include "winbase.h" #include "winnls.h" @@ -38,7 +39,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(secur32); #define MIN_NTLM_AUTH_MINOR_VERSION 0 #define MIN_NTLM_AUTH_MICRO_VERSION 25 -static CHAR ntlm_auth[] = "ntlm_auth"; +static CHAR ntlm_auth[256]; /*********************************************************************** * QueryCredentialsAttributesA @@ -1748,6 +1749,8 @@ void SECUR32_initNTLMSP(void) version, NULL }; + strcpy(ntlm_auth, "ntlm_auth"); + if((ret = fork_helper(&helper, ntlm_auth, args)) != SEC_E_OK) { /* Cheat and allocate a helper anyway, so cleanup later will work. */ @@ -1757,6 +1760,33 @@ void SECUR32_initNTLMSP(void) else check_version(helper); + /* CodeWeavers feature: fall back to our shipped ntlm_auth if a suitable + * system version isn't found */ + if( ((helper->major < MIN_NTLM_AUTH_MAJOR_VERSION) || + (helper->major == MIN_NTLM_AUTH_MAJOR_VERSION && + helper->minor < MIN_NTLM_AUTH_MINOR_VERSION) || + (helper->major == MIN_NTLM_AUTH_MAJOR_VERSION && + helper->minor == MIN_NTLM_AUTH_MINOR_VERSION && + helper->micro < MIN_NTLM_AUTH_MICRO_VERSION)) && + getenv("CX_ROOT") ) + { + cleanup_helper(helper); + + TRACE("falling back to CrossOver version of ntlm_auth\n"); + + strcpy(ntlm_auth, getenv("CX_ROOT")); + strcat(ntlm_auth, "/bin/cxntlm_auth"); + + if((ret = fork_helper(&helper, ntlm_auth, args)) != SEC_E_OK) + { + /* Cheat and allocate a helper anyway, so cleanup later will work. */ + helper = HeapAlloc(GetProcessHeap(),0, sizeof(PNegoHelper)); + helper->major = helper->minor = helper->micro = -1; + } + else + check_version(helper); + } + if( (helper->major > MIN_NTLM_AUTH_MAJOR_VERSION) || (helper->major == MIN_NTLM_AUTH_MAJOR_VERSION && helper->minor > MIN_NTLM_AUTH_MINOR_VERSION) || diff --git a/dlls/setupapi/Makefile.in b/dlls/setupapi/Makefile.in index 3ecbddf6062..5f468b82dab 100644 --- a/dlls/setupapi/Makefile.in +++ b/dlls/setupapi/Makefile.in @@ -6,8 +6,9 @@ VPATH = @srcdir@ MODULE = setupapi.dll IMPORTLIB = libsetupapi.$(IMPLIBEXT) IMPORTS = user32 version advapi32 rpcrt4 kernel32 ntdll -DELAYIMPORTS = shell32 +DELAYIMPORTS = ole32 shell32 EXTRALIBS = -luuid +EXTRAINCL = -I../../../libusb C_SRCS = \ devinst.c \ @@ -21,7 +22,8 @@ C_SRCS = \ queue.c \ setupcab.c \ stringtable.c \ - stubs.c + stubs.c \ + usbdevice.c C_SRCS16 = \ devinst16.c \ diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c index e2a2dfec62d..7fd4ba01791 100644 --- a/dlls/setupapi/devinst.c +++ b/dlls/setupapi/devinst.c @@ -2,6 +2,7 @@ * SetupAPI device installer * * Copyright 2000 Andreas Mohr for CodeWeavers + * 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 @@ -39,7 +40,7 @@ #include "winioctl.h" #include "rpc.h" #include "rpcdce.h" - +#include "dbt.h" #include "setupapi_private.h" @@ -661,8 +662,8 @@ SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid, PCWSTR MachineName, PVOID Reserved) { - struct DeviceInfoSet *list = NULL; - DWORD size = sizeof(struct DeviceInfoSet); + devinfo_struct *list = NULL; + DWORD size = sizeof(devinfo_struct); TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent, debugstr_w(MachineName), Reserved); @@ -687,6 +688,7 @@ SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid, return (HDEVINFO)INVALID_HANDLE_VALUE; } + memset(list,0,sizeof(devinfo_struct)); list->magic = SETUP_DEVICE_INFO_SET_MAGIC; list->hwndParent = hwndParent; memcpy(&list->ClassGuid, @@ -697,6 +699,34 @@ SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid, } /*********************************************************************** + * SetupDiDestroyDeviceInfoList (SETUPAPI.@) + */ +BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo) +{ + devinfo_struct *info = (devinfo_struct*)devinfo; + + TRACE("%p\n", devinfo); + + if (!info) + return TRUE; + + if (info->count > 0) + { + int i; + for (i = 0; i < info->count; i++) + { + if (info->devices[i].hardwareid) + HeapFree(GetProcessHeap(),0,info->devices[i].hardwareid); + } + HeapFree(GetProcessHeap(),0,info->devices); + } + + HeapFree(GetProcessHeap(),0,info); + + return TRUE; +} + +/*********************************************************************** * SetupDiCreateDeviceInfoA (SETUPAPI.@) */ BOOL WINAPI SetupDiCreateDeviceInfoA( @@ -765,15 +795,69 @@ BOOL WINAPI SetupDiEnumDeviceInfo( DWORD index, PSP_DEVINFO_DATA info) { - FIXME("%p %d %p\n", devinfo, index, info); + DWORD rc; + devinfo_struct *tree = (devinfo_struct*)devinfo; + + TRACE("%p %d %p\n", devinfo, index, info ); if(info==NULL) return FALSE; if(info->cbSize < sizeof(*info)) return FALSE; + if (tree == NULL) + return FALSE; - SetLastError(ERROR_NO_MORE_ITEMS); - return FALSE; + if (index >= tree->count) + { + SetLastError(ERROR_NO_MORE_ITEMS); + return FALSE; + } + + memcpy(&(info->ClassGuid),&(tree->devices[index].guid),sizeof(GUID)); + info->Reserved = (ULONG_PTR)&(tree->devices[index]); + + /* + * Used by cfgmgr32... this is BAD BAD not threadsafe + * also it should be a handle that can be used to retrieve data like this + * not the straight up data.... but this hack works for the ipod + */ + tree->devices[index].registry_fn(&(tree->devices[index]), SPDRP_DEVICE_ID, + NULL, NULL, 0, &rc, FALSE); + info->DevInst = (DWORD)(tree->devices[index].deviceId); + + return TRUE; +} + +/*********************************************************************** + * SetupDiEnumDeviceInterfaces (SETUPAPI.@) + */ +BOOL WINAPI SetupDiEnumDeviceInterfaces( + HDEVINFO DeviceInfoSet, + PSP_DEVINFO_DATA DeviceInfoData, + CONST GUID * InterfaceClassGuid, + DWORD MemberIndex, + PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData) +{ + devinfo_struct *tree = (devinfo_struct*)DeviceInfoSet; + + TRACE("(%p, %p, %s, %i %p\n",DeviceInfoSet, DeviceInfoData, + debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData); + + if (!tree) + return FALSE; + + if (MemberIndex >= tree->count) + { + SetLastError(ERROR_NO_MORE_ITEMS); + return FALSE; + } + + memcpy(&(DeviceInterfaceData->InterfaceClassGuid), + &(tree->devices[MemberIndex].guid),sizeof(GUID)); + DeviceInterfaceData->Flags = tree->devices[MemberIndex].flags; + DeviceInterfaceData->Reserved = (ULONG_PTR)&(tree->devices[MemberIndex]); + + return TRUE; } /*********************************************************************** @@ -979,25 +1063,25 @@ HDEVINFO WINAPI SetupDiGetClassDevsA( HWND parent, DWORD flags) { - HDEVINFO ret; - LPWSTR enumstrW = NULL; + devinfo_struct *info; - if (enumstr) - { - int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0); - enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); - if (!enumstrW) - { - ret = (HDEVINFO)INVALID_HANDLE_VALUE; - goto end; - } - MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len); - } - ret = SetupDiGetClassDevsW(class, enumstrW, parent, flags); - HeapFree(GetProcessHeap(), 0, enumstrW); + TRACE("%s %s %p %08x\n",debugstr_guid(class),enumstr,parent,flags); -end: - return ret; + /* TODO: make this thread safe*/ + info = HeapAlloc(GetProcessHeap(),0,sizeof(devinfo_struct)); + memset(info,0,sizeof(devinfo_struct)); + info->flags = flags; + info->unicode = FALSE; + /* setting the winehq structure members */ + info->magic = SETUP_DEVICE_INFO_SET_MAGIC; + info->hwndParent = parent; + memcpy(&info->ClassGuid, + class ? class: &GUID_NULL, + sizeof(info->ClassGuid)); + + USB_GetDeviceDevs(info,class,enumstr); + + return (HDEVINFO)info; } /*********************************************************************** @@ -1033,68 +1117,6 @@ HDEVINFO WINAPI SetupDiGetClassDevsExW( } /*********************************************************************** - * SetupDiEnumDeviceInterfaces (SETUPAPI.@) - */ -BOOL WINAPI SetupDiEnumDeviceInterfaces( - HDEVINFO devinfo, - PSP_DEVINFO_DATA DeviceInfoData, - CONST GUID * InterfaceClassGuid, - DWORD MemberIndex, - PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData) -{ - BOOL ret = FALSE; - - FIXME("%p, %p, %s, 0x%08x, %p\n", devinfo, DeviceInfoData, - debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData); - - if (devinfo && devinfo != (HDEVINFO)INVALID_HANDLE_VALUE) - { - struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo; - if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC) - SetLastError(ERROR_NO_MORE_ITEMS); - else - SetLastError(ERROR_INVALID_HANDLE); - } - else - SetLastError(ERROR_INVALID_HANDLE); - return ret; -} - -/*********************************************************************** - * SetupDiDestroyDeviceInfoList (SETUPAPI.@) - * - * Destroy a DeviceInfoList and free all used memory of the list. - * - * PARAMS - * devinfo [I] DeviceInfoList pointer to list to destroy - * - * RETURNS - * Success: non zero value. - * Failure: zero value. - */ -BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo) -{ - BOOL ret = FALSE; - - TRACE("%p\n", devinfo); - if (devinfo && devinfo != (HDEVINFO)INVALID_HANDLE_VALUE) - { - struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo; - - if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC) - { - HeapFree(GetProcessHeap(), 0, list); - ret = TRUE; - } - } - - if (ret == FALSE) - SetLastError(ERROR_INVALID_HANDLE); - - return ret; -} - -/*********************************************************************** * SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@) */ BOOL WINAPI SetupDiGetDeviceInterfaceDetailA( @@ -1105,14 +1127,18 @@ BOOL WINAPI SetupDiGetDeviceInterfaceDetailA( PDWORD RequiredSize, PSP_DEVINFO_DATA DeviceInfoData) { - BOOL ret = FALSE; + devnode *node = (devnode*)DeviceInterfaceData->Reserved; - FIXME("(%p, %p, %p, %d, %p, %p)\n", DeviceInfoSet, - DeviceInterfaceData, DeviceInterfaceDetailData, - DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData); + FIXME("%p %p %p %i %p %p\n",DeviceInfoSet, DeviceInterfaceData, + DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize, + RequiredSize, DeviceInfoData); - SetLastError(ERROR_INVALID_HANDLE); - return ret; + node->registry_fn(node, SPDRP_DEVICE_PATH, NULL, + (LPBYTE)DeviceInterfaceDetailData->DevicePath, + DeviceInterfaceDetailDataSize, RequiredSize, FALSE); + + SetLastError(0); + return TRUE; } /*********************************************************************** @@ -1126,9 +1152,7 @@ BOOL WINAPI SetupDiGetDeviceInterfaceDetailW( PDWORD RequiredSize, PSP_DEVINFO_DATA DeviceInfoData) { - FIXME("(%p, %p, %p, %d, %p, %p): stub\n", DeviceInfoSet, - DeviceInterfaceData, DeviceInterfaceDetailData, - DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData); + FIXME("\n"); return FALSE; } @@ -1144,10 +1168,17 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyA( DWORD PropertyBufferSize, PDWORD RequiredSize) { - FIXME("%04x %p %d %p %p %d %p\n", (DWORD)devinfo, DeviceInfoData, + devnode *node = (devnode*)DeviceInfoData->Reserved; + + TRACE("%p %p %d %p %p %d %p\n", devinfo, DeviceInfoData, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize); - return FALSE; + + if (!node) + return FALSE; + + return (BOOL)node->registry_fn(node, Property, PropertyRegDataType, + PropertyBuffer, PropertyBufferSize, RequiredSize, FALSE); } /*********************************************************************** @@ -1496,7 +1527,7 @@ BOOL WINAPI SetupDiSetClassInstallParamsA( { FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData, ClassInstallParams->InstallFunction, ClassInstallParamsSize); - return FALSE; + return TRUE; } /*********************************************************************** @@ -1508,7 +1539,7 @@ BOOL WINAPI SetupDiCallClassInstaller( PSP_DEVINFO_DATA DeviceInfoData) { FIXME("%d %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData); - return FALSE; + return TRUE; } /*********************************************************************** @@ -1520,7 +1551,7 @@ BOOL WINAPI SetupDiGetDeviceInstallParamsA( PSP_DEVINSTALL_PARAMS_A DeviceInstallParams) { FIXME("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams); - return FALSE; + return TRUE; } /*********************************************************************** diff --git a/dlls/setupapi/dirid.c b/dlls/setupapi/dirid.c index 89f92fd2c3b..12b671a4ca5 100644 --- a/dlls/setupapi/dirid.c +++ b/dlls/setupapi/dirid.c @@ -94,6 +94,7 @@ static const WCHAR *create_system_dirid( int dirid ) case DIRID_WINDOWS: GetWindowsDirectoryW( buffer, MAX_PATH ); break; + case 13: /* DIRID_SYSTEM32 ? - used by IE6 install */ case DIRID_SYSTEM: GetSystemDirectoryW( buffer, MAX_PATH ); break; diff --git a/dlls/setupapi/setupapi_private.h b/dlls/setupapi/setupapi_private.h index 32f1661e247..3e2ab686fd8 100644 --- a/dlls/setupapi/setupapi_private.h +++ b/dlls/setupapi/setupapi_private.h @@ -67,6 +67,53 @@ UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification, UINT_PTR, U #define _S_IWRITE 0x0080 #define _S_IREAD 0x0100 +typedef BOOL WINAPI *device_registry_fn ( + LPVOID node, + DWORD Property, + PDWORD PropertyRegDataType, + PBYTE PropertyBuffer, + DWORD PropertyBufferSize, + PDWORD RequiredSize, + BOOL unicode); + +typedef struct devnode_tag{ + WCHAR enumerator[20]; + WCHAR devicePath[MAX_PATH*2]; + DWORD flags; + GUID guid; + WCHAR vendor[20]; + DWORD iVendor; + WCHAR product[20]; + DWORD iProduct; + WCHAR revision[5]; + WCHAR serial[50]; + WCHAR devicetype[20]; + WCHAR deviceId[MAX_PATH]; + LPWSTR hardwareid; + LPVOID reserved; + device_registry_fn *registry_fn; +} devnode; + +typedef struct devinfo_struct_tag { +/* from the winehq structure */ + DWORD magic; + GUID ClassGuid; + HWND hwndParent; +/* our Crossover structure */ + DWORD flags; + BOOL unicode; + int count; + devnode *devices; +} devinfo_struct; + +/* some custome device properties */ +#define SPDRP_DEVICE_PATH (SPDRP_MAXIMUM_PROPERTY + 1) +#define SPDRP_DEVICEINST (SPDRP_MAXIMUM_PROPERTY + 2) +#define SPDRP_DEVICE_ID (SPDRP_MAXIMUM_PROPERTY + 3) + +UINT USB_GetDeviceDevs(devinfo_struct *devinfo, CONST GUID *class, + LPCSTR enumstr); + extern OSVERSIONINFOW OsVersionInfo; extern BOOL create_fake_dll( const WCHAR *name, const WCHAR *source ); diff --git a/dlls/shdocvw/Makefile.in b/dlls/shdocvw/Makefile.in index 78e87209e3e..04adadf66d2 100644 --- a/dlls/shdocvw/Makefile.in +++ b/dlls/shdocvw/Makefile.in @@ -33,4 +33,6 @@ IDL_TLB_SRCS = shdocvw_v1.idl @MAKE_DLL_RULES@ +shdocvw.res: shdocvw.inf + @DEPENDENCIES@ # everything below this line is overwritten by make depend diff --git a/dlls/shdocvw/dochost.c b/dlls/shdocvw/dochost.c index f26447d1681..7391239b29d 100644 --- a/dlls/shdocvw/dochost.c +++ b/dlls/shdocvw/dochost.c @@ -496,6 +496,7 @@ void DocHost_Init(DocHost *This, IDispatch *disp) This->frame_hwnd = NULL; This->url = NULL; + This->navigate_call = FALSE; This->silent = VARIANT_FALSE; This->offline = VARIANT_FALSE; diff --git a/dlls/shdocvw/navigate.c b/dlls/shdocvw/navigate.c index 161c138dae4..9e80b9d25f3 100644 --- a/dlls/shdocvw/navigate.c +++ b/dlls/shdocvw/navigate.c @@ -317,7 +317,7 @@ static IBindStatusCallback *create_callback(DocHost *This, PBYTE post_data, return BINDSC(ret); } -static void on_before_navigate2(DocHost *This, LPWSTR url, PBYTE post_data, ULONG post_data_len, +static void on_before_navigate2(DocHost *This, LPCWSTR url, PBYTE post_data, ULONG post_data_len, LPWSTR headers, VARIANT_BOOL *cancel) { VARIANT var_url, var_flags, var_frame_name, var_post_data, var_post_data2, var_headers; @@ -434,6 +434,7 @@ static HRESULT navigate(DocHost *This, IMoniker *mon, IBindCtx *bindctx) * This should be fixed when mshtml.dll and urlmon.dll will be good enough. */ + /* FIXME: We shouldn't have this if and return here, but it's needed for Picasa */ if(This->document) deactivate_document(This); @@ -490,6 +491,12 @@ static HRESULT bind_url_to_object(DocHost *This, LPCWSTR url, PBYTE post_data, U VARIANT_BOOL cancel = VARIANT_FALSE; HRESULT hres; + if(!This->navigate_call) { + This->navigate_call = TRUE; + on_before_navigate2(This, url, post_data, post_data_len, headers, &cancel); + This->navigate_call = FALSE; + } + if(!This->hwnd) create_doc_view_hwnd(This); @@ -597,11 +604,19 @@ static HRESULT navigate_hlink(DocHost *This, IMoniker *mon, IBindCtx *bindctx, CoTaskMemFree(headers); ReleaseBindInfo(&bindinfo); + /* + * FIXME, HACK + * We should cancel navigation here, but for some reason Quicken always + * sets this cancel flag. Until we find the reason, we never cancel + * navigation. + */ +#if 0 if(cancel) { FIXME("navigation canceled\n"); CoTaskMemFree(url); return S_OK; } +#endif /* FIXME: We should do it after BindToObject call */ if(try_application_url(url)) diff --git a/dlls/shdocvw/regsvr.c b/dlls/shdocvw/regsvr.c index c8cd8149400..be7a461dc31 100644 --- a/dlls/shdocvw/regsvr.c +++ b/dlls/shdocvw/regsvr.c @@ -26,6 +26,7 @@ #include "winuser.h" #include "winreg.h" #include "winerror.h" +#include "advpub.h" #include "shdocvw.h" @@ -668,7 +669,7 @@ static struct regsvr_coclass const coclass_list[] = { }, { &CLSID_Internet, - "Internet Explorer", + NULL, /* IE shortcut creation depends on this not being "Internet Explorer" */ NULL, "shdocvw.dll", "Apartment", @@ -726,6 +727,24 @@ err: return (res == ERROR_SUCCESS) ? S_OK : E_FAIL; } +static HRESULT register_inf(BOOL do_register) +{ + HRESULT hres; + HMODULE hAdvpack; + typeof(RegInstallA) *pRegInstall; + + static const WCHAR wszAdvpack[] = {'a','d','v','p','a','c','k','.','d','l','l',0}; + + TRACE("(%x)\n", do_register); + + hAdvpack = LoadLibraryW(wszAdvpack); + pRegInstall = (typeof(RegInstallA)*)GetProcAddress(hAdvpack, "RegInstall"); + + hres = pRegInstall(shdocvw_hinstance, do_register ? "RegisterDll" : "UnregisterDll", NULL); + + return hres; +} + static HRESULT register_typelib(void) { ITypeLib *typelib; @@ -763,6 +782,8 @@ HRESULT WINAPI DllRegisterServer(void) hr = register_interfaces(interface_list); if (SUCCEEDED(hr)) hr = register_localserver(); + if (SUCCEEDED(hr)) + hr = register_inf(TRUE); if(SUCCEEDED(hr)) hr = register_typelib(); @@ -781,6 +802,8 @@ HRESULT WINAPI DllUnregisterServer(void) hr = unregister_coclasses(coclass_list); if (SUCCEEDED(hr)) hr = unregister_interfaces(interface_list); + if (SUCCEEDED(hr)) + hr = register_inf(FALSE); if(SUCCEEDED(hr)) hr = unregister_typelib(); diff --git a/dlls/shdocvw/shdocvw.h b/dlls/shdocvw/shdocvw.h index 57041564a2b..125dbda795a 100644 --- a/dlls/shdocvw/shdocvw.h +++ b/dlls/shdocvw/shdocvw.h @@ -90,6 +90,8 @@ typedef struct { VARIANT_BOOL offline; ConnectionPointContainer cps; + + BOOL navigate_call; } DocHost; struct WebBrowser { diff --git a/dlls/shdocvw/shdocvw.rc b/dlls/shdocvw/shdocvw.rc index a81b509d156..6a6bfd2721b 100644 --- a/dlls/shdocvw/shdocvw.rc +++ b/dlls/shdocvw/shdocvw.rc @@ -19,4 +19,7 @@ #include "version.rc" LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL + +REGINST REGINST shdocvw.inf + 1 TYPELIB LOADONCALL DISCARDABLE shdocvw_v1.tlb diff --git a/dlls/shell32/Makefile.in b/dlls/shell32/Makefile.in index 052027650bd..3afdb4ac8fb 100644 --- a/dlls/shell32/Makefile.in +++ b/dlls/shell32/Makefile.in @@ -25,6 +25,7 @@ C_SRCS = \ enumidlist.c \ folders.c \ iconcache.c \ + memorystream.c \ pidl.c \ recyclebin.c \ regsvr.c \ @@ -38,6 +39,7 @@ C_SRCS = \ shfldr_desktop.c \ shfldr_fs.c \ shfldr_mycomp.c \ + shfldr_nethood.c \ shfldr_unixfs.c \ shlexec.c \ shlfileop.c \ diff --git a/dlls/shell32/debughlp.c b/dlls/shell32/debughlp.c index 16f79f233ea..b1e92381fbf 100644 --- a/dlls/shell32/debughlp.c +++ b/dlls/shell32/debughlp.c @@ -104,6 +104,51 @@ LPSTR _dbg_ILGetTextPointer(LPCITEMIDLIST pidl) } static +LPWSTR _dbg_ILGetTextPointerW(LPCITEMIDLIST pidl) +{ + LPPIDLDATA pdata =_dbg_ILGetDataPointer(pidl); + + if (pdata) + { + switch (pdata->type) + { + case PT_GUID: + case PT_SHELLEXT: + case PT_YAGUID: + return NULL; + + case PT_DRIVE: + case PT_DRIVE1: + case PT_DRIVE2: + case PT_DRIVE3: + /* return (LPSTR)&(pdata->u.drive.szDriveName);*/ + return NULL; + + case PT_FOLDER: + case PT_FOLDER1: + case PT_VALUE: + case PT_IESPECIAL1: + case PT_IESPECIAL2: + /* return (LPSTR)&(pdata->u.file.szNames); */ + return NULL; + + case PT_WORKGRP: + case PT_COMP: + case PT_NETWORK: + case PT_NETPROVIDER: + case PT_SHARE: + /* return (LPSTR)&(pdata->u.network.szNames); */ + return NULL; + + case PT_VALUEW: + return (LPWSTR)&(pdata->u.file.szNames); + } + } + return NULL; +} + + +static LPSTR _dbg_ILGetSTextPointer(LPCITEMIDLIST pidl) { LPPIDLDATA pdata =_dbg_ILGetDataPointer(pidl); @@ -126,6 +171,34 @@ LPSTR _dbg_ILGetSTextPointer(LPCITEMIDLIST pidl) } static +LPWSTR _dbg_ILGetSTextPointerW(LPCITEMIDLIST pidl) +{ + LPPIDLDATA pdata =_dbg_ILGetDataPointer(pidl); + + if (pdata) + { + switch (pdata->type) + { + case PT_FOLDER: + case PT_VALUE: + case PT_IESPECIAL1: + case PT_IESPECIAL2: + /*return (LPSTR)(pdata->u.file.szNames + strlen (pdata->u.file.szNames) + 1); */ + return NULL; + + case PT_WORKGRP: + /* return (LPSTR)(pdata->u.network.szNames + strlen (pdata->u.network.szNames) + 1); */ + return NULL; + + case PT_VALUEW: + return (LPWSTR)(pdata->u.file.szNames + lstrlenW ((LPWSTR)pdata->u.file.szNames) + 1); + } + } + return NULL; +} + + +static IID* _dbg_ILGetGUIDPointer(LPCITEMIDLIST pidl) { LPPIDLDATA pdata =_ILGetDataPointer(pidl); @@ -147,6 +220,7 @@ static void _dbg_ILSimpleGetText (LPCITEMIDLIST pidl, LPSTR szOut, UINT uOutSize) { LPSTR szSrc; + LPWSTR szSrcW; GUID const * riid; if (!pidl) return; @@ -164,6 +238,13 @@ void _dbg_ILSimpleGetText (LPCITEMIDLIST pidl, LPSTR szOut, UINT uOutSize) /* filesystem */ if (szOut) lstrcpynA(szOut, szSrc, uOutSize); } + else if (( szSrcW = _dbg_ILGetTextPointerW(pidl) )) + { + CHAR tmp[MAX_PATH]; + /* unicode filesystem */ + WideCharToMultiByte(CP_ACP,0,szSrcW, -1, tmp, MAX_PATH, NULL, NULL); + if (szOut) lstrcpynA(szOut, tmp, uOutSize); + } else if (( riid = _dbg_ILGetGUIDPointer(pidl) )) { if (szOut) @@ -194,20 +275,40 @@ void pdump (LPCITEMIDLIST pidl) { do { - DWORD dwAttrib = 0; - LPPIDLDATA pData = _dbg_ILGetDataPointer(pidltemp); - DWORD type = pData ? pData->type : 0; - LPSTR szLongName = _dbg_ILGetTextPointer(pidltemp); - LPSTR szShortName = _dbg_ILGetSTextPointer(pidltemp); - char szName[MAX_PATH]; - - _dbg_ILSimpleGetText(pidltemp, szName, MAX_PATH); - if ( pData && (PT_FOLDER == type || PT_VALUE == type) ) - dwAttrib = pData->u.file.uFileAttribs; - - MESSAGE ("[%p] size=%04u type=%x attr=0x%08x name=%s (%s,%s)\n", - pidltemp, pidltemp->mkid.cb, type, dwAttrib, - debugstr_a(szName), debugstr_a(szLongName), debugstr_a(szShortName)); + if (_ILIsUnicode(pidltemp)) + { + DWORD dwAttrib = 0; + LPPIDLDATA pData = _dbg_ILGetDataPointer(pidltemp); + DWORD type = pData ? pData->type : 0; + LPWSTR szLongName = _dbg_ILGetTextPointerW(pidltemp); + LPWSTR szShortName = _dbg_ILGetSTextPointerW(pidltemp); + char szName[MAX_PATH]; + + _dbg_ILSimpleGetText(pidltemp, szName, MAX_PATH); + if ( pData && (PT_FOLDER == type || PT_VALUE == type) ) + dwAttrib = pData->u.file.uFileAttribs; + + MESSAGE ("[%p] size=%04u type=%x attr=0x%08x name=%s (%s,%s)\n", + pidltemp, pidltemp->mkid.cb, type, dwAttrib, + debugstr_a(szName), debugstr_w(szLongName), debugstr_w(szShortName)); + } + else + { + DWORD dwAttrib = 0; + LPPIDLDATA pData = _dbg_ILGetDataPointer(pidltemp); + DWORD type = pData ? pData->type : 0; + LPSTR szLongName = _dbg_ILGetTextPointer(pidltemp); + LPSTR szShortName = _dbg_ILGetSTextPointer(pidltemp); + char szName[MAX_PATH]; + + _dbg_ILSimpleGetText(pidltemp, szName, MAX_PATH); + if ( pData && (PT_FOLDER == type || PT_VALUE == type) ) + dwAttrib = pData->u.file.uFileAttribs; + + MESSAGE ("[%p] size=%04u type=%x attr=0x%08x name=%s (%s,%s)\n", + pidltemp, pidltemp->mkid.cb, type, dwAttrib, + debugstr_a(szName), debugstr_a(szLongName), debugstr_a(szShortName)); + } pidltemp = _dbg_ILGetNext(pidltemp); diff --git a/dlls/shell32/pidl.c b/dlls/shell32/pidl.c index c5a79e053a9..7c4845b34aa 100644 --- a/dlls/shell32/pidl.c +++ b/dlls/shell32/pidl.c @@ -1430,6 +1430,12 @@ LPITEMIDLIST _ILCreateNetwork(void) return _ILCreateGuid(PT_GUID, &CLSID_NetworkPlaces); } +LPITEMIDLIST _ILCreateNetHood(void) +{ + TRACE("()\n"); + return _ILCreateGuid(PT_GUID, &CLSID_NetworkPlaces); +} + LPITEMIDLIST _ILCreateBitBucket(void) { TRACE("()\n"); @@ -1484,95 +1490,52 @@ LPITEMIDLIST _ILCreateGuidFromStrW(LPCWSTR szGUID) return _ILCreateGuid(PT_GUID, &iid); } -LPITEMIDLIST _ILCreateFromFindDataW( WIN32_FIND_DATAW *wfd ) -{ - /* FIXME: should make unicode PIDLs */ - WIN32_FIND_DATAA fda; - - memset( &fda, 0, sizeof fda ); - fda.dwFileAttributes = wfd->dwFileAttributes; - fda.ftCreationTime = wfd->ftCreationTime; - fda.ftLastAccessTime = wfd->ftLastAccessTime; - fda.ftLastWriteTime = wfd->ftLastWriteTime; - fda.nFileSizeHigh = wfd->nFileSizeHigh; - fda.nFileSizeLow = wfd->nFileSizeLow; - fda.dwReserved0 = wfd->dwReserved0; - fda.dwReserved1 = wfd->dwReserved1; - WideCharToMultiByte( CP_ACP, 0, wfd->cFileName, -1, - fda.cFileName, MAX_PATH, NULL, NULL ); - return _ILCreateFromFindDataA( &fda ); -} - -LPITEMIDLIST _ILCreateFromFindDataA(WIN32_FIND_DATAA * stffile ) +LPITEMIDLIST _ILCreateFromFindDataW( const WIN32_FIND_DATAW *wfd ) { char buff[MAX_PATH + 14 +1]; /* see WIN32_FIND_DATA */ - char * pbuff = buff; - size_t len, len1; + DWORD len, len1, wlen, alen; LPITEMIDLIST pidl; PIDLTYPE type; - if (!stffile) + if (!wfd) return NULL; - TRACE("(%s, %s)\n",stffile->cAlternateFileName, stffile->cFileName); + TRACE("(%s, %s)\n",debugstr_w(wfd->cAlternateFileName), debugstr_w(wfd->cFileName)); /* prepare buffer with both names */ - len = strlen (stffile->cFileName) + 1; - memcpy (pbuff, stffile->cFileName, len); - pbuff += len; - - len1 = strlen (stffile->cAlternateFileName)+1; - memcpy (pbuff, stffile->cAlternateFileName, len1); + len = WideCharToMultiByte(CP_ACP,0,wfd->cFileName,-1,buff,MAX_PATH,NULL,NULL); + len1 = WideCharToMultiByte(CP_ACP,0,wfd->cAlternateFileName,-1, buff+len, sizeof(buff)-len, NULL, NULL); + alen = len + len1; - type = (stffile->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? PT_FOLDER : PT_VALUE; + type = (wfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? PT_FOLDER : PT_VALUE; - /* - * FileStruct already has one byte for the first name, so use len - 1 in - * size calculation - */ - pidl = _ILAlloc(type, sizeof(FileStruct) + (len - 1) + len1); + wlen = lstrlenW(wfd->cFileName) + 1; + pidl = _ILAlloc(type, FIELD_OFFSET(FileStruct, szNames[alen + (alen & 1)]) + + FIELD_OFFSET(FileStructW, wszName[wlen]) + sizeof(WORD)); if (pidl) { - LPPIDLDATA pData; - LPSTR pszDest; - - /* set attributes */ - pData = _ILGetDataPointer(pidl); - if (pData) - { - pData->type = type; - FileTimeToDosDateTime( &(stffile->ftLastWriteTime), - &pData->u.file.uFileDate, &pData->u.file.uFileTime); - pData->u.file.dwFileSize = stffile->nFileSizeLow; - pData->u.file.uFileAttribs = (WORD)stffile->dwFileAttributes; - } - pszDest = _ILGetTextPointer(pidl); - if (pszDest) - { - memcpy(pszDest, buff, len + len1); - TRACE("-- create Value: %s\n",debugstr_a(pszDest)); - } + LPPIDLDATA pData = _ILGetDataPointer(pidl); + FileStruct *fs = &pData->u.file; + FileStructW *fsw; + WORD *pOffsetW; + + FileTimeToDosDateTime( &wfd->ftLastWriteTime, &fs->uFileDate, &fs->uFileTime); + fs->dwFileSize = wfd->nFileSizeLow; + fs->uFileAttribs = wfd->dwFileAttributes; + memcpy(fs->szNames, buff, alen); + + fsw = (FileStructW*)(pData->u.file.szNames + alen + (alen & 0x1)); + fsw->cbLen = FIELD_OFFSET(FileStructW, wszName[wlen]) + sizeof(WORD); + FileTimeToDosDateTime( &wfd->ftCreationTime, &fsw->uCreationDate, &fsw->uCreationTime); + FileTimeToDosDateTime( &wfd->ftLastAccessTime, &fsw->uLastAccessDate, &fsw->uLastAccessTime); + memcpy(fsw->wszName, wfd->cFileName, wlen * sizeof(WCHAR)); + + pOffsetW = (WORD*)((LPBYTE)pidl + pidl->mkid.cb - sizeof(WORD)); + *pOffsetW = (LPBYTE)fsw - (LPBYTE)pidl; + TRACE("-- Set Value: %s\n",debugstr_w(fsw->wszName)); } return pidl; -} - -HRESULT _ILCreateFromPathA(LPCSTR szPath, LPITEMIDLIST* ppidl) -{ - HANDLE hFile; - WIN32_FIND_DATAA stffile; - - if (!ppidl) - return E_INVALIDARG; - hFile = FindFirstFileA(szPath, &stffile); - if (hFile == INVALID_HANDLE_VALUE) - return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); - - FindClose(hFile); - - *ppidl = _ILCreateFromFindDataA(&stffile); - - return *ppidl ? S_OK : E_OUTOFMEMORY; } HRESULT _ILCreateFromPathW(LPCWSTR szPath, LPITEMIDLIST* ppidl) @@ -1642,6 +1605,7 @@ DWORD _ILGetDrive(LPCITEMIDLIST pidl,LPSTR pOut, UINT uSize) * ### 2. section testing pidls ### * ************************************************************************** + * _ILIsUnicode() * _ILIsDesktop() * _ILIsMyComputer() * _ILIsSpecialFolder() @@ -1650,6 +1614,15 @@ DWORD _ILGetDrive(LPCITEMIDLIST pidl,LPSTR pOut, UINT uSize) * _ILIsValue() * _ILIsPidlSimple() */ +BOOL _ILIsUnicode(LPCITEMIDLIST pidl) +{ + LPPIDLDATA lpPData = _ILGetDataPointer(pidl); + + TRACE("(%p)\n",pidl); + + return (pidl && lpPData && PT_VALUEW == lpPData->type); +} + BOOL _ILIsDesktop(LPCITEMIDLIST pidl) { TRACE("(%p)\n",pidl); @@ -1754,6 +1727,7 @@ DWORD _ILSimpleGetText (LPCITEMIDLIST pidl, LPSTR szOut, UINT uOutSize) { DWORD dwReturn=0; LPSTR szSrc; + LPWSTR szSrcW; GUID const * riid; char szTemp[MAX_PATH]; @@ -1784,6 +1758,16 @@ DWORD _ILSimpleGetText (LPCITEMIDLIST pidl, LPSTR szOut, UINT uOutSize) dwReturn = strlen(szSrc); } + else if (( szSrcW = _ILGetTextPointerW(pidl) )) + { + /* unicode filesystem */ + WideCharToMultiByte(CP_ACP,0,szSrcW, -1, szTemp, MAX_PATH, NULL, NULL); + + if (szOut) + lstrcpynA(szOut, szTemp, uOutSize); + + dwReturn = strlen (szTemp); + } else if (( riid = _ILGetGUIDPointer(pidl) )) { /* special folder */ @@ -1814,7 +1798,6 @@ DWORD _ILSimpleGetText (LPCITEMIDLIST pidl, LPSTR szOut, UINT uOutSize) DWORD _ILSimpleGetTextW (LPCITEMIDLIST pidl, LPWSTR szOut, UINT uOutSize) { DWORD dwReturn; - char szTemp[MAX_PATH]; FileStructW *pFileStructW = _ILGetFileStructW(pidl); TRACE("(%p %p %x)\n",pidl,szOut,uOutSize); @@ -1823,10 +1806,62 @@ DWORD _ILSimpleGetTextW (LPCITEMIDLIST pidl, LPWSTR szOut, UINT uOutSize) lstrcpynW(szOut, pFileStructW->wszName, uOutSize); dwReturn = lstrlenW(pFileStructW->wszName); } else { - dwReturn = _ILSimpleGetText(pidl, szTemp, MAX_PATH); + GUID const * riid; + WCHAR szTemp[MAX_PATH]; + LPSTR szSrc; + LPWSTR szSrcW; + dwReturn=0; - if (!MultiByteToWideChar(CP_ACP, 0, szTemp, -1, szOut, uOutSize)) + if (!pidl) + return 0; + + if (szOut) *szOut = 0; + + if (_ILIsDesktop(pidl)) + { + /* desktop */ + if (HCR_GetClassNameW(&CLSID_ShellDesktop, szTemp, MAX_PATH)) + { + if (szOut) + lstrcpynW(szOut, szTemp, uOutSize); + + dwReturn = lstrlenW (szTemp); + } + } + else if (( szSrcW = _ILGetTextPointerW(pidl) )) + { + /* unicode filesystem */ + if (szOut) + lstrcpynW(szOut, szSrcW, uOutSize); + + dwReturn = lstrlenW(szSrcW); + } + else if (( szSrc = _ILGetTextPointer(pidl) )) + { + /* filesystem */ + MultiByteToWideChar(CP_ACP, 0, szSrc, -1, szTemp, MAX_PATH); + + if (szOut) + lstrcpynW(szOut, szTemp, uOutSize); + + dwReturn = lstrlenW (szTemp); + } + else if (( riid = _ILGetGUIDPointer(pidl) )) + { + /* special folder */ + if ( HCR_GetClassNameW(riid, szTemp, MAX_PATH) ) + { + if (szOut) + lstrcpynW(szOut, szTemp, uOutSize); + + dwReturn = lstrlenW (szTemp); + } + } + else + { + ERR("-- no text\n"); + } } TRACE("-- (%p=%s 0x%08x)\n",szOut,debugstr_w(szOut),dwReturn); @@ -1848,6 +1883,56 @@ LPPIDLDATA _ILGetDataPointer(LPCITEMIDLIST pidl) } /************************************************************************** + * _ILGetTextPointerW() + * gets a pointer to the unicode long filename string stored in the pidl + */ +LPWSTR _ILGetTextPointerW(LPCITEMIDLIST pidl) +{ + /* TRACE(pidl,"(pidl%p)\n", pidl);*/ + + LPPIDLDATA pdata = _ILGetDataPointer(pidl); + + if (!pdata) + return NULL; + + switch (pdata->type) + { + case PT_GUID: + case PT_SHELLEXT: + case PT_YAGUID: + return NULL; + + case PT_DRIVE: + case PT_DRIVE1: + case PT_DRIVE2: + case PT_DRIVE3: + /*return (LPSTR)&(pdata->u.drive.szDriveName);*/ + return NULL; + + case PT_FOLDER: + case PT_FOLDER1: + case PT_VALUE: + case PT_IESPECIAL1: + case PT_IESPECIAL2: + /*return (LPSTR)&(pdata->u.file.szNames);*/ + return NULL; + + case PT_WORKGRP: + case PT_COMP: + case PT_NETWORK: + case PT_NETPROVIDER: + case PT_SHARE: + /*return (LPSTR)&(pdata->u.network.szNames);*/ + return NULL; + + case PT_VALUEW: + return (LPWSTR)&(pdata->u.file.szNames); + } + return NULL; +} + + +/************************************************************************** * _ILGetTextPointer() * gets a pointer to the long filename string stored in the pidl */ diff --git a/dlls/shell32/pidl.h b/dlls/shell32/pidl.h index 0bdae80877c..bc1a5bf4b47 100644 --- a/dlls/shell32/pidl.h +++ b/dlls/shell32/pidl.h @@ -201,6 +201,7 @@ DWORD _ILGetDrive (LPCITEMIDLIST, LPSTR, UINT); /* * testing simple pidls */ +BOOL _ILIsUnicode (LPCITEMIDLIST pidl); BOOL _ILIsDesktop (LPCITEMIDLIST pidl); BOOL _ILIsMyComputer (LPCITEMIDLIST pidl); BOOL _ILIsDrive (LPCITEMIDLIST pidl); @@ -241,9 +242,7 @@ LPITEMIDLIST _ILCreateGuidFromStrW(LPCWSTR szGUID); /* Commonly used PIDLs representing file system objects. */ LPITEMIDLIST _ILCreateDesktop (void); -LPITEMIDLIST _ILCreateFromFindDataA(WIN32_FIND_DATAA *stffile); -LPITEMIDLIST _ILCreateFromFindDataW(WIN32_FIND_DATAW *stffile); -HRESULT _ILCreateFromPathA (LPCSTR szPath, LPITEMIDLIST* ppidl); +LPITEMIDLIST _ILCreateFromFindDataW(const WIN32_FIND_DATAW *stffile); HRESULT _ILCreateFromPathW (LPCWSTR szPath, LPITEMIDLIST* ppidl); /* Other helpers */ @@ -253,6 +252,7 @@ LPITEMIDLIST _ILCreateIExplore (void); LPITEMIDLIST _ILCreateControlPanel (void); LPITEMIDLIST _ILCreatePrinters (void); LPITEMIDLIST _ILCreateNetwork (void); +LPITEMIDLIST _ILCreateNetHood (void); LPITEMIDLIST _ILCreateBitBucket (void); LPITEMIDLIST _ILCreateDrive (LPCWSTR); @@ -261,6 +261,7 @@ LPITEMIDLIST _ILCreateDrive (LPCWSTR); */ LPPIDLDATA _ILGetDataPointer (LPCITEMIDLIST); LPSTR _ILGetTextPointer (LPCITEMIDLIST); +LPWSTR _ILGetTextPointerW (LPCITEMIDLIST); LPSTR _ILGetSTextPointer (LPCITEMIDLIST); IID *_ILGetGUIDPointer (LPCITEMIDLIST pidl); FileStructW *_ILGetFileStructW (LPCITEMIDLIST pidl); diff --git a/dlls/shell32/shell32.spec b/dlls/shell32/shell32.spec index 23004ce6074..875d6ccec42 100644 --- a/dlls/shell32/shell32.spec +++ b/dlls/shell32/shell32.spec @@ -428,3 +428,5 @@ @ stdcall StrStrIW(wstr wstr) shlwapi.StrStrIW @ stdcall StrStrW(wstr wstr) shlwapi.StrStrW @ stub WOWShellExecute + +@ stdcall wine_update_symbolic_links() diff --git a/dlls/shell32/shell32_En.rc b/dlls/shell32/shell32_En.rc index a67cc8a6f4a..7f058bd3b54 100644 --- a/dlls/shell32/shell32_En.rc +++ b/dlls/shell32/shell32_En.rc @@ -207,7 +207,7 @@ STRINGTABLE DISCARDABLE IDS_SENDTO "SendTo" IDS_STARTMENU "Start Menu" IDS_MYMUSIC "My Music" - IDS_MYVIDEO "My Video" + IDS_MYVIDEO "My Videos" IDS_DESKTOPDIRECTORY "Desktop" IDS_NETHOOD "NetHood" IDS_TEMPLATES "Templates" @@ -224,6 +224,10 @@ STRINGTABLE DISCARDABLE IDS_ADMINTOOLS "Start Menu\\Programs\\Administrative Tools" IDS_COMMON_MUSIC "Documents\\My Music" IDS_COMMON_PICTURES "Documents\\My Pictures" - IDS_COMMON_VIDEO "Documents\\My Video" + IDS_COMMON_VIDEO "Documents\\My Videos" IDS_CDBURN_AREA "Local Settings\\Application Data\\Microsoft\\CD Burning" + + WINE_IDS_PICTURES "Pictures" + WINE_IDS_MUSIC "Music" + WINE_IDS_MOVIES "Movies" } diff --git a/dlls/shell32/shell32_main.c b/dlls/shell32/shell32_main.c index 70db342465d..ea4b5100c48 100644 --- a/dlls/shell32/shell32_main.c +++ b/dlls/shell32/shell32_main.c @@ -275,6 +275,9 @@ static DWORD shgfi_get_exe_type(LPCWSTR szFullPath) SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET ); ReadFile( hfile, &nt, sizeof(nt), &len, NULL ); CloseHandle( hfile ); + /* DLL files are not executable and should return 0 */ + if (nt.FileHeader.Characteristics & IMAGE_FILE_DLL) + return 0; if (nt.OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) { return IMAGE_NT_SIGNATURE | diff --git a/dlls/shell32/shell32_main.h b/dlls/shell32/shell32_main.h index c974c8ea46b..ea30de2ecd7 100644 --- a/dlls/shell32/shell32_main.h +++ b/dlls/shell32/shell32_main.h @@ -90,6 +90,7 @@ HRESULT WINAPI IShellLink_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID HRESULT WINAPI IShellLink_ConstructFromFile(IUnknown * pUnkOuter, REFIID riid, LPCITEMIDLIST pidl, LPVOID * ppv); HRESULT WINAPI ISF_Desktop_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); HRESULT WINAPI ISF_MyComputer_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); +HRESULT WINAPI ISF_NetworkPlaces_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); HRESULT WINAPI IDropTargetHelper_Constructor (IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); HRESULT WINAPI IFileSystemBindData_Constructor(const WIN32_FIND_DATAW *pfd, LPBC *ppV); HRESULT WINAPI IControlPanel_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); @@ -107,6 +108,7 @@ HRESULT WINAPI IAutoComplete_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVO LPEXTRACTICONA IExtractIconA_Constructor(LPCITEMIDLIST); LPEXTRACTICONW IExtractIconW_Constructor(LPCITEMIDLIST); +HRESULT CreateStreamOnFile (LPCWSTR pszFilename, DWORD grfMode, IStream ** ppstm); /* menu merging */ #define MM_ADDSEPARATOR 0x00000001L diff --git a/dlls/shell32/shelllink.c b/dlls/shell32/shelllink.c index f7c9c59b479..8b4964ba3a0 100644 --- a/dlls/shell32/shelllink.c +++ b/dlls/shell32/shelllink.c @@ -381,9 +381,7 @@ static HRESULT WINAPI IPersistFile_fnLoad(IPersistFile* iface, LPCOLESTR pszFile TRACE("(%p, %s, %x)\n",This, debugstr_w(pszFileName), dwMode); - if( dwMode == 0 ) - dwMode = STGM_READ | STGM_SHARE_DENY_WRITE; - r = SHCreateStreamOnFileW(pszFileName, dwMode, &stm); + r = CreateStreamOnFile(pszFileName, dwMode, &stm); if( SUCCEEDED( r ) ) { r = IPersistStream_Load(StreamThis, stm); @@ -434,13 +432,34 @@ static HRESULT WINAPI IPersistFile_fnSave(IPersistFile* iface, LPCOLESTR pszFile IPersistStream *StreamThis = (IPersistStream *)&This->lpvtblPersistStream; HRESULT r; IStream *stm; + static const WCHAR wszIEStartMenuHardCoded[] = {'C',':','\\','W','i','n','d','o','w','s','\\','S','t','a','r','t',' ','M','e','n','u','\\','P','r','o','g','r','a','m','s','\\','I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','.','l','n','k',0}; + static const WCHAR wszIEDesktopHardCoded[] = {'C',':','\\','W','i','n','d','o','w','s','\\','D','e','s','k','t','o','p','\\','I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','.','l','n','k',0}; + WCHAR buffer[MAX_PATH]; TRACE("(%p)->(%s)\n",This,debugstr_w(pszFileName)); if (!pszFileName) return E_FAIL; - r = SHCreateStreamOnFileW( pszFileName, STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE, &stm ); + /* CrossOver HACK! The IE 6 installer hardcodes these paths (which work on + * Win9x), but don't in Windows 2000+ and Wine. So fix them up to use the + * proper functions to get the directory to save the link into */ + if (!strcmpW(pszFileName, wszIEStartMenuHardCoded)) + { + r = SHGetFolderPathW(NULL, CSIDL_STARTMENU, NULL, SHGFP_TYPE_CURRENT, buffer); + strcatW(buffer, strchrW(strchrW(strchrW(wszIEStartMenuHardCoded, '\\') + 1, '\\') + 1, '\\')); + TRACE("changing %s to %s\n", debugstr_w(pszFileName), debugstr_w(buffer)); + pszFileName = buffer; + } + else if (!strcmpW(pszFileName, wszIEDesktopHardCoded)) + { + r = SHGetFolderPathW(NULL, CSIDL_DESKTOP, NULL, SHGFP_TYPE_CURRENT, buffer); + strcatW(buffer, strchrW(strchrW(strchrW(wszIEDesktopHardCoded, '\\') + 1, '\\') + 1, '\\')); + TRACE("changing %s to %s\n", debugstr_w(pszFileName), debugstr_w(buffer)); + pszFileName = buffer; + } + + r = CreateStreamOnFile(pszFileName, STGM_READWRITE | STGM_CREATE, &stm); if( SUCCEEDED( r ) ) { r = IPersistStream_Save(StreamThis, stm, FALSE); @@ -686,6 +705,16 @@ static HRESULT Stream_LoadLocation( IStream *stm, return r; loc = (LOCATION_INFO*) p; + + /* hack around .lnk files generated by older broken shelllink code */ + if( loc->dwTotalSize == 0x18 ) + { + ERR("link was generated by an older shelllink version\n"); + memset( volume, 0, sizeof *volume ); + *path = NULL; + return S_OK; + } + if (loc->dwTotalSize < sizeof(LOCATION_INFO)) { HeapFree( GetProcessHeap(), 0, p ); diff --git a/dlls/shell32/shellole.c b/dlls/shell32/shellole.c index e5d8368202d..830c3cdd7c4 100644 --- a/dlls/shell32/shellole.c +++ b/dlls/shell32/shellole.c @@ -64,6 +64,7 @@ static const struct { } InterfaceTable[] = { {&CLSID_ShellFSFolder, &IFSFolder_Constructor}, {&CLSID_MyComputer, &ISF_MyComputer_Constructor}, + {&CLSID_NetworkPlaces, &ISF_NetworkPlaces_Constructor}, {&CLSID_ShellDesktop, &ISF_Desktop_Constructor}, {&CLSID_ShellLink, &IShellLink_Constructor}, {&CLSID_DragDropHelper, &IDropTargetHelper_Constructor}, diff --git a/dlls/shell32/shellord.c b/dlls/shell32/shellord.c index f2f72dc3cd0..8fca34e7db2 100644 --- a/dlls/shell32/shellord.c +++ b/dlls/shell32/shellord.c @@ -790,7 +790,11 @@ void WINAPI SHAddToRecentDocs (UINT uFlags,LPCVOID pv) switch (uFlags) { case SHARD_PIDL: - SHGetPathFromIDListA((LPCITEMIDLIST) pv, doc_name); + if (!SHGetPathFromIDListA((LPCITEMIDLIST) pv, doc_name)) + { + ERR("Unable to get pure document name from pidl\n"); + return; + } break; case SHARD_PATHA: diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c index 8c05aaf15d0..ee1fb584fba 100644 --- a/dlls/shell32/shellpath.c +++ b/dlls/shell32/shellpath.c @@ -1230,6 +1230,21 @@ static HRESULT _SHGetUserShellFolderPath(HKEY rootKey, LPCWSTR userPrefix, return hr; } +/* CrossOver HACK: Load an English string to work around restoring bottles + * with non-US-ASCII characters, which doesn't work when the locale has + * changed */ +static inline INT LoadStringW_English( HINSTANCE instance, UINT resource_id, + LPWSTR buffer, INT buflen ) +{ + INT ret; + LCID lcid = GetThreadLocale(); + SetThreadLocale(MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT),SORT_DEFAULT)); + ret = LoadStringW(instance, resource_id, buffer, buflen); + SetThreadLocale(lcid); + return ret; +} + + /* Gets a 'semi-expanded' default value of the CSIDL with index folder into * pszPath, based on the entries in CSIDL_Data. By semi-expanded, I mean: * - The entry's szDefaultPath may be either a string value or an integer @@ -1260,7 +1275,7 @@ static HRESULT _SHGetDefaultValue(BYTE folder, LPWSTR pszPath) if (CSIDL_Data[folder].szDefaultPath && IS_INTRESOURCE(CSIDL_Data[folder].szDefaultPath)) { - if (LoadStringW(shell32_hInstance, + if (LoadStringW_English(shell32_hInstance, LOWORD(CSIDL_Data[folder].szDefaultPath), resourcePath, MAX_PATH)) { hr = S_OK; @@ -1562,11 +1577,9 @@ static HRESULT _SHExpandEnvironmentStrings(LPCWSTR szSrc, LPWSTR szDest) } else if (!strncmpiW(szTemp, UserProfileW, strlenW(UserProfileW))) { - WCHAR userName[MAX_PATH]; - DWORD userLen = MAX_PATH; + static const WCHAR userName[] = {'c','r','o','s','s','o','v','e','r',0}; strcpyW(szDest, szProfilesPrefix); - GetUserNameW(userName, &userLen); PathAppendW(szDest, userName); PathAppendW(szDest, szTemp + strlenW(UserProfileW)); } @@ -1945,14 +1958,20 @@ static HRESULT _SHRegisterCommonShellFolders(void) * Success: TRUE, * Failure: FALSE */ -static inline BOOL _SHAppendToUnixPath(char *szBasePath, LPCWSTR pwszSubPath) { +static inline BOOL _SHAppendToUnixPath(char *szBasePath, LPCWSTR pwszSubPath, int localize) { WCHAR wszSubPath[MAX_PATH]; int cLen = strlen(szBasePath); char *pBackslash; if (IS_INTRESOURCE(pwszSubPath)) { - if (!LoadStringW(shell32_hInstance, LOWORD(pwszSubPath), wszSubPath, MAX_PATH)) { - /* Fall back to hard coded defaults. */ + int rc; + if (localize) + rc=LoadStringW(shell32_hInstance, LOWORD(pwszSubPath), wszSubPath, MAX_PATH); + else + rc=LoadStringW_English(shell32_hInstance, LOWORD(pwszSubPath), wszSubPath, MAX_PATH); + if (!rc) { + /* Fall back to hardcoded defaults. */ + WARN("Falling back to hardcoded defaults\n"); switch (LOWORD(pwszSubPath)) { case IDS_PERSONAL: lstrcpyW(wszSubPath, PersonalW); @@ -1989,126 +2008,311 @@ static inline BOOL _SHAppendToUnixPath(char *szBasePath, LPCWSTR pwszSubPath) { return TRUE; } +typedef struct +{ + UINT ids; + int csidl; + UINT unix_location[3]; +} folder_mapping_t; + +static const folder_mapping_t folder_mappings[]={ + { /* Must be the first in the list */ + IDS_PERSONAL, + CSIDL_PERSONAL, + { IDS_PERSONAL, /* 'My Documents' */ + IDS_COMMON_DOCUMENTS, /* 'Documents' (used on SUSE, Mandriva, ...) */ + 0 + } + }, + { IDS_MYPICTURES, + CSIDL_MYPICTURES, + { IDS_MYPICTURES, /* 'My Pictures' */ + WINE_IDS_PICTURES, /* 'Pictures' (used on the Mac) */ + 0 + } + }, + { IDS_MYVIDEO, + CSIDL_MYVIDEO, + { IDS_MYVIDEO, /* 'My Videos' */ + WINE_IDS_MOVIES, /* 'Movies' (used on the Mac) */ + 0 + } + }, + { IDS_MYMUSIC, + CSIDL_MYMUSIC, + { IDS_MYMUSIC, /* 'My Music' */ + WINE_IDS_MUSIC, /* 'Music' (used on the Mac) */ + 0 + } + } +}; + /****************************************************************************** * _SHCreateSymbolicLinks [Internal] * * Sets up symbol links for various shell folders to point into the users home * directory. We do an educated guess about what the user would probably want: - * - If there is a 'My Documents' directory in $HOME, the user probably wants - * wine's 'My Documents' to point there. Furthermore, we imply that the user - * is a Windows lover and has no problem with wine creating 'My Pictures', - * 'My Music' and 'My Video' subfolders under '$HOME/My Documents', if those - * do not already exits. We put appropriate symbolic links in place for those, - * too. - * - If there is no 'My Documents' directory in $HOME, we let 'My Documents' - * point directly to $HOME. We assume the user to be a unix hacker who does not - * want wine to create anything anywhere besides the .wine directory. So, if - * there already is a 'My Music' directory in $HOME, we symlink the 'My Music' - * shell folder to it. But if not, we symlink it to $HOME directly. The same - * holds fo 'My Pictures' and 'My Video'. + * - If there is a 'My Documents' or 'Documents' directory in $HOME, the user + * probably wants Wine's 'My Documents' to point there. Furthermore, we + * assume that the user is a Windows lover and has no problem with Wine + * creating 'My Pictures', 'My Music' and 'My Video' subfolders under + * '$HOME/My Documents', if those do not already exits. We put appropriate + * symbolic links in place for those too. + * - If there is no 'My Documents' directory in $HOME, we let it point + * directly to $HOME. We assume the user to be a Unix hacker who does not + * want Wine to create anything anywhere besides the .wine directory. So, if + * there already is a 'My Music' directory in $HOME, we symlink the + * 'My Music' shell folder to it. But if not, we symlink it to $HOME + * directly. The same holds for 'My Pictures' and 'My Video'. * - The Desktop shell folder is symlinked to '$HOME/Desktop', if that does * exists and left alone if not. - * ('My Music',... above in fact means LoadString(IDS_MYMUSIC)) + * ('My Music', ... above in fact means LoadString(IDS_MYMUSIC)) */ static void _SHCreateSymbolicLinks(void) { - UINT aidsMyStuff[] = { IDS_MYPICTURES, IDS_MYVIDEO, IDS_MYMUSIC }, i; - int acsidlMyStuff[] = { CSIDL_MYPICTURES, CSIDL_MYVIDEO, CSIDL_MYMUSIC }; WCHAR wszTempPath[MAX_PATH]; char szPersonalTarget[FILENAME_MAX], *pszPersonal; char szMyStuffTarget[FILENAME_MAX], *pszMyStuff; +# define szLinuxDesktop "/My Linux Desktop" +# define szMacDesktop "/My Mac Desktop" +# define szNativeDesktop "/My Native Desktop" + static const char* szDesktops[] = {szLinuxDesktop, + szMacDesktop, + szNativeDesktop, + NULL}; + const char* pszNativeDesktop; + char *pszDesktopLink; char szDesktopTarget[FILENAME_MAX], *pszDesktop; - struct stat statFolder; const char *pszHome; + struct stat statHome, statFolder; + static const int MDL_DIRS = 1; + static const int MDL_FLAT_LINKS = 2; + static const int MDL_NESTED_LINKS = 3; + int layout, localize, i, u; HRESULT hr; /* Create all necessary profile sub-dirs up to 'My Documents' and get the unix path. */ hr = SHGetFolderPathW(NULL, CSIDL_PERSONAL|CSIDL_FLAG_CREATE, NULL, - SHGFP_TYPE_DEFAULT, wszTempPath); + SHGFP_TYPE_CURRENT, wszTempPath); if (FAILED(hr)) return; pszPersonal = wine_get_unix_file_name(wszTempPath); if (!pszPersonal) return; + /* SHGetFolderPathW() creates 'My Documents' as a directory which may + * not be what we want. But we need to rmdir() the folder anyway so we + * get another chance to symlink during upgrades in case the folder is + * not used yet. + */ + rmdir(pszPersonal); pszHome = getenv("HOME"); - if (pszHome && !stat(pszHome, &statFolder) && S_ISDIR(statFolder.st_mode)) { - strcpy(szPersonalTarget, pszHome); - if (_SHAppendToUnixPath(szPersonalTarget, MAKEINTRESOURCEW(IDS_PERSONAL)) && - !stat(szPersonalTarget, &statFolder) && S_ISDIR(statFolder.st_mode)) + if (!pszHome || !strcmp(pszHome, "/") || stat(pszHome, &statHome) || + !S_ISDIR(statHome.st_mode) || statHome.st_uid != geteuid()) + { + /* $HOME does not exist or is otherwise unusable */ + pszHome=NULL; + } + + /* Create and / or figure out the 'My Documents' layout */ + localize=1; + if (stat(pszPersonal, &statFolder) || !S_ISDIR(statFolder.st_mode) || + statFolder.st_uid != geteuid()) + { + /* Wine's 'My Documents' does not exist or is unusable. + * Delete it in case it is a dead link, then recreate it. + */ + unlink(pszPersonal); + + if (!pszHome) { - /* '$HOME/My Documents' exists. Create 'My Pictures', 'My Videos' and - * 'My Music' subfolders or fail silently if they already exist. */ - for (i = 0; i < sizeof(aidsMyStuff)/sizeof(aidsMyStuff[0]); i++) { - strcpy(szMyStuffTarget, szPersonalTarget); - if (_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(aidsMyStuff[i]))) - mkdir(szMyStuffTarget, S_IRWXU|S_IRWXG|S_IRWXO); - } - } + /* $HOME does not exist so just create 'My Documents' as a + * directory in the c: drive. + */ + layout=MDL_DIRS; + mkdir(pszPersonal, S_IRWXU|S_IRWXG|S_IRWXO); + } else { - /* '$HOME/My Documents' doesn't exists, but '$HOME' does. */ - strcpy(szPersonalTarget, pszHome); + /* Try to find the Unix equivalent to 'My Documents' */ + layout=MDL_FLAT_LINKS; + for (localize=1; localize >= 0; localize--) + { + for (u=0; folder_mappings[0].unix_location[u] != 0; u++) + { + strcpy(szPersonalTarget, pszHome); + if (_SHAppendToUnixPath(szPersonalTarget, MAKEINTRESOURCEW(folder_mappings[0].unix_location[u]), localize) && + !stat(szPersonalTarget, &statFolder) && + S_ISDIR(statFolder.st_mode) && + statFolder.st_uid == geteuid()) + { + layout=MDL_NESTED_LINKS; + symlink(szPersonalTarget, pszPersonal); + break; + } + } + if (layout != MDL_FLAT_LINKS) + break; + } + if (layout == MDL_FLAT_LINKS) + { + strcpy(szPersonalTarget, pszHome); + symlink(szPersonalTarget, pszPersonal); + localize=1; + } } - - /* Replace 'My Documents' directory with a symlink of fail silently if not empty. */ - rmdir(pszPersonal); - symlink(szPersonalTarget, pszPersonal); + } + else if (pszHome && statFolder.st_dev == statHome.st_dev && + statFolder.st_ino == statHome.st_ino) + { + /* Wine's 'My Documents' is obviously a symbolic link to $HOME */ + strcpy(szPersonalTarget, pszHome); + layout=MDL_FLAT_LINKS; } else { - /* '$HOME' doesn't exist. Create 'My Pictures', 'My Videos' and 'My Music' subdirs - * in '%USERPROFILE%\\My Documents' or fail silently if they already exist. */ - strcpy(szPersonalTarget, pszPersonal); - for (i = 0; i < sizeof(aidsMyStuff)/sizeof(aidsMyStuff[0]); i++) { - strcpy(szMyStuffTarget, szPersonalTarget); - if (_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(aidsMyStuff[i]))) - mkdir(szMyStuffTarget, S_IRWXU|S_IRWXG|S_IRWXO); + lstat(pszPersonal, &statFolder); + if (S_ISLNK(statFolder.st_mode) && + readlink(pszPersonal, szPersonalTarget, sizeof(szPersonalTarget)) > 0) + { + /* Wine's 'My Documents' is a symbolic link, presumably to a + * $HOME subdirectory equivalent to 'My Documents' + */ + layout=MDL_NESTED_LINKS; + } + else + { + /* Wine's 'My Documents' is a simple directory */ + layout=MDL_DIRS; } } - HeapFree(GetProcessHeap(), 0, pszPersonal); - /* Create symbolic links for 'My Pictures', 'My Video' and 'My Music'. */ - for (i=0; i < sizeof(aidsMyStuff)/sizeof(aidsMyStuff[0]); i++) { - /* Create the current 'My Whatever' folder and get it's unix path. */ - hr = SHGetFolderPathW(NULL, acsidlMyStuff[i]|CSIDL_FLAG_CREATE, NULL, - SHGFP_TYPE_DEFAULT, wszTempPath); + /* Create the 'My Stuff' folders now */ + for (i=1; i= 0; l--) + { + for (u=0; folder_mappings[i].unix_location[u] != 0; u++) + { + strcpy(szMyStuffTarget, szPersonalTarget); + if (_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(folder_mappings[i].unix_location[u]), l) && + !stat(szMyStuffTarget, &statFolder) && + S_ISDIR(statFolder.st_mode) && + statFolder.st_uid == geteuid()) + break; + *szMyStuffTarget='\0'; + } + if (*szMyStuffTarget) + break; + } + if (*szMyStuffTarget) + { + /* 'My Stuff' already exists on the Unix side, so link to it */ + symlink(szMyStuffTarget, pszMyStuff); + } + else if (layout == MDL_FLAT_LINKS) + { + /* 'My Stuff' does not exist on the Unix side, so just + * link to $HOME. + */ + symlink(pszHome, pszMyStuff); + } + else + { + /* 'My Stuff' does not exist on the Unix side. So create it + * with the 'best' localization as per the 'nested' layout. + */ + strcpy(szMyStuffTarget, szPersonalTarget); + if (!_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(folder_mappings[i].ids), localize)) + { + /* This should really not happen */ + mkdir(pszMyStuff, S_IRWXU|S_IRWXG|S_IRWXO); + } + else + { + mkdir(szMyStuffTarget, S_IRWXU|S_IRWXG|S_IRWXO); + symlink(szMyStuffTarget, pszMyStuff); + } + } } HeapFree(GetProcessHeap(), 0, pszMyStuff); } /* Last but not least, the Desktop folder */ - strcpy(szDesktopTarget, pszHome); - if (_SHAppendToUnixPath(szDesktopTarget, DesktopW) && - !stat(szDesktopTarget, &statFolder) && S_ISDIR(statFolder.st_mode)) + hr = SHGetFolderPathW(NULL, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, + NULL, SHGFP_TYPE_CURRENT, wszTempPath); + if (SUCCEEDED(hr) && (pszDesktop = wine_get_unix_file_name(wszTempPath))) { - hr = SHGetFolderPathW(NULL, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, NULL, - SHGFP_TYPE_DEFAULT, wszTempPath); - if (SUCCEEDED(hr) && (pszDesktop = wine_get_unix_file_name(wszTempPath))) +#ifdef linux + pszNativeDesktop=szLinuxDesktop; +#elif defined(__APPLE__) + pszNativeDesktop=szMacDesktop; +#else + pszNativeDesktop=szNativeDesktop; +#endif + for (i=0; szDesktops[i]; i++) { - rmdir(pszDesktop); - symlink(szDesktopTarget, pszDesktop); - HeapFree(GetProcessHeap(), 0, pszDesktop); + pszDesktopLink = HeapAlloc(GetProcessHeap(), 0, strlen(pszDesktop) + strlen(szDesktops[i])+1); + strcpy(pszDesktopLink, pszDesktop); + strcat(pszDesktopLink, szDesktops[i]); + rmdir(pszDesktopLink); + if (stat(pszDesktopLink, &statFolder) || + !S_ISDIR(statFolder.st_mode) || statFolder.st_uid != geteuid()) + { + /* Delete the other platforms' links */ + unlink(pszDesktopLink); + + /* And create one for the current platform */ + if (strcmp(szDesktops[i], pszNativeDesktop) == 0 && pszHome) + { + strcpy(szDesktopTarget, pszHome); + if (_SHAppendToUnixPath(szDesktopTarget, DesktopW, 0) && + !stat(szDesktopTarget, &statFolder) && + S_ISDIR(statFolder.st_mode) && + statFolder.st_uid == geteuid()) + { + symlink(szDesktopTarget, pszDesktopLink); + } + } + } + HeapFree(GetProcessHeap(), 0, pszDesktopLink); } + + HeapFree(GetProcessHeap(), 0, pszDesktop); } } +void WINAPI wine_update_symbolic_links(HWND hwnd, HINSTANCE handle, LPCWSTR cmdline, INT show) +{ + TRACE("\n"); + _SHCreateSymbolicLinks(); +} + /* Register the default values in the registry, as some apps seem to depend * on their presence. The set registered was taken from Windows XP. */ @@ -2120,6 +2324,7 @@ HRESULT SHELL_RegisterShellFolders(void) * 'My Video', 'My Music' and 'Desktop' in advance, so that the * _SHRegister*ShellFolders() functions will find everything nice and clean * and thus will not attempt to create them in the profile directory. */ + /* In CrossOver Desktop is not a symlink */ _SHCreateSymbolicLinks(); hr = _SHRegisterUserShellFolders(TRUE); diff --git a/dlls/shell32/shfldr_desktop.c b/dlls/shell32/shfldr_desktop.c index 428c3f710a2..3fee311bf0b 100644 --- a/dlls/shell32/shfldr_desktop.c +++ b/dlls/shell32/shfldr_desktop.c @@ -558,7 +558,7 @@ static HRESULT WINAPI ISF_Desktop_fnGetDisplayNameOf (IShellFolder2 * iface, { IGenericSFImpl *This = (IGenericSFImpl *)iface; HRESULT hr = S_OK; - WCHAR wszPath[MAX_PATH]; + LPWSTR pszPath; TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", This, pidl, dwFlags, strRet); pdump (pidl); @@ -566,13 +566,17 @@ static HRESULT WINAPI ISF_Desktop_fnGetDisplayNameOf (IShellFolder2 * iface, if (!strRet) return E_INVALIDARG; + pszPath = CoTaskMemAlloc((MAX_PATH +1) * sizeof(WCHAR)); + if (!pszPath) + return E_OUTOFMEMORY; + if (_ILIsDesktop (pidl)) { if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) && (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING)) - strcpyW(wszPath, This->sPathTarget); + strcpyW(pszPath, This->sPathTarget); else - HCR_GetClassNameW(&CLSID_ShellDesktop, wszPath, MAX_PATH); + HCR_GetClassNameW(&CLSID_ShellDesktop, pszPath, MAX_PATH); } else if (_ILIsPidlSimple (pidl)) { @@ -627,21 +631,21 @@ static HRESULT WINAPI ISF_Desktop_fnGetDisplayNameOf (IShellFolder2 * iface, * Only the folder itself can know it */ hr = SHELL32_GetDisplayNameOfChild (iface, pidl, dwFlags, - wszPath, + pszPath, MAX_PATH); } else { /* parsing name like ::{...} */ - wszPath[0] = ':'; - wszPath[1] = ':'; - SHELL32_GUIDToStringW (clsid, &wszPath[2]); + pszPath[0] = ':'; + pszPath[1] = ':'; + SHELL32_GUIDToStringW (clsid, &pszPath[2]); } } else { /* user friendly name */ - HCR_GetClassNameW (clsid, wszPath, MAX_PATH); + HCR_GetClassNameW (clsid, pszPath, MAX_PATH); } } else @@ -652,44 +656,43 @@ static HRESULT WINAPI ISF_Desktop_fnGetDisplayNameOf (IShellFolder2 * iface, if ((GET_SHGDN_FOR(dwFlags) == SHGDN_FORPARSING) && (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER)) { - lstrcpynW(wszPath, This->sPathTarget, MAX_PATH - 1); - PathAddBackslashW(wszPath); - cLen = lstrlenW(wszPath); + lstrcpynW(pszPath, This->sPathTarget, MAX_PATH - 1); + PathAddBackslashW(pszPath); + cLen = lstrlenW(pszPath); } - _ILSimpleGetTextW(pidl, wszPath + cLen, MAX_PATH - cLen); + _ILSimpleGetTextW(pidl, pszPath + cLen, MAX_PATH - cLen); if (!_ILIsFolder(pidl)) - SHELL_FS_ProcessDisplayFilename(wszPath, dwFlags); + SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags); } } else { /* a complex pidl, let the subfolder do the work */ hr = SHELL32_GetDisplayNameOfChild (iface, pidl, dwFlags, - wszPath, MAX_PATH); + pszPath, MAX_PATH); } if (SUCCEEDED(hr)) { - BOOL defCharUsed; - strRet->uType = STRRET_CSTR; - if (!WideCharToMultiByte(CP_ACP, 0, wszPath, -1, strRet->u.cStr, MAX_PATH, - NULL, &defCharUsed)) - strRet->u.cStr[0] = '\0'; - if (defCharUsed) + /* Win9x always returns ANSI strings, NT always returns Unicode strings */ + if (GetVersion() & 0x80000000) { - strRet->u.pOleStr = SHAlloc((lstrlenW(This->sPathTarget)+1) * - sizeof(WCHAR)); - if (!strRet->u.pOleStr) - hr = E_OUTOFMEMORY; - else - { - strcpyW(strRet->u.pOleStr, This->sPathTarget); - strRet->uType = STRRET_WSTR; - } + strRet->uType = STRRET_CSTR; + if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->u.cStr, MAX_PATH, + NULL, NULL)) + strRet->u.cStr[0] = '\0'; + CoTaskMemFree(pszPath); + } + else + { + strRet->uType = STRRET_WSTR; + strRet->u.pOleStr = pszPath; } } + else + CoTaskMemFree(pszPath); TRACE ("-- (%p)->(%s,0x%08x)\n", This, strRet->uType == STRRET_CSTR ? strRet->u.cStr : diff --git a/dlls/shell32/shfldr_fs.c b/dlls/shell32/shfldr_fs.c index 5fda4af321d..0fa690df1b2 100644 --- a/dlls/shell32/shfldr_fs.c +++ b/dlls/shell32/shfldr_fs.c @@ -771,7 +771,7 @@ IShellFolder_fnGetDisplayNameOf (IShellFolder2 * iface, LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet) { IGenericSFImpl *This = impl_from_IShellFolder2(iface); - WCHAR wszPath[MAX_PATH+1]; + LPWSTR pszPath; HRESULT hr = S_OK; int len = 0; @@ -782,12 +782,16 @@ IShellFolder_fnGetDisplayNameOf (IShellFolder2 * iface, LPCITEMIDLIST pidl, if (!pidl || !strRet) return E_INVALIDARG; + pszPath = CoTaskMemAlloc((MAX_PATH +1) * sizeof(WCHAR)); + if (!pszPath) + return E_OUTOFMEMORY; + if (_ILIsDesktop(pidl)) { /* empty pidl */ if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) && (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER)) { if (This->sPathTarget) - lstrcpynW(wszPath, This->sPathTarget, MAX_PATH); + lstrcpynW(pszPath, This->sPathTarget, MAX_PATH); } else { /* pidl has to contain exactly one non null SHITEMID */ hr = E_INVALIDARG; @@ -797,24 +801,32 @@ IShellFolder_fnGetDisplayNameOf (IShellFolder2 * iface, LPCITEMIDLIST pidl, (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) && This->sPathTarget) { - lstrcpynW(wszPath, This->sPathTarget, MAX_PATH); - PathAddBackslashW(wszPath); - len = lstrlenW(wszPath); + lstrcpynW(pszPath, This->sPathTarget, MAX_PATH); + PathAddBackslashW(pszPath); + len = lstrlenW(pszPath); } - _ILSimpleGetTextW(pidl, wszPath + len, MAX_PATH + 1 - len); - if (!_ILIsFolder(pidl)) SHELL_FS_ProcessDisplayFilename(wszPath, dwFlags); + _ILSimpleGetTextW(pidl, pszPath + len, MAX_PATH + 1 - len); + if (!_ILIsFolder(pidl)) SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags); } else { - hr = SHELL32_GetDisplayNameOfChild(iface, pidl, dwFlags, wszPath, MAX_PATH); + hr = SHELL32_GetDisplayNameOfChild(iface, pidl, dwFlags, pszPath, MAX_PATH); } if (SUCCEEDED(hr)) { - strRet->uType = STRRET_CSTR; - if (!WideCharToMultiByte(CP_ACP, 0, wszPath, -1, strRet->u.cStr, MAX_PATH, - NULL, NULL)) - strRet->u.cStr[0] = '\0'; - } + /* Win9x always returns ANSI strings, NT always returns Unicode strings */ + if (GetVersion() & 0x80000000) { + strRet->uType = STRRET_CSTR; + if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->u.cStr, MAX_PATH, + NULL, NULL)) + strRet->u.cStr[0] = '\0'; + CoTaskMemFree(pszPath); + } else { + strRet->uType = STRRET_WSTR; + strRet->u.pOleStr = pszPath; + } + } else + CoTaskMemFree(pszPath); - TRACE ("-- (%p)->(%s)\n", This, strRet->u.cStr); + TRACE ("-- (%p)->(%s)\n", This, strRet->uType == STRRET_CSTR ? strRet->u.cStr : debugstr_w(strRet->u.pOleStr)); return hr; } diff --git a/dlls/shell32/shfldr_mycomp.c b/dlls/shell32/shfldr_mycomp.c index e21a231ab2d..1901bde8e38 100644 --- a/dlls/shell32/shfldr_mycomp.c +++ b/dlls/shell32/shfldr_mycomp.c @@ -26,6 +26,7 @@ #include #include #include +#include #define COBJMACROS #define NONAMELESSUNION @@ -51,6 +52,38 @@ WINE_DEFAULT_DEBUG_CHANNEL (shell); /*********************************************************************** +* SHELL32_DisplayUnixPaths +* +* Check if unix paths should be displayed. +*/ +static int bDisplayUnixPath = -1; + +static int SHELL32_DisplayUnixPaths(void) +{ + if (bDisplayUnixPath < 0) + { + HKEY hkey; + + bDisplayUnixPath = 0; + + /* @@ Wine registry key: HKCU\Software\Wine */ + if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine", &hkey)) + { + char buffer[20]; + DWORD type, count = sizeof(buffer); + + if(!RegQueryValueExA(hkey, "DisplayUnixPaths", 0, &type, (LPBYTE)buffer, &count)) + bDisplayUnixPath = atoi(buffer); + + RegCloseKey(hkey); + } + } + + return bDisplayUnixPath; +} + + +/*********************************************************************** * IShellFolder implementation */ @@ -554,7 +587,7 @@ static HRESULT WINAPI ISF_MyComputer_fnGetDisplayNameOf (IShellFolder2 *iface, { IGenericSFImpl *This = (IGenericSFImpl *)iface; - WCHAR wszPath[MAX_PATH]; + LPWSTR pszPath; HRESULT hr = S_OK; TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", This, pidl, dwFlags, strRet); @@ -563,14 +596,18 @@ static HRESULT WINAPI ISF_MyComputer_fnGetDisplayNameOf (IShellFolder2 *iface, if (!strRet) return E_INVALIDARG; - wszPath[0] = 0; + pszPath = CoTaskMemAlloc((MAX_PATH +1) * sizeof(WCHAR)); + if (!pszPath) + return E_OUTOFMEMORY; + + pszPath[0] = 0; if (!pidl->mkid.cb) { /* parsing name like ::{...} */ - wszPath[0] = ':'; - wszPath[1] = ':'; - SHELL32_GUIDToStringW(&CLSID_MyComputer, &wszPath[2]); + pszPath[0] = ':'; + pszPath[1] = ':'; + SHELL32_GUIDToStringW(&CLSID_MyComputer, &pszPath[2]); } else if (_ILIsPidlSimple(pidl)) { @@ -622,11 +659,11 @@ static HRESULT WINAPI ISF_MyComputer_fnGetDisplayNameOf (IShellFolder2 *iface, * Only the folder itself can know it */ hr = SHELL32_GetDisplayNameOfChild (iface, pidl, - dwFlags, wszPath, MAX_PATH); + dwFlags, pszPath, MAX_PATH); } else { - LPWSTR p = wszPath; + LPWSTR p = pszPath; /* parsing name like ::{...} */ p[0] = ':'; @@ -634,7 +671,6 @@ static HRESULT WINAPI ISF_MyComputer_fnGetDisplayNameOf (IShellFolder2 *iface, p += 2; p += SHELL32_GUIDToStringW(&CLSID_MyComputer, p); - /* \:: */ p[0] = '\\'; p[1] = ':'; p[2] = ':'; @@ -645,18 +681,18 @@ static HRESULT WINAPI ISF_MyComputer_fnGetDisplayNameOf (IShellFolder2 *iface, else { /* user friendly name */ - HCR_GetClassNameW (clsid, wszPath, MAX_PATH); + HCR_GetClassNameW (clsid, pszPath, MAX_PATH); } } else { /* append my own path */ - _ILSimpleGetTextW (pidl, wszPath, MAX_PATH); + _ILSimpleGetTextW (pidl, pszPath, MAX_PATH); } } else if (_ILIsDrive(pidl)) { - _ILSimpleGetTextW (pidl, wszPath, MAX_PATH); /* append my own path */ + _ILSimpleGetTextW (pidl, pszPath, MAX_PATH); /* append my own path */ /* long view "lw_name (C:)" */ if (!(dwFlags & SHGDN_FORPARSING)) @@ -666,14 +702,48 @@ static HRESULT WINAPI ISF_MyComputer_fnGetDisplayNameOf (IShellFolder2 *iface, static const WCHAR wszOpenBracket[] = {' ','(',0}; static const WCHAR wszCloseBracket[] = {')',0}; - GetVolumeInformationW (wszPath, wszDrive, + GetVolumeInformationW (pszPath, wszDrive, sizeof(wszDrive)/sizeof(wszDrive[0]) - 6, &dwVolumeSerialNumber, &dwMaximumComponetLength, &dwFileSystemFlags, NULL, 0); + + /* Display unix path if volume has no label */ + if (!wszDrive[0]) + { + char *unix_path; + char real_unix_path[PATH_MAX]; + + unix_path = wine_get_unix_file_name(pszPath); + if (unix_path) + { + realpath(unix_path, real_unix_path); + HeapFree( GetProcessHeap(), 0, unix_path ); + MultiByteToWideChar(CP_UNIXCP, 0, real_unix_path, -1, wszDrive, sizeof(wszDrive)/sizeof(wszDrive[0])); + wszDrive[sizeof(wszDrive)/sizeof(wszDrive[0])-1] = '\0'; + } + } + strcatW (wszDrive, wszOpenBracket); - lstrcpynW (wszDrive + strlenW(wszDrive), wszPath, 3); + + if (SHELL32_DisplayUnixPaths()) + { + char *unix_path; + char real_unix_path[PATH_MAX]; + + unix_path = wine_get_unix_file_name(pszPath); + if (unix_path) + { + realpath(unix_path, real_unix_path); + HeapFree( GetProcessHeap(), 0, unix_path ); + MultiByteToWideChar(CP_UNIXCP, 0, real_unix_path, -1, wszDrive, sizeof(wszDrive)/sizeof(wszDrive[0])); + wszDrive[sizeof(wszDrive)/sizeof(wszDrive[0])-1] = '\0'; + } + } + else + lstrcpynW (wszDrive + strlenW(wszDrive), pszPath, 3); + strcatW (wszDrive, wszCloseBracket); - strcpyW (wszPath, wszDrive); + strcpyW (pszPath, wszDrive); } } else @@ -686,18 +756,30 @@ static HRESULT WINAPI ISF_MyComputer_fnGetDisplayNameOf (IShellFolder2 *iface, else { /* Complex pidl. Let the child folder do the work */ - hr = SHELL32_GetDisplayNameOfChild(iface, pidl, dwFlags, wszPath, MAX_PATH); + hr = SHELL32_GetDisplayNameOfChild(iface, pidl, dwFlags, pszPath, MAX_PATH); } if (SUCCEEDED (hr)) { - strRet->uType = STRRET_CSTR; - if (!WideCharToMultiByte(CP_ACP, 0, wszPath, -1, strRet->u.cStr, MAX_PATH, - NULL, NULL)) - strRet->u.cStr[0] = '\0'; + /* Win9x always returns ANSI strings, NT always returns Unicode strings */ + if (GetVersion() & 0x80000000) + { + strRet->uType = STRRET_CSTR; + if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->u.cStr, MAX_PATH, + NULL, NULL)) + strRet->u.cStr[0] = '\0'; + CoTaskMemFree(pszPath); + } + else + { + strRet->uType = STRRET_WSTR; + strRet->u.pOleStr = pszPath; + } } + else + CoTaskMemFree(pszPath); - TRACE ("-- (%p)->(%s)\n", This, debugstr_w(wszPath)); + TRACE ("-- (%p)->(%s)\n", This, strRet->uType == STRRET_CSTR ? strRet->u.cStr : debugstr_w(strRet->u.pOleStr)); return hr; } diff --git a/dlls/shell32/shfldr_unixfs.c b/dlls/shell32/shfldr_unixfs.c index a4f4ade3cc3..2d06fcd6e1b 100644 --- a/dlls/shell32/shfldr_unixfs.c +++ b/dlls/shell32/shfldr_unixfs.c @@ -1151,6 +1151,7 @@ static HRESULT WINAPI UnixFolder_IShellFolder2_GetDisplayNameOf(IShellFolder2* i hr = IShellFolder_GetDisplayNameOf(pSubFolder, (LPITEMIDLIST)&emptyIDL, uFlags, lpName); IShellFolder_Release(pSubFolder); + goto exit; } } else { WCHAR wszFileName[MAX_PATH]; @@ -1166,7 +1167,17 @@ static HRESULT WINAPI UnixFolder_IShellFolder2_GetDisplayNameOf(IShellFolder2* i } } - TRACE("--> %s\n", debugstr_w(lpName->u.pOleStr)); + if (SUCCEEDED(hr) && (GetVersion() & 0x80000000)) + { + /* Win9x shell32 returns an ANSI string */ + WCHAR *strW = lpName->u.pOleStr; + WideCharToMultiByte(CP_ACP, 0, strW, -1, lpName->u.cStr, MAX_PATH, NULL, NULL); + lpName->uType = STRRET_CSTR; + SHFree( strW ); + } + +exit: + TRACE("--> %s\n", lpName->uType == STRRET_CSTR ? lpName->u.cStr : debugstr_w(lpName->u.pOleStr)); return hr; } diff --git a/dlls/shell32/shlexec.c b/dlls/shell32/shlexec.c index 2d4a25e6740..5c37902a3f1 100644 --- a/dlls/shell32/shlexec.c +++ b/dlls/shell32/shlexec.c @@ -370,6 +370,62 @@ static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait, return retval; } +/* + * Helper function for ShellExecuteExA + * In order to prevent opening of particular extension types + */ +static BOOL verify_extension_permission(const WCHAR* ext) +{ + static const WCHAR AppDefaultsW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\', + 'A','p','p','D','e','f','a','u','l','t','s',0}; + static const WCHAR DenyShellExecuteW[] = {'D','e','n','y','S','h','e','l','l','E','x','e','c','u','t','e',0}; + WCHAR buffer[MAX_PATH]; + WCHAR *filename; + HKEY hkey,appkey; + int RC; + DWORD type,count; + + if(!GetModuleFileNameW(0,buffer,MAX_PATH)) + return TRUE; + + filename = PathFindFileNameW(buffer); + /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe */ + if (RegOpenKeyW( HKEY_CURRENT_USER, AppDefaultsW, &hkey )) + return TRUE; + + if (RegOpenKeyW( hkey, filename, &appkey )) appkey = 0; + RegCloseKey( hkey ); + + if (!appkey) + return TRUE; + + RC = TRUE; + count = sizeof(buffer); + if (!RegQueryValueExW(appkey,DenyShellExecuteW,NULL,&type,(LPBYTE)buffer,&count)) + { + WCHAR *s,*e; + int lext; + + buffer[count / sizeof(WCHAR)] = 0; + ext++; /* Skip the '.' */ + lext=strlenW(ext); + s=buffer; + while (*s) { + e=strchrW(s,';'); + if (!e) + e=s+strlenW(s); + if ((e-s==lext) && (strncmpiW(ext,s,lext)==0)) + { + RC=FALSE; + break; + } + s=(*e?e+1:e); + } + } + RegCloseKey(appkey); + return RC; +} + /*********************************************************************** * SHELL_BuildEnvW [Internal] @@ -607,6 +663,8 @@ UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpOperation, return SE_ERR_NOASSOC; } + if (!verify_extension_permission(extension)) return 31; /* no association */ + /* Three places to check: */ /* 1. win.ini, [windows], programs (NB no leading '.') */ /* 2. Registry, HKEY_CLASS_ROOT\\shell\open\command */ @@ -896,7 +954,7 @@ static UINT_PTR execute_from_key(LPWSTR key, LPCWSTR lpFile, WCHAR *env, LPCWSTR /* Is there a replace() function anywhere? */ cmdlen /= sizeof(WCHAR); cmd[cmdlen] = '\0'; - if (!SHELL_ArgifyW(param, sizeof(param)/sizeof(WCHAR), cmd, lpFile, psei->lpIDList, szCommandline, &resultLen)) + if (!SHELL_ArgifyW(param, sizeof(param)/sizeof(WCHAR), cmd, lpFile, psei->lpIDList, szCommandline, &resultLen) && lpFile[0]) { /* looks like there is no %1 param in the cmd, add one */ static const WCHAR oneW[] = { ' ','\"','%','1','\"',0 }; @@ -960,6 +1018,37 @@ HINSTANCE WINAPI FindExecutableA(LPCSTR lpFile, LPCSTR lpDirectory, LPSTR lpResu return retval; } +static UINT_PTR SHELL_CrossOverFallback(const WCHAR* lpFile, const WCHAR* lpVerb, WCHAR* cmdFormat, int cmdFormatSize) +{ + /* See if there is a native association for this file. + * This is a CodeWeavers only hack. + * + * But before that, check that this is not the file we just opened + * in order to avoid native -> wine -> native association loops. + */ + UINT_PTR retval = SE_ERR_NOASSOC; + static const WCHAR NoCrossOverFallbackW[] = {'N','O','C','R','O','S','S','O','V','E','R','F','A','L','L','B','A','C','K',0}; + WCHAR* nofallback=NULL; + int size=GetEnvironmentVariableW(NoCrossOverFallbackW, NULL, 0); + if (size) + { + nofallback=HeapAlloc(GetProcessHeap(), 0, size*sizeof(*nofallback)); + GetEnvironmentVariableW(NoCrossOverFallbackW, nofallback, size); + TRACE("NoCrossOverFallback=%s\n", debugstr_w(nofallback)); + } + if (!nofallback || strcmpW(nofallback, lpFile) != 0) + { + WCHAR szFallback[MAX_PATH] = {'C','r','o','s','s','O','v','e','r','F','a','l','l','b','a','c','k',0}; + + TRACE("Trying CrossOverFallback, verb=%s\n", debugstr_w(lpVerb)); + retval=SHELL_FindExecutableByOperation(lpVerb, NULL, szFallback, cmdFormat, cmdFormatSize); + } + if (nofallback) + HeapFree(GetProcessHeap(), 0, nofallback); + TRACE("CrossOverFallback returning %d\n", retval); + return retval; +} + /************************************************************************* * FindExecutableW [SHELL32.@] * @@ -1004,6 +1093,35 @@ HINSTANCE WINAPI FindExecutableW(LPCWSTR lpFile, LPCWSTR lpDirectory, LPWSTR lpR retval = SHELL_FindExecutable(lpDirectory, lpFile, wszOpen, lpResult, MAX_PATH, NULL, NULL, NULL, NULL); + if (retval <= 32) + { + retval=SHELL_CrossOverFallback(lpFile, wszOpen, lpResult, MAX_PATH*sizeof(*lpResult)); + if (retval > 32) + { + /* Remove double quotation marks and command line arguments */ + if (*lpResult == '"') + { + WCHAR *p = lpResult; + while (*(p + 1) != '"') + { + *p = *(p + 1); + p++; + } + *p = '\0'; + } + else + { + /* Truncate on first space, like Windows: + * http://support.microsoft.com/?scid=kb%3Ben-us%3B140724 + */ + WCHAR *p = lpResult; + while (*p != ' ' && *p != '\0') + p++; + *p='\0'; + } + } + } + TRACE("returning %s\n", debugstr_w(lpResult)); if (lpDirectory) SetCurrentDirectoryW(old_dir); @@ -1295,6 +1413,7 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc ) WCHAR wcmd[1024]; WCHAR buffer[MAX_PATH]; BOOL done; + BOOL appKnownSingular = FALSE; /* make a local copy of the LPSHELLEXECUTEINFO structure and work with this from now on */ memcpy(&sei_tmp, sei, sizeof(sei_tmp)); @@ -1322,6 +1441,7 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc ) memcpy(wszApplicationName, sei_tmp.lpFile+1, (l+1)*sizeof(WCHAR)); if (wszApplicationName[l-1] == '\"') wszApplicationName[l-1] = '\0'; + appKnownSingular = TRUE; TRACE("wszApplicationName=%s\n",debugstr_w(wszApplicationName)); } else { DWORD l = strlenW(sei_tmp.lpFile)+1; @@ -1370,6 +1490,7 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc ) } SHGetPathFromIDListW(sei_tmp.lpIDList, wszApplicationName); + appKnownSingular = TRUE; TRACE("-- idlist=%p (%s)\n", sei_tmp.lpIDList, debugstr_w(wszApplicationName)); } @@ -1399,8 +1520,10 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc ) done = SHELL_ArgifyW(wcmd, sizeof(wcmd)/sizeof(WCHAR), wszParameters, wszApplicationName, sei_tmp.lpIDList, NULL, &resultLen); if (!done && wszApplicationName[0]) { - strcatW(wcmd, wSpace); - strcatW(wcmd, wszApplicationName); + /* looks like there is no %1 param in the cmd, add one */ + static const WCHAR oneW[] = { ' ','\"','%','1','\"',0 }; + strcatW(wszParameters, oneW); + SHELL_ArgifyW(wcmd, sizeof(wcmd)/sizeof(WCHAR), wszParameters, wszApplicationName, sei_tmp.lpIDList, NULL, &resultLen); } if (resultLen > sizeof(wcmd)/sizeof(WCHAR)) ERR("Argify buffer not large enough... truncating\n"); @@ -1419,6 +1542,7 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc ) /* open shell folder for the specified class GUID */ strcpyW(wszParameters, buffer); strcpyW(wszApplicationName, wExplorer); + appKnownSingular = TRUE; sei_tmp.fMask &= ~SEE_MASK_INVOKEIDLIST; } else { @@ -1438,6 +1562,7 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc ) buffer, target, sei_tmp.lpIDList, NULL, &resultLen); if (resultLen > dwApplicationNameLen) ERR("Argify buffer not large enough... truncating\n"); + appKnownSingular = FALSE; } sei_tmp.fMask &= ~SEE_MASK_INVOKEIDLIST; } @@ -1455,6 +1580,7 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc ) HeapFree(GetProcessHeap(), 0, wszApplicationName); dwApplicationNameLen = len+1; wszApplicationName = buf; + /* appKnownSingular unmodified */ sei_tmp.lpFile = wszApplicationName; } @@ -1495,7 +1621,7 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc ) TRACE("execute:%s,%s,%s\n", debugstr_w(wszApplicationName), debugstr_w(wszParameters), debugstr_w(wszDir)); /* separate out command line arguments from executable file name */ - if (!*sei_tmp.lpParameters) { + if (!*sei_tmp.lpParameters && !appKnownSingular) { /* If the executable path is quoted, handle the rest of the command line as parameters. */ if (sei_tmp.lpFile[0] == '"') { LPWSTR src = wszApplicationName/*sei_tmp.lpFile*/ + 1; @@ -1632,6 +1758,32 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc ) strcatW(lpstrTmpFile, lpFile); retval = (UINT_PTR)ShellExecuteW(sei_tmp.hwnd, sei_tmp.lpVerb, lpstrTmpFile, NULL, NULL, 0); } + else + { + WCHAR wCmdFormat[1024]; + retval=SHELL_CrossOverFallback(lpFile, sei_tmp.lpVerb, wCmdFormat, sizeof(wCmdFormat)); + if (retval > 32) + { + + WCHAR wCommandLine[1024]; + DWORD len; + TRACE("wCmdFormat=%s\n", debugstr_w(wCmdFormat)); + SHELL_ArgifyW(wCommandLine, 1024, wCmdFormat, lpFile, sei_tmp.lpIDList, NULL, &len); + TRACE("wCommandLine=%s\n", debugstr_w(wCommandLine)); + sei_tmp.fMask|=SEE_MASK_NOCLOSEPROCESS; + retval = execfunc(wCommandLine, env, FALSE, &sei_tmp, sei); + if (retval > 32) + { + DWORD retcode; + WaitForSingleObject(sei->hProcess, INFINITE); + GetExitCodeProcess(sei->hProcess, &retcode); + CloseHandle(sei->hProcess); + sei->hProcess=NULL; + TRACE("CrossOverFallback returned %d\n", retcode); + retval=(retcode == 0 ? 33 : 31); + } + } + } TRACE("retval %u\n", retval); diff --git a/dlls/shell32/shlfileop.c b/dlls/shell32/shlfileop.c index 5410c97a71e..c624cb8a5cd 100644 --- a/dlls/shell32/shlfileop.c +++ b/dlls/shell32/shlfileop.c @@ -352,27 +352,36 @@ BOOL SHELL_DeleteDirectoryW(HWND hwnd, LPCWSTR pszDir, BOOL bShowUI) HANDLE hFind; WIN32_FIND_DATAW wfd; WCHAR szTemp[MAX_PATH]; + WCHAR szPath[MAX_PATH]; + BOOL foundOne; /* Make sure the directory exists before eventually prompting the user */ - PathCombineW(szTemp, pszDir, wWildcardFile); - hFind = FindFirstFileW(szTemp, &wfd); - if (hFind == INVALID_HANDLE_VALUE) - return FALSE; + PathCombineW(szPath, pszDir, wWildcardFile); if (!bShowUI || (ret = SHELL_ConfirmDialogW(hwnd, ASK_DELETE_FOLDER, pszDir, NULL))) { do { - if (IsDotDir(wfd.cFileName)) - continue; - PathCombineW(szTemp, pszDir, wfd.cFileName); - if (FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes) - ret = SHELL_DeleteDirectoryW(hwnd, szTemp, FALSE); - else - ret = (SHNotifyDeleteFileW(szTemp) == ERROR_SUCCESS); - } while (ret && FindNextFileW(hFind, &wfd)); + foundOne = FALSE; + hFind = FindFirstFileW(szPath, &wfd); + if (hFind == INVALID_HANDLE_VALUE) + return FALSE; + + do + { + if (IsDotDir(wfd.cFileName)) + continue; + foundOne = TRUE; + PathCombineW(szTemp, pszDir, wfd.cFileName); + if (FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes) + ret = SHELL_DeleteDirectoryW(hwnd, szTemp, FALSE); + else + ret = (SHNotifyDeleteFileW(szTemp) == ERROR_SUCCESS); + } while (ret && FindNextFileW(hFind, &wfd)); + + FindClose(hFind); + }while (ret && foundOne); } - FindClose(hFind); if (ret) ret = (SHNotifyRemoveDirectoryW(pszDir) == ERROR_SUCCESS); return ret; diff --git a/dlls/shell32/shlfolder.c b/dlls/shell32/shlfolder.c index 6ab490806dc..e99ce2bfe10 100644 --- a/dlls/shell32/shlfolder.c +++ b/dlls/shell32/shlfolder.c @@ -222,13 +222,10 @@ static HRESULT SHELL32_CoCreateInitSF (LPCITEMIDLIST pidlRoot, LPCWSTR pathRoot, } if (pidlChild) { - LPCSTR pszChild = _ILGetTextPointer(pidlChild); int len = lstrlenW(ppfti.szTargetParsingName); - if (pszChild) - MultiByteToWideChar (CP_ACP, 0, pszChild, -1, ppfti.szTargetParsingName + len, MAX_PATH - len); - else - hr = E_INVALIDARG; + if (!_ILSimpleGetTextW(pidlChild, ppfti.szTargetParsingName + len, MAX_PATH - len)) + hr = E_INVALIDARG; } IPersistFolder3_InitializeEx (ppf, NULL, pidlAbsolute, &ppfti); @@ -290,7 +287,9 @@ HRESULT SHELL32_BindToChild (LPCITEMIDLIST pidlRoot, lstrcpynW(wszFolderPath, pathRoot, MAX_PATH); pwszPathTail = PathAddBackslashW(wszFolderPath); } - MultiByteToWideChar(CP_ACP, 0, _ILGetTextPointer(pidlChild), -1, pwszPathTail, MAX_PATH - (int)(pwszPathTail - wszFolderPath)); + + _ILSimpleGetTextW(pidlChild,pwszPathTail,MAX_PATH - (int)(pwszPathTail - wszFolderPath)); + if (SHELL32_GetCustomFolderAttributeFromPath (wszFolderPath, wszDotShellClassInfo, wszCLSID, wszCLSIDValue, CHARS_IN_GUID)) CLSIDFromString (wszCLSIDValue, &clsidFolder); @@ -311,6 +310,17 @@ HRESULT SHELL32_BindToChild (LPCITEMIDLIST pidlRoot, IShellFolder_Release (pSF); } + /* + * Return the correct interface + */ + if ((hr==S_OK)&&(riid)) + { + IShellFolder **check = (IShellFolder **)ppvOut; + hr = IShellView_QueryInterface(*check, riid, ppvOut); + if (hr==S_OK) + IShellFolder_Release(*check); + } + TRACE ("-- returning (%p) %08x\n", *ppvOut, hr); return hr; diff --git a/dlls/shell32/shlview.c b/dlls/shell32/shlview.c index e7eafc1a633..3f471ee59e1 100644 --- a/dlls/shell32/shlview.c +++ b/dlls/shell32/shlview.c @@ -2011,6 +2011,7 @@ static HRESULT WINAPI IShellView_fnSelectItem( static HRESULT WINAPI IShellView_fnGetItemObject(IShellView * iface, UINT uItem, REFIID riid, LPVOID *ppvOut) { + HRESULT hr = S_OK; IShellViewImpl *This = (IShellViewImpl *)iface; TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n",This, uItem, debugstr_guid(riid), ppvOut); @@ -2032,7 +2033,18 @@ static HRESULT WINAPI IShellView_fnGetItemObject(IShellView * iface, UINT uItem, if(!*ppvOut) return E_OUTOFMEMORY; - return S_OK; + /* + * Return the correct interface + */ + if (riid) + { + IUnknown *check = *ppvOut; + hr = IUnknown_QueryInterface(check, riid, ppvOut); + if (hr==S_OK) + IUnknown_Release(check); + } + + return hr; } static const IShellViewVtbl svvt = diff --git a/dlls/shell32/shresdef.h b/dlls/shell32/shresdef.h index 3619353ec8c..500043108c7 100644 --- a/dlls/shell32/shresdef.h +++ b/dlls/shell32/shresdef.h @@ -94,6 +94,10 @@ #define IDS_CANTTRASH_TEXT 140 #define IDS_OVERWRITEFOLDER_TEXT 141 +#define WINE_IDS_PICTURES 1000 +#define WINE_IDS_MUSIC 1001 +#define WINE_IDS_MOVIES 1002 + /* Note: this string is referenced from the registry*/ #define IDS_RECYCLEBIN_FOLDER_NAME 8964 diff --git a/dlls/shell32/version.h b/dlls/shell32/version.h index cd0d8dbb9c7..e97eca3d04f 100644 --- a/dlls/shell32/version.h +++ b/dlls/shell32/version.h @@ -18,11 +18,11 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#define WINE_FILEVERSION_MAJOR 5 -#define WINE_FILEVERSION_MINOR 0 -#define WINE_FILEVERSION_BUILD 3900 -#define WINE_FILEVERSION_PLATFORMID 6975 +#define WINE_FILEVERSION_MAJOR 4 +#define WINE_FILEVERSION_MINOR 72 +#define WINE_FILEVERSION_BUILD 3110 +#define WINE_FILEVERSION_PLATFORMID 1 /* FIXME: when libs/wpp gets fixed to support concatenation we can remove * this and define it in version.rc */ -#define WINE_FILEVERSION_STR "5.0.3900.6975" +#define WINE_FILEVERSION_STR "4.72.3110.1" diff --git a/dlls/shlwapi/shlwapi.spec b/dlls/shlwapi/shlwapi.spec index 8d2cd852778..c1cebdd0569 100644 --- a/dlls/shlwapi/shlwapi.spec +++ b/dlls/shlwapi/shlwapi.spec @@ -334,7 +334,7 @@ 334 stdcall -noname SHGetPathFromIDListWrapW(ptr ptr) 335 stdcall -noname ShellExecuteExWrapW(ptr) 336 stdcall -noname SHFileOperationWrapW(ptr) -337 stdcall @(wstr long ptr ptr long) user32.ExtractIconExW +337 stdcall @(wstr long ptr ptr long) user32.PrivateExtractIconExW 338 stdcall @(wstr long) kernel32.SetFileAttributesW 339 stdcall @(long long wstr ptr ptr long) kernel32.GetNumberFormatW 340 stdcall @(long wstr wstr long) user32.MessageBoxW diff --git a/dlls/user32/button.c b/dlls/user32/button.c index 14416e2b7bc..8a255435027 100644 --- a/dlls/user32/button.c +++ b/dlls/user32/button.c @@ -199,7 +199,9 @@ static inline UINT get_button_type( LONG window_style ) /* paint a button of any type */ static inline void paint_button( HWND hwnd, LONG style, UINT action ) { - if (btnPaintFunc[style] && IsWindowVisible(hwnd)) + RECT rc; + GetClientRect( hwnd, &rc ); + if (btnPaintFunc[style] && IsWindowVisible(hwnd) && !IsRectEmpty(&rc)) { HDC hdc = GetDC( hwnd ); btnPaintFunc[style]( hwnd, hdc, action ); diff --git a/dlls/user32/combo.c b/dlls/user32/combo.c index 4be67cc72cd..a849685d2c3 100644 --- a/dlls/user32/combo.c +++ b/dlls/user32/combo.c @@ -1583,12 +1583,19 @@ static void CBResetPos( */ static void COMBO_Size( LPHEADCOMBO lphc, BOOL bRedraw ) { + RECT oldtext,olddrop; + CopyRect(&oldtext,&lphc->textRect); + CopyRect(&olddrop,&lphc->droppedRect); + CBCalcPlacement(lphc->self, lphc, &lphc->textRect, &lphc->buttonRect, &lphc->droppedRect); + if (EqualRect(&oldtext,&lphc->textRect) && + EqualRect(&olddrop,&lphc->droppedRect)) + return; CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, bRedraw ); } @@ -1974,7 +1981,13 @@ static LRESULT ComboWndProc_common( HWND hwnd, UINT message, else return CB_ERR; case WM_DRAWITEM: + /* + * WM_DELETEITEM causes an infinite loop within the ACT2000 installer + * so we need to revisit why this is here and why we get the loop in + * ACT2000 + * case WM_DELETEITEM: + */ case WM_COMPAREITEM: case WM_MEASUREITEM: return COMBO_ItemOp(lphc, message, lParam); diff --git a/dlls/user32/cursoricon.c b/dlls/user32/cursoricon.c index 38e2ac6bf10..99c2595c6e0 100644 --- a/dlls/user32/cursoricon.c +++ b/dlls/user32/cursoricon.c @@ -1919,6 +1919,12 @@ BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon, TRACE_(icon)("(hdc=%p,pos=%d.%d,hicon=%p,extend=%d.%d,istep=%d,br=%p,flags=0x%08x)\n", hdc,x0,y0,hIcon,cxWidth,cyWidth,istep,hbr,flags ); + if( ptr->bPlanes != 1 ) + { + ERR("bad icon!\n"); + GlobalUnlock16(HICON_16(hIcon)); + return FALSE; + } hMemDC = CreateCompatibleDC (hdc); if (istep) FIXME_(icon)("Ignoring istep=%d\n", istep); @@ -2145,6 +2151,15 @@ static HBITMAP BITMAP_Load( HINSTANCE instance, LPCWSTR name, else { if (!(ptr = map_fileW( name, NULL ))) return 0; + + /* we need to make sure this is a bitmap before we move on */ + if (((BITMAPFILEHEADER*)ptr)->bfType != 0x4D42) + { + WARN("Not a bitmap file\n"); + UnmapViewOfFile( ptr ); + return 0; + } + info = (BITMAPINFO *)(ptr + sizeof(BITMAPFILEHEADER)); } diff --git a/dlls/user32/edit.c b/dlls/user32/edit.c index bbd8a0560ad..92f7e28acd4 100644 --- a/dlls/user32/edit.c +++ b/dlls/user32/edit.c @@ -59,6 +59,7 @@ #include "wine/unicode.h" #include "controls.h" #include "user_private.h" +#include "winreg.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(edit); @@ -291,6 +292,38 @@ static void EDIT_ImeComposition(HWND hwnd, LPARAM CompFlag, EDITSTATE *es); LRESULT WINAPI EditWndProcA(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); LRESULT WINAPI EditWndProcW(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +/*********************************************************************** +* USER32_DisplayUnixPaths +* +* Check if unix paths should be displayed. +*/ +static int bDisplayUnixPath = -1; + +int USER32_DisplayUnixPaths(EDITSTATE *es) +{ + if (bDisplayUnixPath < 0) + { + HKEY hkey; + + bDisplayUnixPath = 0; + + /* @@ Wine registry key: HKCU\Software\Wine */ + if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine", &hkey)) + { + char buffer[20]; + DWORD type, count = sizeof(buffer); + + if(!RegQueryValueExA(hkey, "DisplayUnixPaths", 0, &type, (LPBYTE)buffer, &count)) + bDisplayUnixPath = atoi(buffer); + + RegCloseKey(hkey); + } + } + + return bDisplayUnixPath && !(es->style & ES_MULTILINE) && strchrW(es->text, '/'); +} + + /********************************************************************* * edit class descriptor */ @@ -438,7 +471,7 @@ static LRESULT WINAPI EditWndProc_common( HWND hwnd, UINT msg, EDITSTATE *es = (EDITSTATE *)GetWindowLongPtrW( hwnd, 0 ); LRESULT result = 0; - TRACE("hwnd=%p msg=%x (%s) wparam=%x lparam=%lx\n", hwnd, msg, SPY_GetMsgName(msg, hwnd), wParam, lParam); + TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", hwnd, msg, wParam, lParam); if (!es && msg != WM_NCCREATE) return DefWindowProcT(hwnd, msg, wParam, lParam, unicode); @@ -598,6 +631,11 @@ static LRESULT WINAPI EditWndProc_common( HWND hwnd, UINT msg, case EM_LINELENGTH16: case EM_LINELENGTH: + if (USER32_DisplayUnixPaths(es)) + { + WCHAR textW[MAX_PATH]; + return EDIT_WM_GetText(es, MAX_PATH, textW, TRUE); + } result = (LRESULT)EDIT_EM_LineLength(es, (INT)wParam); break; @@ -894,6 +932,11 @@ static LRESULT WINAPI EditWndProc_common( HWND hwnd, UINT msg, break; case WM_GETTEXTLENGTH: + if (USER32_DisplayUnixPaths(es)) + { + WCHAR textW[MAX_PATH]; + return EDIT_WM_GetText(es, MAX_PATH, textW, TRUE); + } if (unicode) result = strlenW(es->text); else result = WideCharToMultiByte( CP_ACP, 0, es->text, strlenW(es->text), NULL, 0, NULL, NULL ); @@ -4257,9 +4300,19 @@ static LRESULT EDIT_WM_EraseBkGnd(EDITSTATE *es, HDC dc) */ static INT EDIT_WM_GetText(EDITSTATE *es, INT count, LPWSTR dst, BOOL unicode) { + WCHAR text[MAX_PATH]; + LPWSTR lptext = es->text; + if(!count) return 0; - if(unicode) + if (USER32_DisplayUnixPaths(es)) + { + INT len = GetShortPathNameW(es->text, text, MAX_PATH); + if (len && len < MAX_PATH) + lptext = text; + } + + if (unicode) { lstrcpynW(dst, es->text, count); return strlenW(dst); @@ -5024,12 +5077,14 @@ static void EDIT_WM_SetFont(EDITSTATE *es, HFONT font, BOOL redraw) */ static void EDIT_WM_SetText(EDITSTATE *es, LPCWSTR text, BOOL unicode) { + INT countW; LPWSTR textW = NULL; + if (!unicode && text) { LPCSTR textA = (LPCSTR)text; - INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0); - textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR)); + countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0); + textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR)); if (textW) MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW); text = textW; @@ -5043,6 +5098,23 @@ static void EDIT_WM_SetText(EDITSTATE *es, LPCWSTR text, BOOL unicode) EDIT_EM_SetSel(es, 0, (UINT)-1, FALSE); if (text) { + if (USER32_DisplayUnixPaths(es)) + { + char *textA = wine_get_unix_file_name( text ); + + if (!unicode) + HeapFree(GetProcessHeap(), 0, textW); + + countW = MultiByteToWideChar(CP_UNIXCP, 0, textA, -1, NULL, 0); + if ((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR)))) + { + MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW); + unicode = FALSE; /* Force text to be freed */ + text = textW; + } + HeapFree( GetProcessHeap(), 0, textA ); + } + TRACE("%s\n", debugstr_w(text)); EDIT_EM_ReplaceSel(es, FALSE, text, FALSE, FALSE); if(!unicode) diff --git a/dlls/user32/menu.c b/dlls/user32/menu.c index 63cb4442e1c..9ad64c88c4c 100644 --- a/dlls/user32/menu.c +++ b/dlls/user32/menu.c @@ -4375,6 +4375,22 @@ BOOL WINAPI IsMenu(HMENU hmenu) } /********************************************************************** + * check_MENUITEMINFO_size + */ +static BOOL check_MENUITEMINFO_size(LPMENUITEMINFOW lpmii) +{ + if (lpmii->cbSize == sizeof(MENUITEMINFOW)) + return TRUE; + /* + * an old version of MENUITEMINFO lacked the hbmpItem field. + */ + if (lpmii->cbSize == (sizeof(MENUITEMINFOW) - sizeof(HBITMAP))) + return TRUE; + + return FALSE; +} + +/********************************************************************** * GetMenuItemInfo_common */ @@ -4388,6 +4404,14 @@ static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos, if (!menu) return FALSE; + /* check for a valid structure */ + if (!check_MENUITEMINFO_size(lpmii)) + { + ERR("Invalid structure size: %i\n", lpmii->cbSize); + SetLastError(ERROR_BAD_ARGUMENTS); + return FALSE; + } + if( lpmii->fMask & MIIM_TYPE) { if( lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP)) { WARN("invalid combination of fMask bits used\n"); @@ -4555,6 +4579,14 @@ static BOOL SetMenuItemInfo_common(MENUITEM * menu, debug_print_menuitem("SetMenuItemInfo_common from: ", menu, ""); + if (lpmii->fMask & ~(MIIM_BITMAP | MIIM_CHECKMARKS | MIIM_DATA | MIIM_FTYPE + | MIIM_ID | MIIM_STATE | MIIM_STRING | MIIM_SUBMENU | + MIIM_TYPE)) + { + FIXME("Invalid or Unhandled fMask(%x)\n",lpmii->fMask); + return FALSE; + } + if (lpmii->fMask & MIIM_TYPE ) { if( lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP)) { WARN("invalid combination of fMask bits used\n"); diff --git a/dlls/user32/message.c b/dlls/user32/message.c index bde85d9a2dc..bad3927a9fa 100644 --- a/dlls/user32/message.c +++ b/dlls/user32/message.c @@ -2498,6 +2498,13 @@ LRESULT WINAPI SendMessageW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) LRESULT WINAPI SendMessageA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { DWORD_PTR res = 0; + + /*------------------------------------------------------------------------ + ** Hack for Shockwave. + **----------------------------------------------------------------------*/ + if (msg == 0x9e0) + usleep(0); + SendMessageTimeoutA( hwnd, msg, wparam, lparam, SMTO_NORMAL, 0, &res ); return res; } @@ -2767,31 +2774,23 @@ BOOL WINAPI PeekMessageW( MSG *msg_out, HWND hwnd, UINT first, UINT last, UINT f hwnd = WIN_GetFullHandle( hwnd ); - for (;;) + if (!peek_message( &msg, hwnd, first, last, flags )) { - if (!peek_message( &msg, hwnd, first, last, flags )) + if (!(flags & PM_NOYIELD)) { - if (!(flags & PM_NOYIELD)) - { - DWORD count; - ReleaseThunkLock(&count); - NtYieldExecution(); - if (count) RestoreThunkLock(count); - } - return FALSE; + DWORD count; + ReleaseThunkLock(&count); + NtYieldExecution(); + if (count) RestoreThunkLock(count); } - if (msg.message & 0x80000000) - { - if (!(flags & PM_REMOVE)) - { - /* Have to remove the message explicitly. - Do this before handling it, because the message handler may - call PeekMessage again */ - peek_message( &msg, msg.hwnd, msg.message, msg.message, flags | PM_REMOVE ); - } + return FALSE; + } + if (msg.message & 0x80000000) + { + if (flags & PM_REMOVE) handle_internal_message( msg.hwnd, msg.message, msg.wParam, msg.lParam ); - } - else break; + msg.message = WM_NULL; + msg.hwnd = 0; } thread_info->GetMessageTimeVal = msg.time; diff --git a/dlls/user32/msgbox.c b/dlls/user32/msgbox.c index 0143d5d815c..28e141b76bc 100644 --- a/dlls/user32/msgbox.c +++ b/dlls/user32/msgbox.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include #include #include @@ -349,6 +350,11 @@ static INT_PTR CALLBACK MSGBOX_DlgProc( HWND hwnd, UINT message, */ INT WINAPI MessageBoxA(HWND hWnd, LPCSTR text, LPCSTR title, UINT type) { + if (getenv("CX_HACK_SIEBELMSJVM")) + { + if (!hWnd && !strncmp("This application or DLL can not be loaded", text, 41)) + return MB_OK; + } return MessageBoxExA(hWnd, text, title, type, LANG_NEUTRAL); } diff --git a/dlls/user32/painting.c b/dlls/user32/painting.c index c3616100585..b81683c5c58 100644 --- a/dlls/user32/painting.c +++ b/dlls/user32/painting.c @@ -820,11 +820,12 @@ INT WINAPI ScrollWindowEx( HWND hwnd, INT dx, INT dy, hwnd = WIN_GetFullHandle( hwnd ); GetClientRect(hwnd, &rc); - if (rect) IntersectRect(&rc, &rc, rect); if (clipRect) IntersectRect(&cliprc,&rc,clipRect); else cliprc = rc; + if (rect) IntersectRect(&rc, &rc, rect); + if( hrgnUpdate ) bOwnRgn = FALSE; else if( bUpdate ) hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 ); @@ -891,6 +892,8 @@ INT WINAPI ScrollWindowEx( HWND hwnd, INT dx, INT dy, DeleteObject( hrgnClip ); } DeleteObject( hrgnTemp ); + if (rcUpdate) + GetRgnBox( hrgnUpdate, rcUpdate); } else { /* nothing was scrolled */ if( !bOwnRgn) diff --git a/dlls/user32/scroll.c b/dlls/user32/scroll.c index d24770fd941..052e6d87a03 100644 --- a/dlls/user32/scroll.c +++ b/dlls/user32/scroll.c @@ -904,6 +904,9 @@ static void SCROLL_HandleScrollEvent( HWND hwnd, INT nBar, UINT msg, POINT pt) case SCROLL_TOP_ARROW: SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical, (hittest == SCROLL_trackHitTest), FALSE ); + SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize, + thumbPos, infoPtr->flags, vertical, + (hittest == SCROLL_trackHitTest), FALSE ); if (hittest == SCROLL_trackHitTest) { if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER)) @@ -1009,6 +1012,9 @@ static void SCROLL_HandleScrollEvent( HWND hwnd, INT nBar, UINT msg, POINT pt) case SCROLL_BOTTOM_ARROW: SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical, FALSE, (hittest == SCROLL_trackHitTest) ); + SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize, + thumbPos, infoPtr->flags, vertical, + FALSE, (hittest == SCROLL_trackHitTest) ); if (hittest == SCROLL_trackHitTest) { if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER)) diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index 50b00c8eea7..25d330088a3 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -192,14 +192,30 @@ static const struct message WmSWP_ResizePopupSeq[] = { */ static const struct message WmSWP_MoveSeq[] = { { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE }, - { WM_NCPAINT, sent|optional }, - { WM_GETTEXT, sent|defwinproc|optional }, - { WM_ERASEBKGND, sent|optional }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE }, { WM_MOVE, sent|defwinproc|wparam, 0 }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, { 0 } }; +/* Resize with SetWindowPos(SWP_NOZORDER) + * for a visible overlapped window + * SWP_NOZORDER is stripped by the logging code + */ +static const struct message WmSWP_ResizeNoZOrder[] = { + { WM_WINDOWPOSCHANGING, sent|wparam, 0/*SWP_NOZORDER*/ }, + { WM_GETMINMAXINFO, sent|defwinproc }, + { WM_NCCALCSIZE, sent|wparam, 1 }, + { WM_NCPAINT, sent }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */ + { WM_WINDOWPOSCHANGED, sent|wparam, /*SWP_NOZORDER|*/SWP_NOMOVE|SWP_NOCLIENTMOVE }, + { WM_SIZE, sent|defwinproc|wparam, 0 }, + { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */ + { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */ + { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */ + { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */ + { 0 } +}; /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE| SWP_NOZORDER|SWP_FRAMECHANGED) @@ -3732,8 +3748,16 @@ static void test_messages(void) /* test resizing and moving */ SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE ); ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE ); + flush_events(); + flush_sequence(); SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE ); ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE ); + flush_events(); + flush_sequence(); + SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER ); + ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE ); + flush_events(); + flush_sequence(); /* popups don't get WM_GETMINMAXINFO */ SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP ); diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 5502bf9cf43..632fcc19d34 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -3718,8 +3718,36 @@ static void test_IsWindowUnicode(void) DestroyWindow(hwnd); } +static LRESULT CALLBACK minmax_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +{ + MINMAXINFO *minmax; + + if (msg != WM_GETMINMAXINFO) + return DefWindowProc(hwnd, msg, wp, lp); + + minmax = (MINMAXINFO *)lp; + + if ((GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD)) + { + minmax->ptReserved.x = 0; + minmax->ptReserved.y = 0; + minmax->ptMaxSize.x = 400; + minmax->ptMaxSize.y = 400; + minmax->ptMaxPosition.x = 300; + minmax->ptMaxPosition.y = 300; + minmax->ptMaxTrackSize.x = 200; + minmax->ptMaxTrackSize.y = 200; + minmax->ptMinTrackSize.x = 100; + minmax->ptMinTrackSize.y = 100; + } + else + DefWindowProc(hwnd, msg, wp, lp); + return 1; +} + static void test_CreateWindow(void) { + WNDCLASS cls; HWND hwnd, parent; HMENU hmenu; RECT rc, rc_minmax; @@ -3917,8 +3945,20 @@ static void test_CreateWindow(void) ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError()); /* test child window sizing */ + cls.style = 0; + cls.lpfnWndProc = minmax_wnd_proc; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandle(0); + cls.hIcon = 0; + cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hbrBackground = GetStockObject(WHITE_BRUSH); + cls.lpszMenuName = NULL; + cls.lpszClassName = "MinMax_WndClass"; + RegisterClass(&cls); + SetLastError(0xdeadbeef); - parent = CreateWindowEx(0, "static", NULL, WS_CAPTION | WS_SYSMENU | WS_THICKFRAME, + parent = CreateWindowEx(0, "MinMax_WndClass", NULL, WS_CAPTION | WS_SYSMENU | WS_THICKFRAME, 0, 0, 100, 100, 0, 0, 0, NULL); ok(parent != 0, "CreateWindowEx error %d\n", GetLastError()); expect_menu(parent, 0); @@ -3928,19 +3968,20 @@ static void test_CreateWindow(void) memset(&minmax, 0, sizeof(minmax)); SendMessage(parent, WM_GETMINMAXINFO, 0, (LPARAM)&minmax); SetRect(&rc_minmax, 0, 0, minmax.ptMaxSize.x, minmax.ptMaxSize.y); - ok(IsRectEmpty(&rc_minmax), "rc_minmax is not empty\n"); + ok(IsRectEmpty(&rc_minmax), "ptMaxSize is not empty\n"); + SetRect(&rc_minmax, 0, 0, minmax.ptMaxTrackSize.x, minmax.ptMaxTrackSize.y); + ok(IsRectEmpty(&rc_minmax), "ptMaxTrackSize is not empty\n"); + GetWindowRect(parent, &rc); + ok(!IsRectEmpty(&rc), "parent window rect is empty\n"); GetClientRect(parent, &rc); - ok(rc_minmax.left >= rc.left && rc_minmax.top >= rc.top && - rc_minmax.right <= rc.right && rc_minmax.bottom <= rc.bottom, - "rc_minmax (%d,%d-%d,%d) is not within of parent client rect (%d,%d-%d,%d)\n", - rc_minmax.left, rc_minmax.top, rc_minmax.right, rc_minmax.bottom, - rc.left, rc.top, rc.right, rc.bottom); + ok(!IsRectEmpty(&rc), "parent client rect is empty\n"); + InflateRect(&rc, 200, 200); trace("creating child with rect (%d,%d-%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom); SetLastError(0xdeadbeef); - hwnd = CreateWindowEx(0, "static", NULL, WS_CHILD | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME, + hwnd = CreateWindowEx(0, "MinMax_WndClass", NULL, WS_CHILD | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, parent, (HMENU)1, 0, NULL); ok(hwnd != 0, "CreateWindowEx error %d\n", GetLastError()); @@ -3948,10 +3989,12 @@ static void test_CreateWindow(void) expect_style(hwnd, WS_CHILD | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME); expect_ex_style(hwnd, WS_EX_WINDOWEDGE); - OffsetRect(&rc, -rc.left, -rc.top); + memset(&minmax, 0, sizeof(minmax)); + SendMessage(hwnd, WM_GETMINMAXINFO, 0, (LPARAM)&minmax); + SetRect(&rc_minmax, 0, 0, minmax.ptMaxTrackSize.x, minmax.ptMaxTrackSize.y); - GetWindowRect(hwnd, &rc_minmax); - OffsetRect(&rc_minmax, -rc_minmax.left, -rc_minmax.top); + GetWindowRect(hwnd, &rc); + OffsetRect(&rc, -rc.left, -rc.top); ok(EqualRect(&rc, &rc_minmax), "rects don't match: (%d,%d-%d,%d) and (%d,%d-%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom, rc_minmax.left, rc_minmax.top, rc_minmax.right, rc_minmax.bottom); @@ -3959,6 +4002,8 @@ static void test_CreateWindow(void) DestroyWindow(hwnd); DestroyWindow(parent); + UnregisterClass("MinMax_WndClass", GetModuleHandle(0)); + #undef expect_menu #undef expect_style #undef expect_ex_style diff --git a/dlls/user32/win.c b/dlls/user32/win.c index 35144bde181..c6d17bf0553 100644 --- a/dlls/user32/win.c +++ b/dlls/user32/win.c @@ -1478,6 +1478,22 @@ static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR tit { while (list[i]) { + /* CodeWeavers HACK: + * Fix Outlook 2003 exit hang by not trying to send WM_GETTEXT to + * a hung window. See bug 2753. */ + /* Note: not nul terminated */ + static const WCHAR wszOutlookHungWindow[] = {'W','M','S',' ','S','T',' ','N','o','t','i','f',' ','W','i','n','d','o','w',' '}; + if (!memcmp( title, wszOutlookHungWindow, sizeof(wszOutlookHungWindow) )) + { + FIXME("possibly hung window %s\n", debugstr_w(title)); + if (IsHungAppWindow( list[i] )) + { + FIXME("window %s is hung\n", debugstr_w(title)); + i++; + continue; + } + } + if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break; i++; } @@ -2238,6 +2254,33 @@ LONG WINAPI SetWindowLongW( INT offset, /* [in] offset, in bytes, of location to alter */ LONG newval /* [in] new value of location */ ) { + if (GetVersion()&0x80000000 && offset == GWLP_WNDPROC) + { + /* CodeWeavers Only Hack... Needed for the Delegates tab + * in Outlook XP running in win98 mode + */ + char class[80]; + GetClassNameA(hwnd, class, sizeof(class)); + if (strcmp(class,"REListBox20W")==0) + { + char name[MAX_PATH], *p; + + GetModuleFileNameA(GetModuleHandleA(NULL),name,MAX_PATH); + p = strrchr(name, '\\'); + + if (p) + p++; + else + p = name; + + if (!strcasecmp(p,"OUTLOOK.EXE")) + { + ERR("Outlook in WIN98 calling supposedly unimplemented function, triggering bandaid for class %s\n",debugstr_a(class)); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return 0; + } + } + } return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE ); } diff --git a/dlls/user32/winpos.c b/dlls/user32/winpos.c index 635e9687c5c..554e232b358 100644 --- a/dlls/user32/winpos.c +++ b/dlls/user32/winpos.c @@ -40,6 +40,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(win); +#define SWP_AGG_NOGEOMETRYCHANGE \ + (SWP_NOSIZE | SWP_NOCLIENTSIZE | SWP_NOZORDER) #define SWP_AGG_NOPOSCHANGE \ (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER) #define SWP_AGG_STATUSFLAGS \ @@ -1594,7 +1596,9 @@ BOOL USER_SetWindowPos( WINDOWPOS * winpos ) &newWindowRect, &newClientRect, orig_flags, valid_rects )) return FALSE; - if (!(orig_flags & SWP_SHOWWINDOW)) + /* Windows doesn't redraw a window if it is being just moved */ + if (!(orig_flags & SWP_SHOWWINDOW) && + (winpos->flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOGEOMETRYCHANGE) { UINT rdw_flags = RDW_FRAME | RDW_ERASE; if ( !(orig_flags & SWP_DEFERERASE) ) rdw_flags |= RDW_ERASENOW; diff --git a/dlls/user32/winproc.c b/dlls/user32/winproc.c index 5a00e511e49..ef5cc779071 100644 --- a/dlls/user32/winproc.c +++ b/dlls/user32/winproc.c @@ -891,7 +891,7 @@ LRESULT WINPROC_CallProcAtoW( winproc_callback_t callback, HWND hwnd, UINT msg, case LB_DIR: case LB_ADDFILE: case EM_REPLACESEL: - if (!lParam) ret = callback( hwnd, msg, wParam, lParam, result, arg ); + if (!HIWORD(lParam)) ret = callback( hwnd, msg, wParam, lParam, result, arg ); else { WCHAR *ptr, buffer[512]; diff --git a/dlls/usp10/usp10.c b/dlls/usp10/usp10.c index b2b4b3f191c..3e1258dc2f1 100644 --- a/dlls/usp10/usp10.c +++ b/dlls/usp10/usp10.c @@ -1309,8 +1309,8 @@ HRESULT WINAPI ScriptPlace(HDC hdc, SCRIPT_CACHE *psc, const WORD *pwGlyphs, * to get the correct ABC widths. */ if (!(lpABC = usp_zero_alloc(sizeof(ABC) * cGlyphs))) return E_OUTOFMEMORY; - - memset(pABC, 0, sizeof(ABC)); + if (pABC) + memset(pABC, 0, sizeof(ABC)); /* FIXME: set pGoffset to more reasonable values */ if (!GetCharABCWidthsI(get_cache_hdc(psc), 0, cGlyphs, (WORD *) pwGlyphs, lpABC )) @@ -1330,15 +1330,19 @@ HRESULT WINAPI ScriptPlace(HDC hdc, SCRIPT_CACHE *psc, const WORD *pwGlyphs, lpABC[wcnt].abcA, lpABC[wcnt].abcB, lpABC[wcnt].abcC, wcnt); - pABC->abcA += lpABC[wcnt].abcA; - pABC->abcB += lpABC[wcnt].abcB; - pABC->abcC += lpABC[wcnt].abcC; + if (pABC) + { + pABC->abcA += lpABC[wcnt].abcA; + pABC->abcB += lpABC[wcnt].abcB; + pABC->abcC += lpABC[wcnt].abcC; + } piAdvance[wcnt] = lpABC[wcnt].abcA + lpABC[wcnt].abcB + lpABC[wcnt].abcC; pGoffset[wcnt].du = 0; pGoffset[wcnt].dv = 0; } } - TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC); + if (pABC) + TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC); usp_free(lpABC); return S_OK; diff --git a/dlls/vmm.vxd/vmm.c b/dlls/vmm.vxd/vmm.c index 77c81b0c62a..0d9f5833d08 100644 --- a/dlls/vmm.vxd/vmm.c +++ b/dlls/vmm.vxd/vmm.c @@ -160,7 +160,13 @@ DWORD WINAPI VMM_VxDCall( DWORD service, CONTEXT86 *context ) if ( page == PR_PRIVATE || page == PR_SHARED ) page = 0; /* FIXME: Handle flags in some way */ address = (LPVOID )(page * psize); - ret = VirtualAlloc ( address, ( npages * psize ), MEM_RESERVE, 0 ); + if (flags & PR_STATIC) + /* FIXME: this isn't right, it's just a workaround for the stupid native wininet which + * thinks it's a good idea to allocate its own stack without committing it + */ + ret = VirtualAlloc( address, ( npages * psize ), MEM_COMMIT, PAGE_READWRITE ); + else + ret = VirtualAlloc ( address, ( npages * psize ), MEM_RESERVE, 0 ); TRACE("PageReserve: returning: %p\n", ret ); if ( ret == NULL ) return -1; diff --git a/dlls/wineaudioio.drv/Makefile.in b/dlls/wineaudioio.drv/Makefile.in index e077b6e761c..0c6ca41d011 100644 --- a/dlls/wineaudioio.drv/Makefile.in +++ b/dlls/wineaudioio.drv/Makefile.in @@ -1,3 +1,4 @@ +#MKDLL_SKIP TOPSRCDIR = @top_srcdir@ TOPOBJDIR = ../.. SRCDIR = @srcdir@ diff --git a/dlls/winecoreaudio.drv/audio.c b/dlls/winecoreaudio.drv/audio.c index fcd84db21c9..670fab4e7d6 100644 --- a/dlls/winecoreaudio.drv/audio.c +++ b/dlls/winecoreaudio.drv/audio.c @@ -54,6 +54,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(wave); #include #include +WINE_DECLARE_DEBUG_CHANNEL(coreaudio); + /* Due to AudioUnit headers conflict define some needed types. */ @@ -485,6 +487,9 @@ BOOL CoreAudio_GetDevCaps (void) CoreAudio_DefaultDevice.out_caps.wChannels = 2; CoreAudio_DefaultDevice.out_caps.dwFormats|= WAVE_FORMAT_4S16; + + TRACE_(coreaudio)("out dwFormats = %08x, dwSupport = %08x\n", + CoreAudio_DefaultDevice.out_caps.dwFormats, CoreAudio_DefaultDevice.out_caps.dwSupport); return TRUE; } @@ -712,6 +717,8 @@ void CoreAudio_WaveRelease(void) */ static DWORD wodNotifyClient(WINE_WAVEOUT* wwo, WORD wMsg, DWORD dwParam1, DWORD dwParam2) { + TRACE_(coreaudio)("wMsg = 0x%04x dwParm1 = %04x dwParam2 = %04x\n", wMsg, dwParam1, dwParam2); + switch (wMsg) { case WOM_OPEN: case WOM_CLOSE: @@ -721,10 +728,12 @@ static DWORD wodNotifyClient(WINE_WAVEOUT* wwo, WORD wMsg, DWORD dwParam1, DWORD (HDRVR)wwo->waveDesc.hWave, wMsg, wwo->waveDesc.dwInstance, dwParam1, dwParam2)) { + ERR("can't notify client !\n"); return MMSYSERR_ERROR; } break; default: + ERR("Unknown callback message %u\n", wMsg); return MMSYSERR_INVALPARAM; } return MMSYSERR_NOERROR; diff --git a/dlls/winecoreaudio.drv/audiounit.c b/dlls/winecoreaudio.drv/audiounit.c index b6da9531295..3fc24b039b0 100644 --- a/dlls/winecoreaudio.drv/audiounit.c +++ b/dlls/winecoreaudio.drv/audiounit.c @@ -21,11 +21,27 @@ #include "config.h" #include "wine/debug.h" -WINE_DEFAULT_DEBUG_CHANNEL(wave); +WINE_DEFAULT_DEBUG_CHANNEL(coreaudio); #ifdef HAVE_AUDIOUNIT_AUDIOUNIT_H #include +static const char *streamDescription(const AudioStreamBasicDescription* stream) +{ + return wine_dbg_sprintf("\n mSampleRate : %f\n mFormatID : %c%c%c%c\n mFormatFlags : %lX\n mBytesPerPacket : %lu\n mFramesPerPacket : %lu\n mBytesPerFrame : %lu\n mChannelsPerFrame : %lu\n mBitsPerChannel : %lu\n", + stream->mSampleRate, + (char) (stream->mFormatID >> 24), + (char) (stream->mFormatID >> 16), + (char) (stream->mFormatID >> 8), + (char) stream->mFormatID, + stream->mFormatFlags, + stream->mBytesPerPacket, + stream->mFramesPerPacket, + stream->mBytesPerFrame, + stream->mChannelsPerFrame, + stream->mBitsPerChannel); +} + extern OSStatus CoreAudio_woAudioUnitIOProc(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, @@ -46,6 +62,8 @@ int AudioUnit_CreateDefaultAudioUnit(void *wwo, AudioUnit *au) Component comp; ComponentDescription desc; AURenderCallbackStruct callbackStruct; + + TRACE("\n"); desc.componentType = kAudioUnitType_Output; desc.componentSubType = kAudioUnitSubType_DefaultOutput; @@ -82,7 +100,9 @@ int AudioUnit_CloseAudioUnit(AudioUnit au) int AudioUnit_InitializeWithStreamDescription(AudioUnit au, AudioStreamBasicDescription *stream) { OSStatus err = noErr; - + + TRACE("%s\n", streamDescription(stream)); + err = AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, stream, sizeof(*stream)); @@ -104,6 +124,7 @@ int AudioUnit_InitializeWithStreamDescription(AudioUnit au, AudioStreamBasicDesc int AudioUnit_SetVolume(AudioUnit au, float left, float right) { OSStatus err = noErr; + FIXME("independent left/right volume not implemented (%f, %f)\n", left, right); err = AudioUnitSetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left, 0); @@ -118,6 +139,7 @@ int AudioUnit_SetVolume(AudioUnit au, float left, float right) int AudioUnit_GetVolume(AudioUnit au, float *left, float *right) { OSStatus err = noErr; + FIXME("independent left/right volume not implemented\n"); err = AudioUnitGetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left); if (err != noErr) diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c index 02bc4066c3f..d21f5b8b094 100644 --- a/dlls/wined3d/context.c +++ b/dlls/wined3d/context.c @@ -352,6 +352,14 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT); checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);"); + if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) { + /* Most textures will use client storage if supported. Exceptions are non-native power of 2 textures + * and textures in DIB sections(due to the memory protection). + */ + glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); + checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)"); + } + if(oldDrawable && oldCtx) { glXMakeCurrent(display, oldDrawable, oldCtx); } diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 78637149641..20c408f560f 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -363,7 +363,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *ifac * more. In this call we can convert dx7 buffers too. */ conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR)); - if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && + if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && wined3d_settings.vbo_mode != VBO_NONE && + Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && (dxVersion > 7 || !conv) ) { CreateVBO(object); } @@ -3385,7 +3386,7 @@ process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCo /* Get a pointer into the destination vbo(create one if none exists) and * write correct opengl data into it. It's cheap and allows us to run drawStridedFast */ - if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) { + if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && wined3d_settings.vbo_mode != VBO_NONE) { CreateVBO(dest); } @@ -3529,6 +3530,17 @@ process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCo y += vp.Height / 2 + vp.Y; z += vp.MinZ; + /* Half-Life draws vertices in front of the near clipping plane, + * and opengl clips them. Apparently I am expected to clip the vertices here, + * mark them clipped(see below), and modify the primitives in drawprim when + * a clipped vertex is hit. This quite a lot of work for the hardly used hl1 d3d mode + * + * The hack is to draw the verts directly on the near clipping plane, so the weapons will + * look a bit disorted instead of having completely missing near parts... Looks better IHMO + */ + if(hl1hack) { + if(z < vp.MinZ) z = vp.MinZ + eps; + } rhw = 1 / rhw; } else { /* That vertex got clipped @@ -5342,6 +5354,12 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* i memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp); IWineD3DSurface_UnlockRect(pCursorBitmap); ENTER_GL(); + + if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) { + glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE); + checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)"); + } + /* Make sure that a proper texture unit is selected */ if (GL_SUPPORT(ARB_MULTITEXTURE)) { GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB)); @@ -5357,6 +5375,12 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* i glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem); HeapFree(GetProcessHeap(), 0, mem); checkGLcall("glTexImage2D"); + + if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) { + glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); + checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)"); + } + LEAVE_GL(); } else @@ -5369,6 +5393,12 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* i This->xHotSpot = XHotSpot; This->yHotSpot = YHotSpot; + + /* On windows the cursor is not visible any more after this call, although IsCursorVisible still returns that the cursor should be there + * For now just disable it using the user code instead of using some ExtEscape calls + */ + ShowCursor(FALSE); + return WINED3D_OK; } @@ -5390,8 +5420,9 @@ static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOO TRACE("(%p) : visible(%d)\n", This, bShow); - if(This->cursorTexture) - This->bCursorVisible = bShow; + This->bCursorVisible = bShow; + if(cursorhack && !bShow) + ShowCursor(FALSE); /* * When ShowCursor is first called it should make the cursor appear at the OS's last * known cursor position. Because of this, some applications just repetitively call @@ -5470,6 +5501,7 @@ static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAM glDeleteTextures(1, &surface->glDescription.textureName); LEAVE_GL(); surface->glDescription.textureName = 0; + surface->Flags &= ~SFLAG_CLIENT; } if(surface->pow2Width != pPresentationParameters->BackBufferWidth || surface->pow2Height != pPresentationParameters->BackBufferHeight) { @@ -5586,15 +5618,13 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRE (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) || DisplayModeChanged) { - /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */ if(!pPresentationParameters->Windowed) { + /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */ IWineD3DDevice_SetFullscreen(iface, TRUE); - } - - IWineD3DDevice_SetDisplayMode(iface, 0, &mode); - - /* Switching out of fullscreen mode? First set the original res, then change the window */ - if(pPresentationParameters->Windowed) { + IWineD3DDevice_SetDisplayMode(iface, 0, &mode); + } else { + /* Switching out of fullscreen mode? First set the original res, then change the window */ + ChangeDisplaySettingsExW(NULL, NULL, NULL, 0, NULL); IWineD3DDevice_SetFullscreen(iface, FALSE); } swapchain->presentParms.Windowed = pPresentationParameters->Windowed; diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c index e0dbe572391..f4ebe538137 100644 --- a/dlls/wined3d/directx.c +++ b/dlls/wined3d/directx.c @@ -593,8 +593,8 @@ BOOL IWineD3DImpl_FillGLCaps(IWineD3D *iface, Display* display) { glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &gl_max); TRACE_(d3d_caps)(" FOUND: ARB Multitexture support - GL_MAX_TEXTURE_UNITS_ARB=%u\n", gl_max); gl_info->supported[ARB_MULTITEXTURE] = TRUE; - gl_info->max_textures = min(MAX_TEXTURES, gl_max); - gl_info->max_texture_stages = min(MAX_TEXTURES, gl_max); + gl_info->max_textures = min(MAX_TEXTURES, ffp_textures ? ffp_textures : gl_max); + gl_info->max_texture_stages = min(MAX_TEXTURES, ffp_textures ? ffp_textures : gl_max); gl_info->max_samplers = max(gl_info->max_samplers, gl_max); } else if (strcmp(ThisExtn, "GL_ARB_texture_cube_map") == 0) { TRACE_(d3d_caps)(" FOUND: ARB Texture Cube Map support\n"); @@ -741,7 +741,7 @@ BOOL IWineD3DImpl_FillGLCaps(IWineD3D *iface, Display* display) { TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Pixel Shader support - version=%02x\n", gl_info->ps_nv_version); } else if (strcmp(ThisExtn, "GL_NV_register_combiners") == 0) { glGetIntegerv(GL_MAX_GENERAL_COMBINERS_NV, &gl_max); - gl_info->max_texture_stages = min(MAX_TEXTURES, gl_max); + gl_info->max_texture_stages = min(MAX_TEXTURES, ffp_textures ? ffp_textures : gl_max); TRACE_(d3d_caps)(" FOUND: NVIDIA (NV) Register combiners (1) support - GL_MAX_GENERAL_COMBINERS_NV=%d\n", gl_max); gl_info->supported[NV_REGISTER_COMBINERS] = TRUE; } else if (strcmp(ThisExtn, "GL_NV_register_combiners2") == 0) { @@ -812,6 +812,8 @@ BOOL IWineD3DImpl_FillGLCaps(IWineD3D *iface, Display* display) { */ gl_info->supported[NV_FENCE] = FALSE; gl_info->supported[APPLE_FENCE] = TRUE; + } else if (strstr(ThisExtn, "GL_APPLE_client_storage")) { + gl_info->supported[APPLE_CLIENT_STORAGE] = TRUE; } if (*GL_Extensions == ' ') GL_Extensions++; @@ -1112,6 +1114,7 @@ static UINT WINAPI IWineD3DImpl_GetAdapterModeCount(IWineD3D *iface, UINT Ad switch (Format) { case WINED3DFMT_UNKNOWN: + /* This is for D3D8, do not enumerate P8 here */ if (DevModeW.dmBitsPerPel == 32 || DevModeW.dmBitsPerPel == 16) i++; break; @@ -1121,6 +1124,9 @@ static UINT WINAPI IWineD3DImpl_GetAdapterModeCount(IWineD3D *iface, UINT Ad case WINED3DFMT_R5G6B5: if (DevModeW.dmBitsPerPel == 16) i++; break; + case WINED3DFMT_P8: + if (DevModeW.dmBitsPerPel == 8) i++; + break; default: /* Skip other modes as they do not match the requested format */ break; @@ -1164,6 +1170,7 @@ static HRESULT WINAPI IWineD3DImpl_EnumAdapterModes(IWineD3D *iface, UINT Adapte switch (Format) { case WINED3DFMT_UNKNOWN: + /* This is D3D8. Do not enumerate P8 here */ if (DevModeW.dmBitsPerPel == 32 || DevModeW.dmBitsPerPel == 16) i++; break; @@ -1173,6 +1180,9 @@ static HRESULT WINAPI IWineD3DImpl_EnumAdapterModes(IWineD3D *iface, UINT Adapte case WINED3DFMT_R5G6B5: if (DevModeW.dmBitsPerPel == 16) i++; break; + case WINED3DFMT_P8: + if (DevModeW.dmBitsPerPel == 8) i++; + break; default: /* Modes that don't match what we support can get an early-out */ TRACE_(d3d_caps)("Searching for %s, returning D3DERR_INVALIDCALL\n", debug_d3dformat(Format)); @@ -1198,6 +1208,9 @@ static HRESULT WINAPI IWineD3DImpl_EnumAdapterModes(IWineD3D *iface, UINT Adapte { switch (DevModeW.dmBitsPerPel) { + case 8: + pMode->Format = WINED3DFMT_P8; + break; case 16: pMode->Format = WINED3DFMT_R5G6B5; break; @@ -1665,21 +1678,6 @@ static HRESULT WINAPI IWineD3DImpl_CheckDeviceFormat(IWineD3D *iface, UINT Adapt case WINED3DFMT_P8: TRACE_(d3d_caps)("[OK]\n"); return WINED3D_OK; - case WINED3DFMT_R16F: - case WINED3DFMT_A16B16G16R16F: - if (!GL_SUPPORT(ARB_HALF_FLOAT_PIXEL)) { - TRACE_(d3d_caps)("[FAILED]\n"); - return WINED3DERR_NOTAVAILABLE; - } - /* Fall through, support not fully determined yet. */ - case WINED3DFMT_R32F: - case WINED3DFMT_A32B32G32R32F: - if (!GL_SUPPORT(ARB_TEXTURE_FLOAT)) { - TRACE_(d3d_caps)("[FAILED]\n"); - return WINED3DERR_NOTAVAILABLE; - } - TRACE_(d3d_caps)("[OK]\n"); - return WINED3D_OK; default: TRACE_(d3d_caps)("[FAILED]\n"); return WINED3DERR_NOTAVAILABLE; @@ -1700,6 +1698,23 @@ static HRESULT WINAPI IWineD3DImpl_CheckDeviceFormat(IWineD3D *iface, UINT Adapt } } + if (GL_SUPPORT(ARB_TEXTURE_FLOAT)) { + + BOOL half_pixel_support = GL_SUPPORT(ARB_HALF_FLOAT_PIXEL); + + switch (CheckFormat) { + case WINED3DFMT_R16F: + case WINED3DFMT_A16B16G16R16F: + if (!half_pixel_support) break; + case WINED3DFMT_R32F: + case WINED3DFMT_A32B32G32R32F: + TRACE_(d3d_caps)("[OK]\n"); + return WINED3D_OK; + default: + break; /* Avoid compiler warnings */ + } + } + /* This format is nothing special and it is supported perfectly. * However, ati and nvidia driver on windows do not mark this format as * supported (tested with the dxCapsViewer) and pretending to @@ -1882,7 +1897,7 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter, *pCaps->Caps2 = WINED3DCAPS2_CANRENDERWINDOWED | WINED3DCAPS2_FULLSCREENGAMMA | WINED3DCAPS2_DYNAMICTEXTURES; - *pCaps->Caps3 = 0; + *pCaps->Caps3 = WINED3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD; *pCaps->PresentationIntervals = WINED3DPRESENT_INTERVAL_IMMEDIATE; *pCaps->CursorCaps = 0; @@ -2192,7 +2207,7 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter, if (GL_SUPPORT(ARB_TEXTURE_ENV_DOT3)) *pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_DOTPRODUCT3; - if (GL_SUPPORT(NV_REGISTER_COMBINERS)) { + if (GL_SUPPORT(NV_REGISTER_COMBINERS) || forceModulateInvAlphaAddColor) { *pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR | WINED3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA; } @@ -2502,6 +2517,7 @@ static HRESULT WINAPI IWineD3DImpl_CreateDevice(IWineD3D *iface, UINT Adapter, object->ddraw_format = pixelformat_for_depth(GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES)); ReleaseDC(0, hDC); + deviceCreated = TRUE; return WINED3D_OK; create_device_error: diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c index 089030bef7a..4c6e46f4cc5 100644 --- a/dlls/wined3d/drawprim.c +++ b/dlls/wined3d/drawprim.c @@ -412,6 +412,19 @@ static void drawStridedFast(IWineD3DDevice *iface,UINT numberOfVertices, GLenum const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx, ULONG startVertex) { IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + if(attribhack && This->stateBlock->vertexShader) { + if(((IWineD3DVertexShaderImpl *) This->stateBlock->vertexShader)->semantics_in[15].usage != 0 && + ((IWineD3DVertexShaderImpl *) This->stateBlock->vertexShader)->semantics_in[15].reg != 0) { + /* Background of this hack is that the MacOS opengl implementation crashes(or terminates the app silently) if a vertex + * shader using all 16 vertex attributes is used. With this hack the application can conntinue, but some geometry may + * be missing. This allows us to run 3DMark2001 with vertex shaders enabled. The dragon in the dragothic test uses 16 + * vertex attributes. + */ + FIXME("A vertex shader using 16 vertex attributes is used, and the attribute hack is enabled. Not drawing anything\n"); + return; + } + } + if (idxSize != 0 /* This crashes sometimes!*/) { TRACE("(%p) : glElements(%x, %d, %d, ...)\n", This, glPrimitiveType, numberOfVertices, minIndex); idxData = idxData == (void *)-1 ? NULL : idxData; @@ -449,8 +462,8 @@ static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData unsigned int textureNo = 0; unsigned int texture_idx = 0; - const short *pIdxBufS = NULL; - const long *pIdxBufL = NULL; + const WORD *pIdxBufS = NULL; + const DWORD *pIdxBufL = NULL; LONG vx_index; float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */ float rhw = 0.0f; /* rhw */ @@ -458,7 +471,7 @@ static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData DWORD specularColor = 0; /* Specular Color */ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; UINT *streamOffset = This->stateBlock->streamOffset; - LONG SkipnStrides = startVertex + This->stateBlock->loadBaseVertexIndex; + DWORD SkipnStrides = startVertex + This->stateBlock->loadBaseVertexIndex; BYTE *texCoords[WINED3DDP_MAXTEXCOORD]; BYTE *diffuse = NULL, *specular = NULL, *normal = NULL, *position = NULL; @@ -475,8 +488,8 @@ static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData idxData = ((IWineD3DIndexBufferImpl *) This->stateBlock->pIndexData)->resource.allocatedMemory; } - if (idxSize == 2) pIdxBufS = (const short *) idxData; - else pIdxBufL = (const long *) idxData; + if (idxSize == 2) pIdxBufS = (const WORD *) idxData; + else pIdxBufL = (const DWORD *) idxData; } /* Adding the stream offset once is cheaper than doing it every iteration. Do not modify the strided data, it is a pointer diff --git a/dlls/wined3d/indexbuffer.c b/dlls/wined3d/indexbuffer.c index f64d6aa1905..18cfce758fa 100644 --- a/dlls/wined3d/indexbuffer.c +++ b/dlls/wined3d/indexbuffer.c @@ -155,7 +155,7 @@ static HRESULT WINAPI IWineD3DIndexBufferImpl_Unlock(IWineD3DIndexBuffer *iface) TRACE("(%p)\n", This); /* For now load in unlock */ - if(locks == 0 && This->vbo) { + if(locks == 0 && This->vbo && (This->dirtyend - This->dirtystart) > 0) { IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; ENTER_GL(); diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index 8ac924b5176..bc63496a444 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -167,6 +167,11 @@ static void surface_upload_data(IWineD3DSurfaceImpl *This, GLsizei width, GLsize if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { FIXME("Using DXT1/3/5 without advertized support\n"); } else { + if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) { + /* Neither NONPOW2, DIBSECTION nor OVERSIZE flags can be set on compressed textures */ + This->Flags |= SFLAG_CLIENT; + } + TRACE("(%p) : Calling glCompressedTexSubImage2D w %d, h %d, data %p\n", This, width, height, data); ENTER_GL(); /* glCompressedTexSubImage2D for uploading and glTexImage2D for allocating does not work well on some drivers(r200 dri, MacOS ATI driver) @@ -188,6 +193,8 @@ static void surface_upload_data(IWineD3DSurfaceImpl *This, GLsizei width, GLsize } static void surface_allocate_surface(IWineD3DSurfaceImpl *This, GLenum internal, GLsizei width, GLsizei height, GLenum format, GLenum type) { + BOOL enable_client_storage = FALSE; + TRACE("(%p) : Creating surface (target %#x) level %d, d3d format %s, internal format %#x, width %d, height %d, gl format %#x, gl type=%#x\n", This, This->glDescription.target, This->glDescription.level, debug_d3dformat(This->resource.format), internal, width, height, format, type); @@ -201,9 +208,32 @@ static void surface_allocate_surface(IWineD3DSurfaceImpl *This, GLenum internal, ENTER_GL(); - glTexImage2D(This->glDescription.target, This->glDescription.level, internal, width, height, 0, format, type, NULL); + if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) { + if(This->Flags & (SFLAG_NONPOW2 | SFLAG_DIBSECTION | SFLAG_OVERSIZE | SFLAG_CONVERTED) || This->resource.allocatedMemory == NULL) { + /* In some cases we want to disable client storage. + * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches + * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues... + * SFLAG_OVERSIZE: The gl texture is smaller than the allocated memory + * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface + * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively + */ + glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE); + checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)"); + This->Flags &= SFLAG_CLIENT; + enable_client_storage = TRUE; + } else { + This->Flags |= SFLAG_CLIENT; + /* Below point opengl to our allocated texture memory */ + } + } + glTexImage2D(This->glDescription.target, This->glDescription.level, internal, width, height, 0, format, type, + This->Flags & SFLAG_CLIENT ? This->resource.allocatedMemory : NULL); checkGLcall("glTexImage2D"); + if(enable_client_storage) { + glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); + checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)"); + } LEAVE_GL(); } @@ -1203,6 +1233,7 @@ HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) { if(!This->hDC) { int extraline = 0; SYSTEM_INFO sysInfo; + void *oldmem = This->resource.allocatedMemory; switch (This->bytesPerPixel) { case 2: @@ -1306,7 +1337,6 @@ HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) { if(This->resource.allocatedMemory) { memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage); /* We won't need that any more */ - HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory); } else { /* This is to make LockRect read the gl Texture although memory is allocated */ This->Flags &= ~SFLAG_INSYSMEM; @@ -1326,6 +1356,11 @@ HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) { FALSE); This->Flags |= SFLAG_DIBSECTION; + + if(This->Flags & SFLAG_CLIENT) { + IWineD3DSurface_PreLoad(iface); + } + HeapFree(GetProcessHeap(), 0, oldmem); } /* Lock the surface */ @@ -1807,6 +1842,14 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) { glReadBuffer(This->resource.wineD3DDevice->offscreenBuffer); vcheckGLcall("glReadBuffer"); +#ifdef __APPLE__ + /* Crossover HACK for nvidia macs + * The nvidia macs don't synchronize auxiliary buffers properly, force them to their luck :-/ + */ + if(GL_SUPPORT(NV_REGISTER_COMBINERS)) { + glFinish(); + } +#endif glCopyTexImage2D(This->glDescription.target, This->glDescription.level, This->glDescription.glFormatInternal, @@ -1874,6 +1917,9 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) { surface_upload_data(This, This->currentDesc.Width, This->currentDesc.Height, format, type, mem); } } else { + /* When making the realloc conditional, keep in mind that GL_APPLE_client_storage may be in use, and This->resource.allocatedMemory + * changed. So also keep track of memory changes. In this case the texture has to be reallocated + */ surface_allocate_surface(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type); if (mem) { surface_upload_data(This, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type, mem); @@ -2161,6 +2207,7 @@ HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) { } if(Mem && Mem != This->resource.allocatedMemory) { + void *release = NULL; /* Do I have to copy the old surface content? */ if(This->Flags & SFLAG_DIBSECTION) { @@ -2177,14 +2224,31 @@ HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) { This->hDC = NULL; This->Flags &= ~SFLAG_DIBSECTION; } else if(!(This->Flags & SFLAG_USERPTR)) { - HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory); + release = This->resource.allocatedMemory; } This->resource.allocatedMemory = Mem; - This->Flags |= SFLAG_USERPTR; + This->Flags |= SFLAG_USERPTR | SFLAG_INSYSMEM; + + /* Now the surface memory is most up do date. Invalidate drawable and texture */ + This->Flags &= ~(SFLAG_INDRAWABLE | SFLAG_INTEXTURE); + + /* For client textures opengl has to be notified */ + if(This->Flags & SFLAG_CLIENT) { + IWineD3DSurface_PreLoad(iface); + /* And hope that the app behaves correctly and did not free the old surface memory before setting a new pointer */ + } + + /* Now free the old memory if any */ + HeapFree(GetProcessHeap(), 0, release); } else if(This->Flags & SFLAG_USERPTR) { /* Lockrect and GetDC will re-create the dib section and allocated memory */ This->resource.allocatedMemory = NULL; This->Flags &= ~SFLAG_USERPTR; + + if(This->Flags & SFLAG_CLIENT) { + /* This respecifies an empty texture and opengl knows that the old memory is gone */ + IWineD3DSurface_PreLoad(iface); + } } return WINED3D_OK; } @@ -2242,6 +2306,15 @@ static inline void fb_copy_to_texture_direct(IWineD3DSurfaceImpl *This, IWineD3D FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n"); } +#ifdef __APPLE__ + /* Crossover HACK for nvidia macs + * The nvidia macs don't synchronize auxiliary buffers properly, force them to their luck :-/ + */ + if(GL_SUPPORT(NV_REGISTER_COMBINERS)) { + glFinish(); + } +#endif + if(upsidedown && !((xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) && !((yrel - 1.0 < -eps) || (yrel - 1.0 > eps))) { @@ -2270,6 +2343,12 @@ static inline void fb_copy_to_texture_direct(IWineD3DSurfaceImpl *This, IWineD3D if(!warned) { warned = TRUE; FIXME("Doing a pixel by pixel render target -> texture copy, expect performance issues\n"); + + /* warned is not static, so this works */ + if(!enableSlowBlit) { + ERR("Slow pixel per pixel copy disabled, aborting\n"); + break; + } } for(col = drect->x1; col < drect->x2; col++) { @@ -2343,11 +2422,22 @@ static inline void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *This, IWine checkGLcall("glReadBuffer(GL_BACK)"); /* TODO: Only back up the part that will be overwritten */ +#ifdef __APPLE__ + if(GL_SUPPORT(NV_REGISTER_COMBINERS)) { + glFinish(); + } +#endif + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0 /* read offsets */, 0, 0, fbwidth, fbheight); +#ifdef __APPLE__ + if(GL_SUPPORT(NV_REGISTER_COMBINERS)) { + glFinish(); + } +#endif checkGLcall("glCopyTexSubImage2D"); @@ -2430,12 +2520,27 @@ static inline void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *This, IWine /* Now read the stretched and upside down image into the destination texture */ glBindTexture(This->glDescription.target, This->glDescription.textureName); checkGLcall("glBindTexture"); + +#ifdef __APPLE__ + /* Crossover HACK for nvidia macs + * The nvidia macs don't synchronize auxiliary buffers properly, force them to their luck :-/ + */ + if(GL_SUPPORT(NV_REGISTER_COMBINERS)) { + glFinish(); + } +#endif + glCopyTexSubImage2D(This->glDescription.target, 0, drect->x1, drect->y1, /* xoffset, yoffset */ 0, 0, /* We blitted the image to the origin */ drect->x2 - drect->x1, drect->y2 - drect->y1); checkGLcall("glCopyTexSubImage2D"); +#ifdef __APPLE__ + if(GL_SUPPORT(NV_REGISTER_COMBINERS)) { + glFinish(); + } +#endif /* Write the back buffer backup back */ glBindTexture(GL_TEXTURE_2D, backup ? backup : Src->glDescription.textureName); @@ -2537,11 +2642,12 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT * } /* Check the Destination rect and the surface sizes */ - if(SrcOK && + if(hl1hack || + (SrcOK && (rect.x1 == 0) && (rect.y1 == 0) && (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) && (This->currentDesc.Width == Src->currentDesc.Width) && - (This->currentDesc.Height == Src->currentDesc.Height)) { + (This->currentDesc.Height == Src->currentDesc.Height))) { /* These flags are unimportant for the flag check, remove them */ if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) { @@ -3200,6 +3306,13 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) { This->glRect.bottom = This->pow2Height; } + if(GL_SUPPORT(APPLE_CLIENT_STORAGE) && This->resource.allocatedMemory == NULL) { + /* Make sure that memory is allocated from the start if we are going to use GL_APPLE_client_storage. + * Otherwise a glTexImage2D with a NULL pointer may be done, e.g. when blitting or with offscreen render + * targets, thus the client storage wouldn't be used for that texture + */ + This->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->resource.size + 4); + } return WINED3D_OK; } diff --git a/dlls/wined3d/surface_gdi.c b/dlls/wined3d/surface_gdi.c index 4565f723540..e43c7906b89 100644 --- a/dlls/wined3d/surface_gdi.c +++ b/dlls/wined3d/surface_gdi.c @@ -122,6 +122,39 @@ x11_copy_to_screen(IWineD3DSurfaceImpl *This, } /***************************************************************************** + * x11_copy_from_screen + * + * Reads the contents of a window into the front buffer + * + *****************************************************************************/ +static void x11_copy_from_screen(IWineD3DSurfaceImpl* This, + const RECT *rc) +{ + if (This->resource.usage & WINED3DUSAGE_RENDERTARGET) + { + HWND hDisplayWnd = This->resource.wineD3DDevice->ddraw_window; + HDC hDisplayDC = GetDC(hDisplayWnd); + RECT drawrect; + + drawrect.left = 0; + drawrect.right = This->currentDesc.Width; + drawrect.top = 0; + drawrect.bottom = This->currentDesc.Height; + if (rc) + IntersectRect(&drawrect,&drawrect,rc); + + BitBlt(This->hDC, + drawrect.left, drawrect.top, + drawrect.right-drawrect.left, drawrect.bottom-drawrect.top, + hDisplayDC, + drawrect.left, drawrect.top, + SRCCOPY + ); + ReleaseDC(hDisplayWnd, hDisplayDC); + } +} + +/***************************************************************************** * IWineD3DSurface::PreLoad, GDI version * * This call is unsupported on GDI surfaces, if it's called something went @@ -239,6 +272,23 @@ IWineGDISurfaceImpl_LockRect(IWineD3DSurface *iface, This->lockedRect.bottom = pRect->bottom; } + /* DDraw apps can share ddraw operation with GDI if not in exclusive mode. This surface + * implementation BitBlts the front buffer's content onto the GDI device context. In the + * same way as we write to GDI we have to read from there when we lock the primary surface. + * + * Reading from GDI is slow, so do it only when the app locks the whole surface. If the app + * specifies a rectangle to lock it is assumed that the app knows what part it wants to lock. + * + * There is no need to take care for gdi readback for back buffers, or in the Flip method, + * because double buffered surfaces can only be created in DDSCL_EXCLUSIVE mode, and in + * this mode gdi stuff can't be done anyway. + */ + if(!(Flags & DDLOCK_WRITEONLY) && iface == This->resource.wineD3DDevice->ddraw_primary && + !This->resource.wineD3DDevice->ddraw_fullscreen) + { + x11_copy_from_screen(This, NULL); + } + /* No dirtifying is needed for this surface implementation */ TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch); diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c index d46067d41a7..8ac8f369f56 100644 --- a/dlls/wined3d/swapchain.c +++ b/dlls/wined3d/swapchain.c @@ -104,7 +104,6 @@ static HRESULT WINAPI IWineD3DSwapChainImpl_GetParent(IWineD3DSwapChain *iface, /*IWineD3DSwapChain parts follow: */ static void WINAPI IWineD3DSwapChainImpl_Destroy(IWineD3DSwapChain *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyRenderTarget) { IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface; - WINED3DDISPLAYMODE mode; int i; /* release the ref to the front and back buffer parents */ @@ -131,11 +130,7 @@ static void WINAPI IWineD3DSwapChainImpl_Destroy(IWineD3DSwapChain *iface, D3DCB * before starting up Direct3D, thus orig_width and orig_height will be equal to the modes in the presentation params */ if(This->presentParms.Windowed == FALSE) { - mode.Width = This->orig_width; - mode.Height = This->orig_height; - mode.RefreshRate = 0; - mode.Format = This->orig_fmt; - IWineD3DDevice_SetDisplayMode((IWineD3DDevice *) This->wineD3DDevice, 0, &mode); + ChangeDisplaySettingsExW(NULL, NULL, NULL, 0, NULL); } for(i = 0; i < This->num_contexts; i++) { DestroyContext(This->wineD3DDevice, This->context[i]); @@ -150,6 +145,11 @@ static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CO ENTER_GL(); + if(!This->XSynced) { + XSync(This->context[0]->display, FALSE); + This->XSynced = TRUE; + } + /* Does glXSwapBuffers need a glx context? I don't think so. Blt will activate its own context if needed */ /* Render the cursor onto the back buffer, using our nifty directdraw blitting code :-) */ diff --git a/dlls/wined3d/vertexshader.c b/dlls/wined3d/vertexshader.c index 22c49c20e46..c245a5eef30 100644 --- a/dlls/wined3d/vertexshader.c +++ b/dlls/wined3d/vertexshader.c @@ -428,6 +428,12 @@ static VOID IWineD3DVertexShaderImpl_GenerateShader( } } + /* HACK + * The ATI Linux driver looses stream source information when compiling a shader. This makes + * sure things are restored properly + */ + IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *) This->baseShader.device, STATE_VDECL); + #if 1 /* if were using the data buffer of device then we don't need to free it */ HeapFree(GetProcessHeap(), 0, buffer.buffer); #endif diff --git a/dlls/wined3d/volume.c b/dlls/wined3d/volume.c index 3fb30366dec..9033c8a42e4 100644 --- a/dlls/wined3d/volume.c +++ b/dlls/wined3d/volume.c @@ -291,7 +291,11 @@ static HRESULT WINAPI IWineD3DVolumeImpl_LoadTexture(IWineD3DVolume *iface, GLen checkGLcall("glTexImage3D"); } else WARN("This OpenGL implementation doesn't support 3D textures\n"); - + + /* When adding code releasing This->resource.allocatedMemory to save data keep in mind that + * GL_UNPACK_CLIENT_STORAGE_APPLE is enabled by default if supported(GL_APPLE_client_storage). + * Thus do not release This->resource.allocatedMemory if GL_APPLE_client_storage is supported. + */ return WINED3D_OK; } diff --git a/dlls/wined3d/wined3d_main.c b/dlls/wined3d/wined3d_main.c index 965d95df956..780466f26d1 100644 --- a/dlls/wined3d/wined3d_main.c +++ b/dlls/wined3d/wined3d_main.c @@ -45,6 +45,15 @@ wined3d_settings_t wined3d_settings = 64*1024*1024 /* 64MB texture memory by default */ }; +/* CXOffice hacks, not in the main wined3d configuration settings */ +BOOL hl1hack = FALSE; +BOOL cursorhack = FALSE; +BOOL attribhack = FALSE; +UINT ffp_textures = 0; +BOOL forceModulateInvAlphaAddColor = FALSE; +BOOL enableSlowBlit = FALSE; +BOOL deviceCreated = FALSE; + WineD3DGlobalStatistics *wineD3DGlobalStatistics = NULL; CRITICAL_SECTION resourceStoreCriticalSection; @@ -241,6 +250,53 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) else ERR("VideoMemorySize is %i but must be >0\n", TmpVideoMemorySize); } + if ( !get_config_key( hkey, appkey, "hl1hack", buffer, size) ) + { + if (!strcmp(buffer,"enable")) + { + TRACE("Half-Life 1 hack enabled\n"); + hl1hack = TRUE; + + } + } + if ( !get_config_key( hkey, appkey, "cursorhack", buffer, size) ) + { + if (!strcmp(buffer,"enable")) + { + TRACE("Cursor disable hack enabled\n"); + cursorhack = TRUE; + + } + } + if ( !get_config_key( hkey, appkey, "attribhack", buffer, size) ) + { + if (!strcmp(buffer,"enable")) + { + TRACE("16 Vertex attributes hack enabled\n"); + attribhack = TRUE; + + } + } + if ( !get_config_key( hkey, appkey, "ffp_textures", buffer, size) ) + { + ffp_textures = atoi(buffer); + } + if ( !get_config_key( hkey, appkey, "force_modulateinvalpha_addcolor", buffer, size) ) + { + if (!strcmp(buffer,"enable")) + { + TRACE("Enabling WINED3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR even if not supported by hardware\n"); + forceModulateInvAlphaAddColor = TRUE; + } + } + if ( !get_config_key( hkey, appkey, "enable_slow_blit", buffer, size) ) + { + if (!strcmp(buffer,"enable")) + { + TRACE("Enabling slow pixel per pixel blits\n"); + enableSlowBlit = TRUE; + } + } } if (wined3d_settings.vs_mode == VS_HW) TRACE("Allow HW vertex shaders\n"); @@ -253,6 +309,10 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) if (appkey) RegCloseKey( appkey ); if (hkey) RegCloseKey( hkey ); + } else if(fdwReason == DLL_PROCESS_DETACH) + { + /* Restore screen res */ + if(deviceCreated) ChangeDisplaySettingsExW(NULL, NULL, NULL, 0, NULL); } return TRUE; } diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 3f69171c376..9dc7c85028b 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1117,6 +1117,7 @@ HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *S #define SFLAG_LOST 0x00002000 /* Surface lost flag for DDraw */ #define SFLAG_USERPTR 0x00004000 /* The application allocated the memory for this surface */ #define SFLAG_GLCKEY 0x00008000 /* The gl texture was created with a color key */ +#define SFLAG_CLIENT 0x00010000 /* GL_APPLE_client_storage is used on that texture */ /* In some conditions the surface memory must not be freed: * SFLAG_OVERSIZE: Not all data can be kept in GL @@ -1125,6 +1126,7 @@ HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *S * SFLAG_LOCKED: The app requires access to the surface data * SFLAG_DYNLOCK: Avoid freeing the data for performance * SFLAG_DYNCHANGE: Same reason as DYNLOCK + * SFLAG_CLIENT: OpenGL uses our memory as backup */ #define SFLAG_DONOTFREE (SFLAG_OVERSIZE | \ SFLAG_CONVERTED | \ @@ -1132,7 +1134,8 @@ HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *S SFLAG_LOCKED | \ SFLAG_DYNLOCK | \ SFLAG_DYNCHANGE | \ - SFLAG_USERPTR) + SFLAG_USERPTR | \ + SFLAG_CLIENT) BOOL CalculateTexRect(IWineD3DSurfaceImpl *This, RECT *Rect, float glTexCoord[4]); @@ -1362,6 +1365,8 @@ typedef struct IWineD3DSwapChainImpl HWND win_handle; Window win; + + BOOL XSynced; } IWineD3DSwapChainImpl; extern const IWineD3DSwapChainVtbl IWineD3DSwapChain_Vtbl; @@ -1951,4 +1956,11 @@ static inline BOOL use_ps(IWineD3DDeviceImpl *device) { && ((IWineD3DPixelShaderImpl *)device->stateBlock->pixelShader)->baseShader.function); } +/* Hacks, Hacks, Hacks */ +BOOL hl1hack, cursorhack, attribhack; +UINT ffp_textures; +BOOL forceModulateInvAlphaAddColor; +BOOL enableSlowBlit; + +BOOL deviceCreated; #endif diff --git a/dlls/wineoss.drv/Makefile.in b/dlls/wineoss.drv/Makefile.in index 9dd7b59375d..6781275ed4c 100644 --- a/dlls/wineoss.drv/Makefile.in +++ b/dlls/wineoss.drv/Makefile.in @@ -3,7 +3,7 @@ TOPOBJDIR = ../.. SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = wineoss.drv -IMPORTS = winmm user32 kernel32 +IMPORTS = winmm user32 advapi32 kernel32 EXTRALIBS = -ldxguid -luuid C_SRCS = \ diff --git a/dlls/wineoss.drv/audio.c b/dlls/wineoss.drv/audio.c index 98f5a708b08..a00fa6596ac 100644 --- a/dlls/wineoss.drv/audio.c +++ b/dlls/wineoss.drv/audio.c @@ -62,6 +62,7 @@ #include "winuser.h" #include "winnls.h" #include "winerror.h" +#include "winreg.h" #include "mmddk.h" #include "mmreg.h" #include "dsound.h" @@ -81,6 +82,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(wave); #ifdef HAVE_OSS +static int oss_locked_format=-1; +static int oss_locked_stereo=-1; +static int oss_locked_rate=-1; +static int oss_fullduplex=-1; + OSS_DEVICE OSS_Devices[MAX_WAVEDRV]; WINE_WAVEOUT WOutDev[MAX_WAVEDRV]; WINE_WAVEIN WInDev[MAX_WAVEDRV]; @@ -360,6 +366,11 @@ static DWORD OSS_RawOpenDevice(OSS_DEVICE* ossdev, int strict_format) if (ossdev->format>=0) { val = ossdev->format; + if (oss_locked_format>=0 && oss_locked_format!=ossdev->format) { + TRACE("OSS locked format is 0x%x, overriding 0x%x\n", + oss_locked_format,ossdev->format); + ossdev->format = oss_locked_format; + } rc = ioctl(fd, SNDCTL_DSP_SETFMT, &ossdev->format); if (rc != 0 || val != ossdev->format) { TRACE("Can't set format to %d (returned %d)\n", val, ossdev->format); @@ -380,6 +391,11 @@ static DWORD OSS_RawOpenDevice(OSS_DEVICE* ossdev, int strict_format) if (ossdev->sample_rate>=0) { val = ossdev->sample_rate; + if (oss_locked_rate>=0 && oss_locked_rate!=ossdev->sample_rate) { + TRACE("OSS locked rate is %d, overriding %d\n", + oss_locked_rate,ossdev->sample_rate); + ossdev->sample_rate = oss_locked_rate; + } rc = ioctl(fd, SNDCTL_DSP_SPEED, &ossdev->sample_rate); if (rc != 0 || !NEAR_MATCH(val, ossdev->sample_rate)) { TRACE("Can't set sample_rate to %u (returned %d)\n", val, ossdev->sample_rate); @@ -774,6 +790,11 @@ static BOOL OSS_WaveOutInit(OSS_DEVICE* ossdev) */ for (f=0;f<2;f++) { arg=win_std_oss_fmts[f]; + if (oss_locked_format>=0 && oss_locked_format!=arg) { + TRACE("OSS locked format is 0x%x, skipping 0x%x\n", + oss_locked_format,arg); + continue; + } rc=ioctl(ossdev->fd, SNDCTL_DSP_SAMPLESIZE, &arg); if (rc!=0 || arg!=win_std_oss_fmts[f]) { TRACE("DSP_SAMPLESIZE: rc=%d returned %d for %d\n", @@ -805,6 +826,11 @@ static BOOL OSS_WaveOutInit(OSS_DEVICE* ossdev) for (r=0;r=0 && oss_locked_rate!=arg) { + TRACE("OSS locked rate is %d, skipping %d\n", + oss_locked_rate,arg); + continue; + } rc=ioctl(ossdev->fd, SNDCTL_DSP_SPEED, &arg); TRACE("DSP_SPEED: rc=%d returned %d for %dx%dx%d\n", rc,arg,win_std_rates[r],win_std_oss_fmts[f],c); @@ -917,6 +943,11 @@ static BOOL OSS_WaveInInit(OSS_DEVICE* ossdev) /* See the comment in OSS_WaveOutInit for the loop order */ for (f=0;f<2;f++) { arg=win_std_oss_fmts[f]; + if (oss_locked_format>=0 && oss_locked_format!=arg) { + TRACE("OSS locked format is 0x%x, skipping 0x%x\n", + oss_locked_format,arg); + continue; + } rc=ioctl(ossdev->fd, SNDCTL_DSP_SAMPLESIZE, &arg); if (rc!=0 || arg!=win_std_oss_fmts[f]) { TRACE("DSP_SAMPLESIZE: rc=%d returned 0x%x for 0x%x\n", @@ -939,6 +970,11 @@ static BOOL OSS_WaveInInit(OSS_DEVICE* ossdev) for (r=0;r=0 && oss_locked_rate!=arg) { + TRACE("OSS locked rate is %d, skipping %d\n", + oss_locked_rate,arg); + continue; + } rc=ioctl(ossdev->fd, SNDCTL_DSP_SPEED, &arg); TRACE("DSP_SPEED: rc=%d returned %d for %dx%dx%d\n",rc,arg,win_std_rates[r],win_std_oss_fmts[f],c); if (rc==0 && NEAR_MATCH(arg,win_std_rates[r]) && c < 3) @@ -980,6 +1016,13 @@ static void OSS_WaveFullDuplexInit(OSS_DEVICE* ossdev) BOOL has_mixer = FALSE; TRACE("(%p) %s\n", ossdev, ossdev->dev_name); + if (!oss_fullduplex) + { + TRACE("FullDuplex has been disabled.\n"); + ossdev->full_duplex=0; + return; + } + /* The OSS documentation says we must call SNDCTL_SETDUPLEX * *before* checking for SNDCTL_DSP_GETCAPS otherwise we may * get the wrong result. This ioctl must even be done before @@ -1103,11 +1146,32 @@ static char* StrDup(const char* str, const char* def) */ LRESULT OSS_WaveInit(void) { + HKEY hKey; char* str; int i; TRACE("()\n"); + /* @@ Wine registry key: HKCU\Software\Wine\OSS Driver */ + if (!RegCreateKeyA(HKEY_CURRENT_USER, "Software\\Wine\\OSS Driver", &hKey)) { + char buffer[256]; + DWORD type,size; + + size = sizeof(buffer); + if (!RegQueryValueExA(hKey, "LockFormat", 0, &type, (LPVOID)buffer, &size)) + oss_locked_format=atoi(buffer); + size = sizeof(buffer); + if (!RegQueryValueExA(hKey, "LockStereo", 0, &type, (LPVOID)buffer, &size)) + oss_locked_stereo=atoi(buffer); + size = sizeof(buffer); + if (!RegQueryValueExA(hKey, "LockRate", 0, &type, (LPVOID)buffer, &size)) + oss_locked_rate=atoi(buffer); + size = sizeof(buffer); + if (!RegQueryValueExA(hKey, "FullDuplex", 0, &type, (LPVOID)buffer, &size)) + oss_fullduplex=atoi(buffer); + RegCloseKey(hKey); + } + str=getenv("AUDIODEV"); if (str!=NULL) { diff --git a/dlls/wineps.drv/generic.ppd b/dlls/wineps.drv/generic.ppd index ccc4f6375c2..110bdbaa58e 100644 --- a/dlls/wineps.drv/generic.ppd +++ b/dlls/wineps.drv/generic.ppd @@ -29,7 +29,7 @@ *OpenUI *PageSize/Media Size: PickOne *OrderDependency: 10 AnySetup *PageSize -*DefaultPageSize: A4 +*DefaultPageSize: Letter *PageSize Letter/Letter: "<>setpagedevice" *PageSize Legal/Legal: "<>setpagedevice" *PageSize Executive/Executive: "<>setpagedevice" diff --git a/dlls/wineps.drv/init.c b/dlls/wineps.drv/init.c index 3ff0def1ffd..ae9ab6c7ddd 100644 --- a/dlls/wineps.drv/init.c +++ b/dlls/wineps.drv/init.c @@ -159,7 +159,11 @@ BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved ) HeapDestroy( PSDRV_Heap ); #ifdef HAVE_CUPS_CUPS_H if (cupshandle && (cupshandle != (void*)-1)) { - wine_dlclose(cupshandle, NULL, 0); + /* Unloading here is causing a crash in the IE instal process. When it + * is unloading wineps twice. + * + * wine_dlclose(cupshandle, NULL, 0); + */ cupshandle = NULL; } #endif diff --git a/dlls/wineps.drv/ppd.c b/dlls/wineps.drv/ppd.c index 130613a427c..d52f6f9592f 100644 --- a/dlls/wineps.drv/ppd.c +++ b/dlls/wineps.drv/ppd.c @@ -516,6 +516,70 @@ static char *PSDRV_PPDGetWord(char *str, char **next) return ret; } +/************************************************************ + * parse_resolution + * + * Helper to extract x and y resolutions from a resolution entry. + * Returns TRUE on successful parsing, otherwise FALSE. + * + * The ppd spec says that entries can either be: + * "nnndpi" + * or + * "nnnxmmmdpi" + * in the former case return sz.cx == cx.cy == nnn. + * + * There are broken ppd files out there (notably from Samsung) that + * use the form "nnnmmmdpi", so we have to work harder to spot these. + * We use a transition from a zero to a non-zero digit as separator + * (and fail if we find more than one of these). We also don't bother + * trying to parse "dpi" in case that's missing. + */ +static BOOL parse_resolution(const char *str, SIZE *sz) +{ + int tmp[2]; + int *cur; + BOOL had_zero; + const char *c; + + if(sscanf(str, "%dx%d", tmp, tmp + 1) == 2) + { + sz->cx = tmp[0]; + sz->cy = tmp[1]; + return TRUE; + } + + tmp[0] = 0; + tmp[1] = -1; + cur = tmp; + had_zero = FALSE; + for(c = str; isdigit(*c); c++) + { + if(!had_zero || *c == '0') + { + *cur *= 10; + *cur += *c - '0'; + if(*c == '0') + had_zero = TRUE; + } + else if(cur != tmp) + return FALSE; + else + { + cur++; + *cur = *c - '0'; + had_zero = FALSE; + } + } + if(tmp[0] == 0) return FALSE; + + sz->cx = tmp[0]; + if(tmp[1] != -1) + sz->cy = tmp[1]; + else + sz->cy = sz->cx; + return TRUE; +} + /******************************************************************************* * PSDRV_AddSlot * @@ -605,8 +669,14 @@ PPD *PSDRV_ParsePPD(char *fname) else if((!strcmp("*DefaultResolution", tuple.key)) || (!strcmp("*DefaultJCLResolution", tuple.key))) { - sscanf(tuple.value, "%d", &(ppd->DefaultResolution)); - TRACE("DefaultResolution = %d\n", ppd->DefaultResolution); + SIZE sz; + if(parse_resolution(tuple.value, &sz)) + { + TRACE("DefaultResolution %dx%d\n", sz.cx, sz.cy); + ppd->DefaultResolution = sz.cx; + } + else + WARN("failed to parse DefaultResolution %s\n", debugstr_a(tuple.value)); } else if(!strcmp("*Font", tuple.key)) { diff --git a/dlls/wineps.drv/truetype.c b/dlls/wineps.drv/truetype.c index 913bf21c6ab..0557b419817 100644 --- a/dlls/wineps.drv/truetype.c +++ b/dlls/wineps.drv/truetype.c @@ -586,6 +586,10 @@ BOOL PSDRV_GetTrueTypeMetrics(void) static const WCHAR pathW[] = {'P','a','t','h',0}; FT_Error error; FT_Library library; + DWORD type; + const char *ftname = SONAME_LIBFREETYPE; + char freetypelib[MAX_PATH]; + LONG r; HKEY hkey; DWORD len; LPWSTR valueW; @@ -595,13 +599,23 @@ BOOL PSDRV_GetTrueTypeMetrics(void) if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) != ERROR_SUCCESS) return TRUE; - ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0); + len = sizeof freetypelib; + r = RegQueryValueExA( hkey, "FreeTypeLib", 0, &type, + (LPBYTE)freetypelib, &len ); + if( ( ERROR_SUCCESS == r ) && ( type == REG_SZ ) ) + { + ftname = freetypelib; + } + + TRACE("Using freetype library %s\n",ftname); + ft_handle = wine_dlopen(ftname, RTLD_NOW, NULL, 0); if(!ft_handle) { WINE_MESSAGE( "Wine cannot find the FreeType font library. To enable Wine to\n" "use TrueType fonts please install a version of FreeType greater than\n" "or equal to 2.0.5.\n" "http://www.freetype.org\n"); + WINE_MESSAGE("failed to load %s\n", ftname); RegCloseKey(hkey); return TRUE; } diff --git a/dlls/winex11.drv/Makefile.in b/dlls/winex11.drv/Makefile.in index 0684fc35c4e..2f30b0b6ee1 100644 --- a/dlls/winex11.drv/Makefile.in +++ b/dlls/winex11.drv/Makefile.in @@ -5,7 +5,7 @@ VPATH = @srcdir@ MODULE = winex11.drv IMPORTS = user32 gdi32 advapi32 kernel32 ntdll EXTRAINCL = @X_CFLAGS@ -EXTRALIBS = @X_LIBS@ @X_PRE_LIBS@ @XLIB@ @X_EXTRA_LIBS@ +EXTRALIBS = @X_LIBS@ @X_PRE_LIBS@ @XLIB@ @X_EXTRA_LIBS@ @CARBONLIB@ C_SRCS = \ bitblt.c \ @@ -24,6 +24,8 @@ C_SRCS = \ graphics.c \ init.c \ keyboard.c \ + mactext.c \ + mac_xim.c \ mouse.c \ opengl.c \ palette.c \ diff --git a/dlls/winex11.drv/bitblt.c b/dlls/winex11.drv/bitblt.c index 00bf37502c1..45a688ba725 100644 --- a/dlls/winex11.drv/bitblt.c +++ b/dlls/winex11.drv/bitblt.c @@ -881,6 +881,11 @@ static int BITBLT_GetSrcAreaStretch( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE visRectSrc->right - visRectSrc->left, visRectSrc->bottom - visRectSrc->top, AllPlanes, ZPixmap ); + if(!imageSrc) + { + FIXME("Failed!!\n"); + return 0; + } imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left, rectDst.bottom - rectDst.top, physDevDst->depth ); BITBLT_StretchImage( imageSrc, imageDst, widthSrc, heightSrc, diff --git a/dlls/winex11.drv/dce.c b/dlls/winex11.drv/dce.c index a0454cbf30d..2ec0a14bef9 100644 --- a/dlls/winex11.drv/dce.c +++ b/dlls/winex11.drv/dce.c @@ -98,7 +98,7 @@ static void update_visible_region( struct dce *dce ) HRGN vis_rgn = 0; HWND top = 0; struct x11drv_escape_set_drawable escape; - struct x11drv_win_data *data; + struct x11drv_win_data *data = X11DRV_get_win_data( dce->hwnd ); DWORD flags = dce->flags; size_t size = 256; @@ -146,12 +146,32 @@ static void update_visible_region( struct dce *dce ) if (dce->clip_rgn) CombineRgn( vis_rgn, vis_rgn, dce->clip_rgn, (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF ); - if (top == dce->hwnd && ((data = X11DRV_get_win_data( dce->hwnd )) != NULL) && - IsIconic( dce->hwnd ) && data->icon_window) + if (top == dce->hwnd && data && IsIconic( dce->hwnd ) && data->icon_window) escape.drawable = data->icon_window; else escape.drawable = X11DRV_get_whole_window( top ); + if (data && !data->toplevel) + { + HWND parent = dce->hwnd; + + while (parent != top) + { + struct x11drv_win_data *parent_data = X11DRV_get_win_data( parent ); + if (!parent_data) break; + if (parent_data->whole_window) + { + POINT pt = { 0, 0 }; + MapWindowPoints( top, parent, &pt, 1 ); + OffsetRect( &escape.dc_rect, pt.x, pt.y ); + OffsetRect( &escape.drawable_rect, -pt.x, -pt.y ); + escape.drawable = parent_data->whole_window; + break; + } + parent = GetAncestor( parent, GA_PARENT ); + } + } + escape.code = X11DRV_SET_DRAWABLE; escape.mode = IncludeInferiors; ExtEscape( dce->hdc, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); diff --git a/dlls/winex11.drv/dib.c b/dlls/winex11.drv/dib.c index c9210348a93..ab3fdfb3684 100644 --- a/dlls/winex11.drv/dib.c +++ b/dlls/winex11.drv/dib.c @@ -43,6 +43,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(bitmap); +#ifdef HAVE_XSHMEMULATEDSHMGET +#define shmget XShmEmulatedShmget +#define shmat XShmEmulatedShmat +#define shmdt XShmEmulatedShmdt +#define shmctl XShmEmulatedShmctl +#endif + static struct list dibs_list = LIST_INIT(dibs_list); static CRITICAL_SECTION dibs_cs; @@ -86,6 +93,7 @@ typedef struct BOOL useShm; int dibpitch; DWORD sizeImage; + X_PHYSBITMAP *physBitmap; } X11DRV_DIB_IMAGEBITS_DESCR; @@ -1527,6 +1535,7 @@ static void X11DRV_DIB_GetImageBits_8( int lines, BYTE *dstbits, linebytes = -linebytes; } +#if 0 /* * Hack for now * This condition is true when GetImageBits has been called by @@ -1535,6 +1544,7 @@ static void X11DRV_DIB_GetImageBits_8( int lines, BYTE *dstbits, * (In some cases, in an updateDIBSection, the returned colors are bad too) */ if (!srccolors) goto updatesection; +#endif switch (bmpImage->depth) { case 1: @@ -1746,7 +1756,9 @@ static void X11DRV_DIB_GetImageBits_8( int lines, BYTE *dstbits, WARN("from unknown %d bit bitmap (%lx,%lx,%lx) to 8 bit DIB\n", bmpImage->depth, bmpImage->red_mask, bmpImage->green_mask, bmpImage->blue_mask ); +#if 0 updatesection: +#endif /* ==== any bmp format -> pal 8 dib ==== */ for (h=lines-1; h>=0; h--) { dstbyte=dstbits; @@ -2869,7 +2881,6 @@ static void X11DRV_DIB_SetImageBits_32(int lines, const BYTE *srcbits, DWORD linebytes) { DWORD x; - const DWORD *ptr; int h, width = min(srcwidth, dstwidth); const dib_conversions *convs = (bmpImage->byte_order == LSBFirst) ? &dib_normal : &dib_dst_byteswap; @@ -2880,8 +2891,6 @@ static void X11DRV_DIB_SetImageBits_32(int lines, const BYTE *srcbits, linebytes = -linebytes; } - ptr = (const DWORD *) srcbits + left; - switch (bmpImage->depth) { case 24: @@ -3486,7 +3495,7 @@ static int X11DRV_DIB_SetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr ) { int lines = descr->lines >= 0 ? descr->lines : -descr->lines; XImage *bmpImage; - + void *olddata = NULL; wine_tsx11_lock(); if (descr->image) bmpImage = descr->image; @@ -3508,6 +3517,15 @@ static int X11DRV_DIB_SetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr ) bmpImage->depth,bmpImage->bits_per_pixel, bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask); +#ifdef HAVE_LIBXXSHM + if (descr->useShm && descr->xSrc == 0 && descr->ySrc == 0 && descr->xDest == 0 && descr->yDest == 0) { + TRACE("using the shared pixmap data\n"); + XSync(gdi_display, False); + olddata = descr->image->data; + descr->image->data = descr->physBitmap->shminfo.shmaddr; + } +#endif + /* Transfer the pixels */ switch(descr->infoBpp) { @@ -3574,11 +3592,8 @@ static int X11DRV_DIB_SetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr ) descr->xSrc, descr->ySrc, descr->xDest, descr->yDest, descr->width, descr->height); #ifdef HAVE_LIBXXSHM - if (descr->image && descr->useShm) + if (descr->useShm && descr->xSrc == 0 && descr->ySrc == 0 && descr->xDest == 0 && descr->yDest == 0) { - XShmPutImage( gdi_display, descr->drawable, descr->gc, bmpImage, - descr->xSrc, descr->ySrc, descr->xDest, descr->yDest, - descr->width, descr->height, FALSE ); XSync( gdi_display, 0 ); } else @@ -3587,6 +3602,8 @@ static int X11DRV_DIB_SetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr ) descr->xSrc, descr->ySrc, descr->xDest, descr->yDest, descr->width, descr->height ); + if(olddata) descr->image->data = olddata; + if (!descr->image) XDestroyImage( bmpImage ); wine_tsx11_unlock(); return lines; @@ -3601,6 +3618,7 @@ static int X11DRV_DIB_GetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr ) { int lines = descr->lines >= 0 ? descr->lines : -descr->lines; XImage *bmpImage; + void *olddata = NULL; wine_tsx11_lock(); if (descr->image) @@ -3618,29 +3636,12 @@ static int X11DRV_DIB_GetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr ) } #ifdef HAVE_LIBXXSHM - if (descr->image && descr->useShm) + if (descr->useShm && descr->xSrc == 0 && descr->ySrc == 0 && descr->xDest == 0 && descr->yDest == 0) { - int saveRed, saveGreen, saveBlue; - - TRACE("XShmGetImage(%p, %ld, %p, %d, %d, %ld)\n", - gdi_display, descr->drawable, bmpImage, - descr->xSrc, descr->ySrc, AllPlanes); - - /* We must save and restore the bmpImage's masks in order - * to preserve them across the call to XShmGetImage, which - * decides to eleminate them since it doesn't happen to know - * what the format of the image is supposed to be, even though - * we do. */ - saveRed = bmpImage->red_mask; - saveBlue= bmpImage->blue_mask; - saveGreen = bmpImage->green_mask; - - XShmGetImage( gdi_display, descr->drawable, bmpImage, - descr->xSrc, descr->ySrc, AllPlanes); - - bmpImage->red_mask = saveRed; - bmpImage->blue_mask = saveBlue; - bmpImage->green_mask = saveGreen; + XSync(gdi_display, False); + olddata = bmpImage->data; + bmpImage->data = descr->physBitmap->shminfo.shmaddr; + TRACE("using shared pixmap data\n"); } else #endif /* HAVE_LIBXXSHM */ @@ -3720,6 +3721,7 @@ static int X11DRV_DIB_GetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr ) break; } + if(olddata) bmpImage->data = olddata; if (!descr->image) XDestroyImage( bmpImage ); wine_tsx11_unlock(); return lines; @@ -4040,6 +4042,7 @@ INT X11DRV_GetDIBits( X11DRV_PDEVICE *physDev, HBITMAP hbitmap, UINT startscan, descr.yDest = 0; descr.xSrc = 0; descr.sizeImage = core_header ? 0 : info->bmiHeader.biSizeImage; + descr.physBitmap = physBitmap; if (descr.lines > 0) { @@ -4049,13 +4052,8 @@ INT X11DRV_GetDIBits( X11DRV_PDEVICE *physDev, HBITMAP hbitmap, UINT startscan, { descr.ySrc = startscan; } -#ifdef HAVE_LIBXXSHM - descr.useShm = (obj_size == sizeof(DIBSECTION)) && (physBitmap->shminfo.shmid != -1); -#else descr.useShm = FALSE; -#endif - descr.dibpitch = (obj_size == sizeof(DIBSECTION)) ? dib.dsBm.bmWidthBytes - : (((descr.infoWidth * descr.infoBpp + 31) &~31) / 8); + descr.dibpitch = ((descr.infoWidth * descr.infoBpp + 31) &~31) / 8; X11DRV_DIB_Lock( physBitmap, DIB_Status_GdiMod, FALSE ); X11DRV_DIB_GetImageBits( &descr ); @@ -4113,6 +4111,8 @@ static void X11DRV_DIB_DoCopyDIBSection(X_PHYSBITMAP *physBitmap, BOOL toDIB, descr.physDev = NULL; descr.palentry = NULL; + descr.image = physBitmap->image; + descr.physBitmap= physBitmap; descr.infoWidth = dibSection.dsBmih.biWidth; descr.infoBpp = dibSection.dsBmih.biBitCount; descr.lines = dibSection.dsBmih.biHeight; @@ -4160,7 +4160,7 @@ static void X11DRV_DIB_DoCopyDIBSection(X_PHYSBITMAP *physBitmap, BOOL toDIB, descr.sizeImage = 0; #ifdef HAVE_LIBXXSHM - descr.useShm = (physBitmap->shminfo.shmid != -1); + descr.useShm = (physBitmap->shminfo.shmid != -1) && (physBitmap->pixmap == dest); #else descr.useShm = FALSE; #endif @@ -4538,7 +4538,8 @@ static XImage *X11DRV_XShmCreateImage( int width, int height, int bpp, IPC_CREAT|0700); if( shminfo->shmid != -1 ) { - shminfo->shmaddr = image->data = shmat(shminfo->shmid, 0, 0); + shminfo->shmaddr = shmat(shminfo->shmid, 0, 0); + image->data = calloc(height, image->bytes_per_line); if( shminfo->shmaddr != (char*)-1 ) { BOOL ok; @@ -4576,6 +4577,10 @@ HBITMAP X11DRV_CreateDIBSection( X11DRV_PDEVICE *physDev, HBITMAP hbitmap, { X_PHYSBITMAP *physBitmap; DIBSECTION dib; +#ifdef HAVE_LIBXXSHM + int major, minor; + Bool pixmaps; +#endif if (!(physBitmap = X11DRV_init_phys_bitmap( hbitmap ))) return 0; physBitmap->status = DIB_Status_None; @@ -4593,16 +4598,27 @@ HBITMAP X11DRV_CreateDIBSection( X11DRV_PDEVICE *physDev, HBITMAP hbitmap, /* create pixmap and X image */ wine_tsx11_lock(); physBitmap->pixmap_depth = (dib.dsBm.bmBitsPixel == 1) ? 1 : screen_depth; - physBitmap->pixmap = XCreatePixmap( gdi_display, root_window, dib.dsBm.bmWidth, - dib.dsBm.bmHeight, physBitmap->pixmap_depth ); + #ifdef HAVE_LIBXXSHM physBitmap->shminfo.shmid = -1; - if (!XShmQueryExtension(gdi_display) || - !(physBitmap->image = X11DRV_XShmCreateImage( dib.dsBm.bmWidth, dib.dsBm.bmHeight, - physBitmap->pixmap_depth, &physBitmap->shminfo )) ) + if(!(XShmQueryVersion(gdi_display, &major, &minor, &pixmaps) && pixmaps && + (physBitmap->image = X11DRV_XShmCreateImage( dib.dsBm.bmWidth, dib.dsBm.bmHeight, + physBitmap->pixmap_depth, &physBitmap->shminfo ))) ) #endif physBitmap->image = X11DRV_DIB_CreateXImage( dib.dsBm.bmWidth, dib.dsBm.bmHeight, physBitmap->pixmap_depth ); +#ifdef HAVE_LIBXXSHM + if (physBitmap->shminfo.shmid != -1) + { + TRACE("Creating shared pixmap for bmp %p\n", physBitmap->hbitmap); + physBitmap->pixmap = XShmCreatePixmap(gdi_display, root_window, + physBitmap->shminfo.shmaddr, &physBitmap->shminfo, + dib.dsBm.bmWidth, dib.dsBm.bmHeight, + physBitmap->pixmap_depth); + } else +#endif + physBitmap->pixmap = XCreatePixmap( gdi_display, root_window, dib.dsBm.bmWidth, + dib.dsBm.bmHeight, physBitmap->pixmap_depth ); wine_tsx11_unlock(); if (!physBitmap->pixmap || !physBitmap->image) return 0; @@ -4653,6 +4669,10 @@ void X11DRV_DIB_DeleteDIBSection(X_PHYSBITMAP *physBitmap, DIBSECTION *dib) if (physBitmap->shminfo.shmid != -1) { XShmDetach( gdi_display, &(physBitmap->shminfo) ); + if(physBitmap->image->data) { + free(physBitmap->image->data); + physBitmap->image->data = NULL; + } XDestroyImage( physBitmap->image ); shmdt( physBitmap->shminfo.shmaddr ); physBitmap->shminfo.shmid = -1; @@ -4692,11 +4712,11 @@ UINT X11DRV_SetDIBColorTable( X11DRV_PDEVICE *physDev, UINT start, UINT count, c * FIXME we need to recalculate the pen, brush, text and bkgnd pixels here, * at least for a 1 bpp dibsection */ - X11DRV_DIB_Lock( physBitmap, DIB_Status_AppMod, FALSE ); +/* X11DRV_DIB_Lock( physBitmap, DIB_Status_AppMod, FALSE ); */ X11DRV_DIB_GenColorMap( physDev, physBitmap->colorMap, DIB_RGB_COLORS, dib.dsBm.bmBitsPixel, TRUE, colors, start, end ); - X11DRV_DIB_Unlock( physBitmap, TRUE ); +/* X11DRV_DIB_Unlock( physBitmap, TRUE ); */ ret = end - start; } return ret; diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 0ea1f9cea47..92b001a1c40 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -68,6 +68,7 @@ static void EVENT_FocusIn( HWND hwnd, XEvent *event ); static void EVENT_FocusOut( HWND hwnd, XEvent *event ); static void EVENT_PropertyNotify( HWND hwnd, XEvent *event ); static void EVENT_ClientMessage( HWND hwnd, XEvent *event ); +static void EVENT_GravityNotify( HWND hwnd, XEvent *event ); struct event_handler { @@ -95,14 +96,14 @@ static struct event_handler handlers[MAX_EVENT_HANDLERS] = /* NoExpose */ /* VisibilityNotify */ /* CreateNotify */ - /* DestroyNotify */ + { DestroyNotify, X11DRV_DestroyNotify }, { UnmapNotify, X11DRV_UnmapNotify }, { MapNotify, X11DRV_MapNotify }, /* MapRequest */ /* ReparentNotify */ { ConfigureNotify, X11DRV_ConfigureNotify }, /* ConfigureRequest */ - /* GravityNotify */ + { GravityNotify, EVENT_GravityNotify }, /* ResizeRequest */ /* CirculateNotify */ /* CirculateRequest */ @@ -115,8 +116,7 @@ static struct event_handler handlers[MAX_EVENT_HANDLERS] = { MappingNotify, X11DRV_MappingNotify }, }; -static int nb_event_handlers = 18; /* change this if you add handlers above */ - +static int nb_event_handlers = 20; /* change this if you add handlers above */ /* return the name of an X event */ static const char *dbgstr_event( int type ) @@ -559,6 +559,18 @@ static void EVENT_FocusOut( HWND hwnd, XEvent *xev ) SetForegroundWindow( 0 ); } } + if (forcealtrelease && GetAsyncKeyState(VK_MENU)<0) + { + INPUT fake_alt_release; + fake_alt_release.type = INPUT_KEYBOARD; + fake_alt_release.u.ki.wVk = VK_MENU; + fake_alt_release.u.ki.wScan = 0; + fake_alt_release.u.ki.dwFlags = KEYEVENTF_KEYUP; + fake_alt_release.u.ki.time = GetTickCount(); /* is it really this kind of timestamp ? */ + fake_alt_release.u.ki.dwExtraInfo = 0; + SendInput(1, &fake_alt_release, sizeof(INPUT)); + } + } @@ -932,6 +944,34 @@ static void EVENT_ClientMessage( HWND hwnd, XEvent *xev ) /********************************************************************** + * EVENT_GravityNotify + */ +static void EVENT_GravityNotify( HWND hwnd, XEvent *event ) +{ + struct x11drv_win_data *data = X11DRV_get_win_data( hwnd ); + + /* In this case we don't get a ConfigureNotify so we fake it */ + if (data) + { + int flags = SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE; + WND *pWnd = WIN_GetPtr(hwnd); + + if (event->xgravity.x == pWnd->rectWindow.left && event->xgravity.y == pWnd->rectWindow.top) + flags |= SWP_NOMOVE; + + WIN_ReleasePtr( pWnd ); + + if (~flags & SWP_NOMOVE) + { + data->lock_changes++; + SetWindowPos( hwnd, 0, event->xgravity.x, event->xgravity.y, 0, 0, flags ); + data->lock_changes--; + } + } +} + + +/********************************************************************** * X11DRV_WindowMessage (X11DRV.@) */ LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 96a0dc15c9c..a5dbd3ff435 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -55,6 +55,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(keyboard); WINE_DECLARE_DEBUG_CHANNEL(key); +#ifdef __APPLE__ +extern int ProcessMacInput(XKeyEvent*); +#endif + typedef union { struct @@ -1373,6 +1377,12 @@ void X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) ascii_chars = XLookupString(event, Str, sizeof(Str), &keysym, NULL); wine_tsx11_unlock(); +#ifdef __APPLE__ + + if (ProcessMacInput(event)) + return; +#endif + TRACE_(key)("state = %X nbyte = %d, status 0x%x\n", event->state, ascii_chars, status); if (status == XBufferOverflow) @@ -1820,23 +1830,6 @@ void X11DRV_InitKeyboard(void) } -/********************************************************************** - * GetAsyncKeyState (X11DRV.@) - */ -SHORT X11DRV_GetAsyncKeyState(INT key) -{ - SHORT retval; - - X11DRV_MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_KEY, 0 ); - - retval = ((key_state_table[key] & 0x40) ? 0x0001 : 0) | - ((key_state_table[key] & 0x80) ? 0x8000 : 0); - key_state_table[key] &= ~0x40; - TRACE_(key)("(%x) -> %x\n", key, retval); - return retval; -} - - /*********************************************************************** * GetKeyboardLayoutList (X11DRV.@) */ @@ -2153,6 +2146,9 @@ UINT X11DRV_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl) if (wCode==VK_DECIMAL) e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal); + if (wCode==VK_SEPARATOR) + e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator); + if (!e.keycode) { WARN("Unknown virtual key %X !!!\n", wCode); @@ -2465,6 +2461,10 @@ INT X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, LPBYTE lpKeyState, if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9)) e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0); + /* don't apply the numlock state to the non-keypad arrows */ + if ((virtKey>=VK_PRIOR) && (virtKey<=VK_HELP) && (scanCode & KF_EXTENDED)) + e.state &= ~NumLockMask; + if (virtKey==VK_DECIMAL) e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal); diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index e372a0f5eda..c49f44df94f 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -90,6 +90,8 @@ static DWORD last_time_modified; static RECT cursor_clip; /* Cursor clipping rect */ BOOL X11DRV_SetCursorPos( INT x, INT y ); +extern DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, + const HANDLE *handles, DWORD timeout, DWORD mask, DWORD flags); /*********************************************************************** @@ -122,14 +124,21 @@ void X11DRV_Xcursor_Init(void) * * get the coordinates of a mouse event */ -static inline void get_coords( HWND hwnd, int x, int y, POINT *pt ) +static inline HWND get_coords( HWND hwnd, int x, int y, POINT *pt ) { struct x11drv_win_data *data = X11DRV_get_win_data( hwnd ); - if (!data) return; + if (!data) return hwnd; pt->x = x + data->whole_rect.left; pt->y = y + data->whole_rect.top; + + if (!data->toplevel) + { + MapWindowPoints( GetAncestor( hwnd, GA_PARENT ), 0, pt, 1 ); + hwnd = GetAncestor( hwnd, GA_ROOT ); + } + return hwnd; } /*********************************************************************** @@ -164,7 +173,7 @@ static inline void update_button_state( unsigned int state ) * * Update the various window states on a mouse event. */ -static void update_mouse_state( HWND hwnd, Window window, int x, int y, unsigned int state, POINT *pt ) +static HWND update_mouse_state( HWND hwnd, Window window, int x, int y, unsigned int state, POINT *pt ) { struct x11drv_thread_data *data = x11drv_thread_data(); @@ -173,7 +182,7 @@ static void update_mouse_state( HWND hwnd, Window window, int x, int y, unsigned x += virtual_screen_rect.left; y += virtual_screen_rect.top; } - get_coords( hwnd, x, y, pt ); + hwnd = get_coords( hwnd, x, y, pt ); /* update the cursor */ @@ -202,6 +211,7 @@ static void update_mouse_state( HWND hwnd, Window window, int x, int y, unsigned } SERVER_END_REQ; } + return hwnd; } @@ -926,6 +936,35 @@ BOOL X11DRV_SetCursorPos( INT x, INT y ) } /*********************************************************************** + * GetAsyncKeyState (X11DRV.@) + */ +SHORT X11DRV_GetAsyncKeyState( INT key ) +{ + Display *display = thread_display(); + Window root, child; + int rootX, rootY, winX, winY; + unsigned int xstate; + SHORT retval; + + /* Make sure the keyboard state is up to date */ + X11DRV_MsgWaitForMultipleObjectsEx(0,0,0,QS_KEY,0); + + if (key == VK_LBUTTON || key == VK_MBUTTON || key == VK_RBUTTON) + { + wine_tsx11_lock(); + if (XQueryPointer( display, root_window, &root, &child, + &rootX, &rootY, &winX, &winY, &xstate )) + update_button_state( xstate ); + wine_tsx11_unlock(); + } + retval = ((key_state_table[key] & 0x40) ? 0x0001 : 0) | + ((key_state_table[key] & 0x80) ? 0x8000 : 0); + key_state_table[key] &= ~0x40; + TRACE("(%x) -> %x\n", key, retval); + return retval; +} + +/*********************************************************************** * GetCursorPos (X11DRV.@) */ BOOL X11DRV_GetCursorPos(LPPOINT pos) @@ -940,7 +979,6 @@ BOOL X11DRV_GetCursorPos(LPPOINT pos) XQueryPointer( display, root_window, &root, &child, &rootX, &rootY, &winX, &winY, &xstate )) { - update_button_state( xstate ); winX += virtual_screen_rect.left; winY += virtual_screen_rect.top; TRACE("pointer at (%d,%d)\n", winX, winY ); @@ -995,7 +1033,7 @@ void X11DRV_ButtonPress( HWND hwnd, XEvent *xev ) break; } - update_mouse_state( hwnd, event->window, event->x, event->y, event->state, &pt ); + hwnd = update_mouse_state( hwnd, event->window, event->x, event->y, event->state, &pt ); X11DRV_send_mouse_input( hwnd, button_down_flags[buttonNum] | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE, pt.x, pt.y, wData, EVENT_x11_time_to_win32_time(event->time), 0, 0 ); @@ -1025,7 +1063,7 @@ void X11DRV_ButtonRelease( HWND hwnd, XEvent *xev ) break; } - update_mouse_state( hwnd, event->window, event->x, event->y, event->state, &pt ); + hwnd = update_mouse_state( hwnd, event->window, event->x, event->y, event->state, &pt ); X11DRV_send_mouse_input( hwnd, button_up_flags[buttonNum] | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE, pt.x, pt.y, wData, EVENT_x11_time_to_win32_time(event->time), 0, 0 ); @@ -1044,7 +1082,7 @@ void X11DRV_MotionNotify( HWND hwnd, XEvent *xev ) if (!hwnd) return; - update_mouse_state( hwnd, event->window, event->x, event->y, event->state, &pt ); + hwnd = update_mouse_state( hwnd, event->window, event->x, event->y, event->state, &pt ); X11DRV_send_mouse_input( hwnd, MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE, pt.x, pt.y, 0, EVENT_x11_time_to_win32_time(event->time), 0, 0 ); @@ -1065,7 +1103,7 @@ void X11DRV_EnterNotify( HWND hwnd, XEvent *xev ) if (event->detail == NotifyVirtual || event->detail == NotifyNonlinearVirtual) return; /* simulate a mouse motion event */ - update_mouse_state( hwnd, event->window, event->x, event->y, event->state, &pt ); + hwnd = update_mouse_state( hwnd, event->window, event->x, event->y, event->state, &pt ); X11DRV_send_mouse_input( hwnd, MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE, pt.x, pt.y, 0, EVENT_x11_time_to_win32_time(event->time), 0, 0 ); diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 0e2f9ee2228..21bae478703 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -862,6 +862,8 @@ static BOOL get_fbconfig_from_visualid(Display *display, Visual *visual, int *fm static BOOL init_formats(Display *display, int screen, Visual *visual) { int fmt_id, fmt_index; + int nCfgs = 0; + GLXFBConfig* cfgs = NULL; /* Locate the fbconfig correspondig to our main visual */ if(!get_fbconfig_from_visualid(display, visual, &fmt_id, &fmt_index)) { @@ -870,11 +872,39 @@ static BOOL init_formats(Display *display, int screen, Visual *visual) } /* Put Wine's internal format at the first index */ - WineGLPixelFormatList[0].iPixelFormat = 1; - WineGLPixelFormatList[0].fbconfig = fmt_id; - WineGLPixelFormatList[0].fmt_index = fmt_index; + WineGLPixelFormatList[WineGLPixelFormatListSize].iPixelFormat = 1; + WineGLPixelFormatList[WineGLPixelFormatListSize].fbconfig = fmt_id; + WineGLPixelFormatList[WineGLPixelFormatListSize].fmt_index = fmt_index; WineGLPixelFormatListSize = 1; + /* HACK: Wow needs at least one offscreen format enumerated, otherwise it crashes when changing settings */ + if(!find_offscreen_formats) { + return TRUE; + } + + cfgs = pglXGetFBConfigs(display, screen, &nCfgs); + if (NULL == cfgs || 0 == nCfgs) { + ERR("glXChooseFBConfig returns NULL\n"); + if(cfgs != NULL) XFree(cfgs); + return TRUE; + } + + /* HACK 2: My driver(nvidia 9755) gets stuck in glXGetFBConfigAttrib for higher fbconfigs. So limit the amount of them */ + if(nCfgs > find_offscreen_formats) nCfgs = find_offscreen_formats; + + for(fmt_index=0; fmt_index 1) { + res = FALSE; + } else { + res = ConvertPixelFormatWGLtoGLX(gdi_display, iPixelFormat, &fmt_index, &fmt_count); + } if (ppfd == NULL) { /* The application is only querying the number of visuals */ wine_tsx11_lock(); if (NULL != cfgs) XFree(cfgs); wine_tsx11_unlock(); - return fmt_count; + return max(fmt_count, 1); } else if(res == FALSE) { WARN("unexpected iPixelFormat(%d): not >=1 and <=nFormats(%d), returning NULL!\n", iPixelFormat, fmt_count); wine_tsx11_lock(); @@ -1219,7 +1253,7 @@ BOOL X11DRV_SetPixelFormat(X11DRV_PDEVICE *physDev, } /* Check if iPixelFormat is in our list of supported formats to see if it is supported. */ - if(!ConvertPixelFormatWGLtoGLX(gdi_display, iPixelFormat, &fmt_index, &value)) { + if(iPixelFormat > 1 || !ConvertPixelFormatWGLtoGLX(gdi_display, iPixelFormat, &fmt_index, &value)) { ERR("Invalid iPixelFormat: %d\n", iPixelFormat); return 0; } @@ -1296,7 +1330,7 @@ HGLRC X11DRV_wglCreateContext(X11DRV_PDEVICE *physDev) /* We can only render using the iPixelFormat (1) of Wine's Main visual, we need to get the corresponding GLX format. * If this fails something is very wrong on the system. */ - if(!ConvertPixelFormatWGLtoGLX(gdi_display, hdcPF, &fmt_index, &fmt_count)) { + if(hdcPF > 1 || !ConvertPixelFormatWGLtoGLX(gdi_display, hdcPF, &fmt_index, &fmt_count)) { ERR("Cannot get FB Config for main iPixelFormat 1, expect problems!\n"); SetLastError(ERROR_INVALID_PIXEL_FORMAT); return NULL; diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index a31227fc07c..117bd3c0f92 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -54,6 +54,9 @@ XContext winContext = 0; /* X context to associate a struct x11drv_win_data to an hwnd */ static XContext win_data_context; +BOOL WM_has_win_state = FALSE; +BOOL WM_has_net_wm_state = FALSE; + static const char whole_window_prop[] = "__wine_x11_whole_window"; static const char icon_window_prop[] = "__wine_x11_icon_window"; static const char managed_prop[] = "__wine_x11_managed"; @@ -61,6 +64,11 @@ static const char visual_id_prop[] = "__wine_x11_visual_id"; /* for XDG systray icons */ #define SYSTEM_TRAY_REQUEST_DOCK 0 +#define SYSTEM_TRAY_BEGIN_MESSAGE 1 +#define SYSTEM_TRAY_CANCEL_MESSAGE 2 + +/* XEmbed defines */ +#define XEMBED_MAPPED 1 /*********************************************************************** * is_window_managed @@ -75,8 +83,25 @@ static inline BOOL is_window_managed( HWND hwnd ) /* tray window is always managed */ ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE ); if (ex_style & WS_EX_TRAYWINDOW) return TRUE; - /* child windows are not managed */ + /* tool windows *are* managed if we have mwm hints */ style = GetWindowLongW( hwnd, GWL_STYLE ); + if (ex_style & WS_EX_TOOLWINDOW) + { + char class[80]; + GetClassNameA(hwnd,class,sizeof class); + if ( (style & WS_POPUP) && ((strcmp(class,"PSFloatC")==0) || + (strcmp(class,"Internet Explorer_Server")==0)) ) + return TRUE; + /* Dreamweaver MX 2004 floating toolbars */ + if( !strcmp( class, "Afx:00400000:8:000010DE:00000000:00000000" ) ) + return TRUE; + return !strcmp(class,"MsoSplash") || + !strcmp(class,"ibw:0") || + !strcmp(class,"ibw:1") || + !strcmp(class,"#32770") || + !strcmp(class,"icoCTactTrilly"); /* Trillian buddy window */ + } + /* child windows are not managed */ if (style & WS_CHILD) return FALSE; /* windows with caption are managed */ if ((style & WS_CAPTION) == WS_CAPTION) return TRUE; @@ -84,6 +109,75 @@ static inline BOOL is_window_managed( HWND hwnd ) if (ex_style & WS_EX_TOOLWINDOW) return FALSE; /* windows with thick frame are managed */ if (style & WS_THICKFRAME) return TRUE; + + /* + * CODEWEAVERS HACK + * Hack to pervent the Quicken splash screen from obscuring + * the password dialog when it is displayed. + * + * also includes an ugly hack for photoshop 5. This keeps the windows from + * being alwayse on top and following the desktop. Just returning TRUE + * caused the PS5 windows to become decorated by the windowmanager. and + * closing the window with the WM close button caused VERY bad things to + * happen inside photoshop. + */ + if (1) + { + char class[80], *p; + GetClassNameA(hwnd,class,sizeof class); + /* + * In Scientific Word, the startup dialog should be managed. + * In SAP Netweaver, the tooltips should not (WS_EX_TOPMOST). + */ + if ( (strcmp(class,"#32770")==0) && + !(ex_style & WS_EX_TOPMOST) ) + return TRUE; + if (strcmp(class,"SplashWnd")==0) + return TRUE; + if (strcmp(class,"iTunes")==0) + return TRUE; + if (strcmp(class,"QuickTimePlayerMain") == 0) + return TRUE; /* QuickTime 7.1 */ + if ((p = strrchr(class, '\\')) && strcmp(p+1,"QuickTimePlayer.exe") == 0) + return TRUE; /* QuickTime 6.x */ + if (strcmp(class,"PSFloatC")==0) + return TRUE; + /* the office 97 splash screen is not a toolbar */ + if (strcmp(class,"MsoSplash") == 0) + return TRUE; + if ((strcmp(class,"IEFrame") == 0) && (style & WS_SYSMENU)) + return TRUE; + /* for CRPSClient for WorldVistA */ + if (strcmp(class,"TfrmSplash") == 0) + return TRUE; + /* Halo setup window */ + if (strcmp(class,"EBUSetupWnd") == 0) + return TRUE; + /* AWR line style popup */ + if (strcmp(class,"WTL_LineStyleColorDD") == 0) + return TRUE; + /* AWR fill style popup */ + if (strcmp(class,"WTL_PatternColorDD") == 0) + return TRUE; + /* Quickbooks InstallShield window */ + if (strcmp(class,"DlgcacClsName") == 0) + return TRUE; + +#ifdef __APPLE__ + /* Macos does not like those windows to be managed, but Linux needs that(handled below in the + * POPUP | SYSMENU case + */ + /* EVE online - Does not redraw otherwise*/ + if(strcmp(class, "eveSplatter") == 0 || strcmp(class, "triuiScreen") == 0) + return FALSE; +#endif + + /* for outlook 2003 completion window */ + if (strcmp(class,"REListBox20W") == 0 && (style & WS_POPUP) && + (style & WS_SYSMENU)) + return FALSE; + } + /* application windows are managed */ if (ex_style & WS_EX_APPWINDOW) return TRUE; if (style & WS_POPUP) @@ -91,7 +185,9 @@ static inline BOOL is_window_managed( HWND hwnd ) RECT rect; /* popup with sysmenu == caption are managed */ - if (style & WS_SYSMENU) return TRUE; + if (style & WS_SYSMENU) + return TRUE; + /* full-screen popup windows are managed */ GetWindowRect( hwnd, &rect ); if ((rect.right - rect.left) == screen_width && (rect.bottom - rect.top) == screen_height) @@ -132,6 +228,8 @@ static int get_window_attributes( Display *display, struct x11drv_win_data *data XSetWindowAttributes *attr ) { if (!data->managed && + data->toplevel && + !data->adopted && root_window == DefaultRootWindow( display ) && data->whole_window != root_window && is_window_managed( data->hwnd )) @@ -158,7 +256,7 @@ void X11DRV_sync_window_style( Display *display, struct x11drv_win_data *data ) int mask = get_window_attributes( display, data, &attr ); wine_tsx11_lock(); - if (data->whole_window != DefaultRootWindow(display)) + if (data->whole_window != DefaultRootWindow(display) && !data->adopted) XChangeWindowAttributes( display, data->whole_window, mask, &attr ); wine_tsx11_unlock(); } @@ -346,7 +444,9 @@ static void systray_dock_window( Display *display, struct x11drv_win_data *data /* set XEMBED protocol data on the window */ info[0] = 0; /* protocol version */ - info[1] = 1; /* mapped = true */ + /* we always want the window to be mapped when it is embedded, as it + * was unmapped above */ + info[1] = XEMBED_MAPPED; /* flags */ wine_tsx11_lock(); XChangeProperty( display, data->whole_window, @@ -412,6 +512,11 @@ static void set_size_hints( Display *display, struct x11drv_win_data *data, DWOR size_hints->x = data->whole_rect.left; size_hints->y = data->whole_rect.top; size_hints->flags |= PWinGravity | PPosition; + if (data->managed && applewm_title_height && (style & WS_CAPTION) == WS_CAPTION) + { + size_hints->y -= applewm_title_height; + size_hints->win_gravity = NorthWestGravity; + } } if ( !(style & WS_THICKFRAME) ) @@ -429,6 +534,61 @@ static void set_size_hints( Display *display, struct x11drv_win_data *data, DWOR /*********************************************************************** + * WM_RemoveFromTaskbar + * + * make sure that this window doesn't appear on the task list or task bar + */ +static BOOL WM_RemoveFromTaskbar(Display *display, struct x11drv_win_data *data ) +{ + /* KDE 2 style */ + if(WM_has_net_wm_state) + { + XEvent xev; + + wine_tsx11_lock(); + xev.xclient.type = ClientMessage; + xev.xclient.window = data->whole_window; + xev.xclient.message_type = x11drv_atom(_NET_WM_STATE); + xev.xclient.serial = 0; + xev.xclient.display = display; + xev.xclient.send_event = True; + xev.xclient.format = 32; + xev.xclient.data.l[0] = _NET_WM_STATE_ADD; + xev.xclient.data.l[1] = x11drv_atom(_NET_WM_STATE_SKIP_TASKBAR); + xev.xclient.data.l[2] = x11drv_atom(_NET_WM_STATE_SKIP_PAGER); + XSendEvent(thread_display(), root_window, False, SubstructureNotifyMask, &xev); + wine_tsx11_unlock(); + + return TRUE; + } + + /* GNOME style */ + if(WM_has_win_state) + { + XEvent xev; + + wine_tsx11_lock(); + xev.xclient.type = ClientMessage; + xev.xclient.window = data->whole_window; + xev.xclient.message_type = x11drv_atom(_WIN_HINTS); + xev.xclient.format = 32; + xev.xclient.serial = 0; + xev.xclient.display = display; + xev.xclient.send_event = True; + xev.xclient.data.l[0] = WIN_HINTS_SKIP_WINLIST | WIN_HINTS_SKIP_FOCUS | WIN_HINTS_SKIP_TASKBAR; + xev.xclient.data.l[1] = WIN_HINTS_SKIP_WINLIST | WIN_HINTS_SKIP_FOCUS | WIN_HINTS_SKIP_TASKBAR; + xev.xclient.data.l[2] = 0; + XSendEvent(thread_display(), root_window, False, SubstructureNotifyMask, &xev); + wine_tsx11_unlock(); + + return TRUE; + } + + return FALSE; +} + + +/*********************************************************************** * get_process_name * * get the name of the current process for setting class hints @@ -523,6 +683,9 @@ void X11DRV_set_wm_hints( Display *display, struct x11drv_win_data *data ) /* size hints */ set_size_hints( display, data, style ); + if (ex_style & WS_EX_TOOLWINDOW) + WM_RemoveFromTaskbar(display,data); + /* set the WM_CLIENT_MACHINE and WM_LOCALE_NAME properties */ XSetWMProperties(display, data->whole_window, NULL, NULL, NULL, 0, NULL, NULL, NULL); /* set the pid. together, these properties are needed so the window manager can kill us if we freeze */ @@ -532,8 +695,11 @@ void X11DRV_set_wm_hints( Display *display, struct x11drv_win_data *data ) /* set the WM_WINDOW_TYPE */ window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_NORMAL); +#ifndef __APPLE__ /* don't do that on Mac, quartz-wm keeps them always on top, and ignores mwm hints */ if (ex_style & WS_EX_TOOLWINDOW) window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_UTILITY); - else if (style & WS_THICKFRAME) window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_NORMAL); + else +#endif + if (style & WS_THICKFRAME) window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_NORMAL); else if (style & WS_DLGFRAME) window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_DIALOG); else if (ex_style & WS_EX_DLGMODALFRAME) window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_DIALOG); @@ -542,6 +708,11 @@ void X11DRV_set_wm_hints( Display *display, struct x11drv_win_data *data ) mwm_hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; mwm_hints.functions = MWM_FUNC_MOVE; + mwm_hints.decorations = 0; +#ifndef __APPLE__ + if (ex_style&WS_EX_TOOLWINDOW) + goto skip; +#endif if (style & WS_THICKFRAME) mwm_hints.functions |= MWM_FUNC_RESIZE; if (style & WS_MINIMIZEBOX) mwm_hints.functions |= MWM_FUNC_MINIMIZE; if (style & WS_MAXIMIZEBOX) mwm_hints.functions |= MWM_FUNC_MAXIMIZE; @@ -559,6 +730,7 @@ void X11DRV_set_wm_hints( Display *display, struct x11drv_win_data *data ) else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) mwm_hints.decorations |= MWM_DECOR_BORDER; else if (style & WS_BORDER) mwm_hints.decorations |= MWM_DECOR_BORDER; else if (!(style & (WS_CHILD|WS_POPUP))) mwm_hints.decorations |= MWM_DECOR_BORDER; +skip: XChangeProperty( display, data->whole_window, x11drv_atom(_MOTIF_WM_HINTS), x11drv_atom(_MOTIF_WM_HINTS), 32, PropModeReplace, @@ -643,6 +815,9 @@ void X11DRV_window_to_X_rect( struct x11drv_win_data *data, RECT *rect ) if (!data->managed) return; if (IsRectEmpty( rect )) return; +#ifndef __APPLE__ /* quartz-wm doesn't let us do tool windows properly */ + if (GetWindowLongW( data->hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW) return; +#endif rc.top = rc.bottom = rc.left = rc.right = 0; @@ -667,6 +842,9 @@ void X11DRV_X_to_window_rect( struct x11drv_win_data *data, RECT *rect ) { if (!data->managed) return; if (IsRectEmpty( rect )) return; +#ifndef __APPLE__ /* quartz-wm doesn't let us do tool windows properly */ + if (GetWindowLongW( data->hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW) return; +#endif AdjustWindowRectEx( rect, GetWindowLongW( data->hwnd, GWL_STYLE ) & ~(WS_HSCROLL|WS_VSCROLL), FALSE, GetWindowLongW( data->hwnd, GWL_EXSTYLE )); @@ -696,6 +874,7 @@ void X11DRV_sync_window_position( Display *display, struct x11drv_win_data *data OffsetRect( &data->client_rect, -data->whole_rect.left, -data->whole_rect.top ); if (!data->whole_window || data->lock_changes) return; + if (data->adopted) return; mask = get_window_changes( &changes, &old_whole_rect, &data->whole_rect ); @@ -737,6 +916,8 @@ void X11DRV_sync_window_position( Display *display, struct x11drv_win_data *data wine_tsx11_lock(); if (mask & (CWWidth|CWHeight)) set_size_hints( display, data, style ); + if ((mask & CWY) && data->managed && (style & WS_CAPTION) == WS_CAPTION) + changes.y -= applewm_title_height; if (mask & CWX) changes.x -= virtual_screen_rect.left; if (mask & CWY) changes.y -= virtual_screen_rect.top; XReconfigureWMWindow( display, data->whole_window, @@ -747,13 +928,29 @@ void X11DRV_sync_window_position( Display *display, struct x11drv_win_data *data /********************************************************************** + * needs_x_window + * + * Determine if a given window needs to have an associated X window. + * If so, return the X window of the parent to use. + */ +static inline Window needs_x_window( struct x11drv_win_data *data ) +{ + struct x11drv_win_data *parent_data; + + if (data->toplevel) return root_window; + if (!(parent_data = X11DRV_get_win_data( GetAncestor(data->hwnd, GA_PARENT) ))) return 0; + if (!parent_data->adopted) return 0; + return parent_data->whole_window; +} + +/********************************************************************** * create_whole_window * * Create the whole X window for a given window */ -static Window create_whole_window( Display *display, struct x11drv_win_data *data, DWORD style ) +static Window create_whole_window( Display *display, struct x11drv_win_data *data, Window parent, DWORD style ) { - int cx, cy, mask; + int cx, cy, top, mask; XSetWindowAttributes attr; XIM xim; RECT rect; @@ -778,9 +975,11 @@ static Window create_whole_window( Display *display, struct x11drv_win_data *dat wine_tsx11_lock(); data->whole_rect = rect; + top = rect.top; + if (data->managed && (style & WS_CAPTION) == WS_CAPTION) top -= applewm_title_height; data->whole_window = XCreateWindow( display, root_window, rect.left - virtual_screen_rect.left, - rect.top - virtual_screen_rect.top, + top - virtual_screen_rect.top, cx, cy, 0, screen_depth, InputOutput, visual, mask, &attr ); @@ -825,13 +1024,14 @@ static void destroy_whole_window( Display *display, struct x11drv_win_data *data if (thread_data->cursor_window == data->whole_window) thread_data->cursor_window = None; wine_tsx11_lock(); XDeleteContext( display, data->whole_window, winContext ); - if (data->whole_window != DefaultRootWindow(display)) + if (data->whole_window != DefaultRootWindow(display) && !data->adopted) XDestroyWindow( display, data->whole_window ); data->whole_window = 0; if (data->xic) { XUnsetICFocus( data->xic ); XDestroyIC( data->xic ); + data->xic = 0; } /* Outlook stops processing messages after destroying a dialog, so we need an explicit flush */ XFlush( display ); @@ -846,51 +1046,47 @@ static void destroy_whole_window( Display *display, struct x11drv_win_data *data void X11DRV_SetWindowText( HWND hwnd, LPCWSTR text ) { Display *display = thread_display(); + struct x11drv_win_data *data; UINT count; char *buffer; char *utf8_buffer; - Window win; XTextProperty prop; - if ((win = X11DRV_get_whole_window( hwnd )) && win != DefaultRootWindow(display)) - { - /* allocate new buffer for window text */ - count = WideCharToMultiByte(CP_UNIXCP, 0, text, -1, NULL, 0, NULL, NULL); - if (!(buffer = HeapAlloc( GetProcessHeap(), 0, count ))) - { - ERR("Not enough memory for window text\n"); - return; - } - WideCharToMultiByte(CP_UNIXCP, 0, text, -1, buffer, count, NULL, NULL); - - count = WideCharToMultiByte(CP_UTF8, 0, text, strlenW(text), NULL, 0, NULL, NULL); - if (!(utf8_buffer = HeapAlloc( GetProcessHeap(), 0, count ))) - { - ERR("Not enough memory for window text in UTF-8\n"); - HeapFree( GetProcessHeap(), 0, buffer ); - return; - } - WideCharToMultiByte(CP_UTF8, 0, text, strlenW(text), utf8_buffer, count, NULL, NULL); + if (!(data = X11DRV_get_win_data( hwnd ))) return; + if (!data->whole_window || !data->toplevel || data->adopted) return; + if (data->whole_window == DefaultRootWindow(display)) return; - wine_tsx11_lock(); - if (XmbTextListToTextProperty( display, &buffer, 1, XStdICCTextStyle, &prop ) == Success) - { - XSetWMName( display, win, &prop ); - XSetWMIconName( display, win, &prop ); - XFree( prop.value ); - } - /* - Implements a NET_WM UTF-8 title. It should be without a trailing \0, - according to the standard - ( http://www.pps.jussieu.fr/~jch/software/UTF8_STRING/UTF8_STRING.text ). - */ - XChangeProperty( display, win, x11drv_atom(_NET_WM_NAME), x11drv_atom(UTF8_STRING), - 8, PropModeReplace, (unsigned char *) utf8_buffer, count); - wine_tsx11_unlock(); + /* allocate new buffer for window text */ + count = WideCharToMultiByte(CP_UNIXCP, 0, text, -1, NULL, 0, NULL, NULL); + if (!(buffer = HeapAlloc( GetProcessHeap(), 0, count ))) return; + WideCharToMultiByte(CP_UNIXCP, 0, text, -1, buffer, count, NULL, NULL); - HeapFree( GetProcessHeap(), 0, utf8_buffer ); + count = WideCharToMultiByte(CP_UTF8, 0, text, strlenW(text), NULL, 0, NULL, NULL); + if (!(utf8_buffer = HeapAlloc( GetProcessHeap(), 0, count ))) + { HeapFree( GetProcessHeap(), 0, buffer ); + return; } + WideCharToMultiByte(CP_UTF8, 0, text, strlenW(text), utf8_buffer, count, NULL, NULL); + + wine_tsx11_lock(); + if (XmbTextListToTextProperty( display, &buffer, 1, XStdICCTextStyle, &prop ) == Success) + { + XSetWMName( display, data->whole_window, &prop ); + XSetWMIconName( display, data->whole_window, &prop ); + XFree( prop.value ); + } + /* + Implements a NET_WM UTF-8 title. It should be without a trailing \0, + according to the standard + ( http://www.pps.jussieu.fr/~jch/software/UTF8_STRING/UTF8_STRING.text ). + */ + XChangeProperty( display, data->whole_window, x11drv_atom(_NET_WM_NAME), x11drv_atom(UTF8_STRING), + 8, PropModeReplace, (unsigned char *) utf8_buffer, count); + wine_tsx11_unlock(); + + HeapFree( GetProcessHeap(), 0, utf8_buffer ); + HeapFree( GetProcessHeap(), 0, buffer ); } @@ -919,6 +1115,189 @@ void X11DRV_DestroyWindow( HWND hwnd ) } +static Window set_adopted_window_data( Display *display, struct x11drv_win_data *data, Window xwin ) +{ + Window old_win = data->whole_window; + + if (!data->adopted) old_win = 0; /* it will be destroyed */ + destroy_whole_window( display, data ); + data->whole_window = xwin; + data->adopted = TRUE; + + if (data->managed) + { + data->managed = FALSE; + RemovePropA( data->hwnd, managed_prop ); + } + + wine_tsx11_lock(); + XSelectInput( display, xwin, StructureNotifyMask ); + XSaveContext( display, data->whole_window, winContext, (char *)data->hwnd ); + wine_tsx11_unlock(); + SetPropA( data->hwnd, whole_window_prop, (HANDLE)data->whole_window ); + return old_win; +} + +LRESULT WINAPI PassiveAdoptedWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch(msg) + { + case WM_PARENTNOTIFY: + if (LOWORD(wparam) == WM_DESTROY) + { + TRACE("%p: got parent notify destroy for win %lx\n",hwnd,lparam); + PostMessageW( hwnd, WM_USER, 0, 0 ); /* so that we come back here once the child is gone */ + } + return 0; + case WM_USER: + /* check if we have any remaining children */ + if (!GetWindow( hwnd, GW_CHILD )) + { + TRACE("%p: no more children, time to die\n",hwnd); + DestroyWindow(hwnd); + } + return 0; + default: + return DefWindowProcW(hwnd,msg,wparam,lparam); + } +} + + +static HWND adopt_window(Display *display, Window xwin, HWND hParent, DWORD style) +{ + static const WCHAR classW[] = {'_','_','w','i','n','e','_','x','1','1','_','f','o','r','e','i','g','n','_','w','i','n','d','o','w',0}; + static const WCHAR emptyW[] = { 0 }; + static ATOM passiveAdoptedWindow; + HWND hwnd = 0; + + if (!passiveAdoptedWindow) + { + WNDCLASSW class; + class.style = 0; + class.lpfnWndProc = PassiveAdoptedWindowProc; + class.cbClsExtra = 0; + class.cbWndExtra = 0; + class.hInstance = 0; + class.hIcon = 0; + class.hCursor = 0; + class.hbrBackground = 0; + class.lpszMenuName = 0; + class.lpszClassName = classW; + passiveAdoptedWindow = RegisterClassW( &class ); + } + + if (passiveAdoptedWindow) + { + Window xroot; + int x, y; + unsigned int width, height, border, depth; + struct x11drv_win_data *data; + + /* adapt the size */ + wine_tsx11_lock(); + XGetGeometry(display, xwin, &xroot, &x, &y, &width, &height, &border, &depth ); + wine_tsx11_unlock(); + + hwnd = CreateWindowW( classW, emptyW, style, x, y, width, height, hParent, 0, 0, NULL); + + TRACE( "xwin %08lx hParent %p style %08x %d,%d %dx%d -> hwnd %p\n", + xwin, hParent, style, x, y, width, height, hwnd ); + + if (!(data = X11DRV_get_win_data( hwnd ))) return 0; + set_adopted_window_data( display, data, xwin ); + ShowWindow( hwnd, SW_SHOW ); /* FIXME: should check if X window is mapped */ + } + + return hwnd; +} + +/* adopt the specified window and all its ancestors */ +static HWND adopt_ancestors(Display *display, Window xwin) +{ + HWND hwnd, parent; + Window xparent, xroot; + Window *xchildren; + unsigned int nchildren; + DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; + + wine_tsx11_lock(); + if (XFindContext( display, xwin, winContext, (char **)&hwnd)) hwnd = 0; + + if (hwnd) wine_tsx11_unlock(); + else + { + if (!XQueryTree(display, xwin, &xroot, &xparent, &xchildren, &nchildren)) + { + wine_tsx11_unlock(); + return 0; + } + XFree(xchildren); + wine_tsx11_unlock(); + if (xparent == xroot) + { + parent = GetDesktopWindow(); + style |= WS_POPUP; + } + else + { + parent = adopt_ancestors( display, xparent ); + style |= WS_CHILD; + } + hwnd = adopt_window( display, xwin, parent, style ); + } + TRACE("returning 0x%08lx -> hwnd %p\n", xwin, hwnd); + return hwnd; +} + + +/************************************************************************ + * wine_x11_adopt_window (WINEX11.DRV.@) + * + * Adopt an external X window into the specified hwnd. + */ +BOOL wine_x11_adopt_window( HWND hwnd, Window xwin ) +{ + struct x11drv_win_data *data; + Display *display = thread_display(); + HWND old_parent, parent; + LONG style = GetWindowLongW( hwnd, GWL_STYLE ); + + if (!(data = X11DRV_get_win_data( hwnd ))) return FALSE; + + if (!(parent = adopt_ancestors( display, xwin ))) return FALSE; + + old_parent = SetParent( hwnd, parent ); + if (parent != GetDesktopWindow()) + SetWindowLongW( hwnd, GWL_STYLE, (style & ~WS_POPUP) | WS_CHILD ); + else + SetWindowLongW( hwnd, GWL_STYLE, (style & ~WS_CHILD) | WS_POPUP ); + + PostMessageW( old_parent, WM_USER, 0, 0 ); /* make old parent destroy itself if it no longer has children */ + + TRACE( "new window for %p %lx\n", hwnd, data->whole_window ); + + wine_tsx11_lock(); + XSync( display, False ); + wine_tsx11_unlock(); + return TRUE; +} + + +/************************************************************************ + * X11DRV_DestroyNotify + */ +void X11DRV_DestroyNotify( HWND hwnd, XEvent *event ) +{ + struct x11drv_win_data *data = X11DRV_get_win_data( hwnd ); + + if (data && data->adopted) + { + data->whole_window = 0; + data->adopted = FALSE; + } +} + + static struct x11drv_win_data *alloc_win_data( Display *display, HWND hwnd ) { struct x11drv_win_data *data; @@ -930,6 +1309,8 @@ static struct x11drv_win_data *alloc_win_data( Display *display, HWND hwnd ) data->icon_window = 0; data->xic = 0; data->managed = FALSE; + data->toplevel = FALSE; + data->adopted = FALSE; data->dce = NULL; data->lock_changes = 0; data->hWMIconBitmap = 0; @@ -1009,6 +1390,7 @@ BOOL X11DRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode ) { Display *display = thread_display(); WND *wndPtr; + Window parent; struct x11drv_win_data *data; HWND insert_after; RECT rect; @@ -1044,10 +1426,12 @@ BOOL X11DRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode ) SetRect( &rect, cs->x, cs->y, cs->x + cs->cx, cs->y + cs->cy ); X11DRV_SetWindowPos( hwnd, 0, &rect, &rect, SWP_NOZORDER, NULL ); - /* create an X window if it's a top level window */ - if (GetAncestor( hwnd, GA_PARENT ) == GetDesktopWindow()) + /* create an X window if needed */ + data->toplevel = (GetAncestor( hwnd, GA_PARENT ) == GetDesktopWindow()); + parent = needs_x_window( data ); + if (parent) { - if (!create_whole_window( display, data, cs->style )) goto failed; + if (!create_whole_window( display, data, parent, cs->style )) goto failed; } else if (hwnd == GetDesktopWindow()) { @@ -1078,10 +1462,15 @@ BOOL X11DRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode ) if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD))) { POINT maxSize, maxPos, minTrack, maxTrack; - /* Although Windows sends WM_GETMINMAXINFO at the window creation time, - * it doesn't use returned values to set window size. - */ + WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack); + if (maxTrack.x < cs->cx) cs->cx = maxTrack.x; + if (maxTrack.y < cs->cy) cs->cy = maxTrack.y; + if (cs->cx < 0) cs->cx = 0; + if (cs->cy < 0) cs->cy = 0; + + SetRect( &rect, cs->x, cs->y, cs->x + cs->cx, cs->y + cs->cy ); + if (!X11DRV_SetWindowPos( hwnd, 0, &rect, &rect, SWP_NOZORDER, NULL )) return FALSE; } /* send WM_NCCREATE */ @@ -1232,28 +1621,38 @@ void X11DRV_SetParent( HWND hwnd, HWND parent, HWND old_parent ) { Display *display = thread_display(); struct x11drv_win_data *data = X11DRV_get_win_data( hwnd ); + Window x_parent; if (!data) return; if (parent == old_parent) return; - if (parent != GetDesktopWindow()) /* a child window */ + data->toplevel = (parent == GetDesktopWindow()); + if (!data->toplevel) { - if (old_parent == GetDesktopWindow()) + destroy_icon_window( display, data ); + if (data->managed) { - /* destroy the old X windows */ - destroy_whole_window( display, data ); - destroy_icon_window( display, data ); - if (data->managed) - { - data->managed = FALSE; - RemovePropA( data->hwnd, managed_prop ); - } + data->managed = FALSE; + RemovePropA( data->hwnd, managed_prop ); } } - else /* new top level window */ + + if ((x_parent = needs_x_window( data ))) + { + if (data->whole_window) + { + /* already have an X window, reparent it */ + wine_tsx11_lock(); + XReparentWindow( display, data->whole_window, x_parent, data->whole_rect.left, data->whole_rect.top ); + wine_tsx11_unlock(); + } + else /* FIXME: we ignore errors since we can't really recover anyway */ + create_whole_window( display, data, x_parent, GetWindowLongW( hwnd, GWL_STYLE ) ); + } + else { - /* FIXME: we ignore errors since we can't really recover anyway */ - create_whole_window( display, data, GetWindowLongW( hwnd, GWL_STYLE ) ); + /* destroy the old X window */ + destroy_whole_window( display, data ); } } diff --git a/dlls/winex11.drv/winex11.drv.spec b/dlls/winex11.drv/winex11.drv.spec index 6a6c17355a1..2dec7d17cd4 100644 --- a/dlls/winex11.drv/winex11.drv.spec +++ b/dlls/winex11.drv/winex11.drv.spec @@ -115,6 +115,9 @@ @ cdecl WindowFromDC(long) X11DRV_WindowFromDC @ cdecl WindowMessage(long long long long) X11DRV_WindowMessage +# Adopted X windows +@ cdecl wine_x11_adopt_window(long long) + # WinTab32 @ cdecl AttachEventQueueToTablet(long) X11DRV_AttachEventQueueToTablet @ cdecl GetCurrentPacket(ptr) X11DRV_GetCurrentPacket diff --git a/dlls/winex11.drv/winpos.c b/dlls/winex11.drv/winpos.c index e41b11fb149..387c49eac2a 100644 --- a/dlls/winex11.drv/winpos.c +++ b/dlls/winex11.drv/winpos.c @@ -108,16 +108,19 @@ void X11DRV_Expose( HWND hwnd, XEvent *xev ) rect.right > data->client_rect.right || rect.bottom > data->client_rect.bottom) flags |= RDW_FRAME; - SERVER_START_REQ( update_window_zorder ) + if (data->toplevel) { - req->window = hwnd; - req->rect.left = rect.left + data->whole_rect.left; - req->rect.top = rect.top + data->whole_rect.top; - req->rect.right = rect.right + data->whole_rect.left; - req->rect.bottom = rect.bottom + data->whole_rect.top; - wine_server_call( req ); + SERVER_START_REQ( update_window_zorder ) + { + req->window = hwnd; + req->rect.left = rect.left + data->whole_rect.left; + req->rect.top = rect.top + data->whole_rect.top; + req->rect.right = rect.right + data->whole_rect.left; + req->rect.bottom = rect.bottom + data->whole_rect.top; + wine_server_call( req ); + } + SERVER_END_REQ; } - SERVER_END_REQ; /* make position relative to client area instead of window */ OffsetRect( &rect, -data->client_rect.left, -data->client_rect.top ); @@ -145,7 +148,7 @@ void X11DRV_SetWindowStyle( HWND hwnd, DWORD old_style ) { if (data->whole_window && X11DRV_is_window_rect_mapped( &data->window_rect )) { - if (new_style & WS_VISIBLE) + if (new_style & WS_VISIBLE && !(new_style & WS_MINIMIZE )) { TRACE( "mapping win %p\n", hwnd ); X11DRV_sync_window_style( display, data ); @@ -158,6 +161,11 @@ void X11DRV_SetWindowStyle( HWND hwnd, DWORD old_style ) } invalidate_dce( hwnd, &data->window_rect ); } + else if (changed & WS_CAPTION) + { + if (data->whole_window && (new_style & WS_VISIBLE)) + X11DRV_set_wm_hints( display, data ); + } if (changed & WS_DISABLED) { @@ -348,7 +356,7 @@ BOOL X11DRV_SetWindowPos( HWND hwnd, HWND insert_after, const RECT *rectWindow, } - if (data->whole_window && !data->lock_changes) + if (data->whole_window && !data->lock_changes && !data->adopted) { if ((old_style & WS_VISIBLE) && !(new_style & WS_VISIBLE)) { @@ -370,7 +378,7 @@ BOOL X11DRV_SetWindowPos( HWND hwnd, HWND insert_after, const RECT *rectWindow, X11DRV_sync_window_position( display, data, swp_flags, rectClient, &new_whole_rect ); - if (data->whole_window && !data->lock_changes) + if (data->whole_window && !data->lock_changes && !data->adopted) { BOOL new_fs_state, mapped = FALSE; @@ -587,20 +595,142 @@ UINT WINPOS_MinMaximize( HWND hwnd, UINT cmd, LPRECT rect ) /*********************************************************************** + * X11DRV_WMMaximizeWindow + * + * Ask X to Maximize the window + * assume win lock is held + */ +static BOOL X11DRV_WMMaximizeWindow(HWND hwnd, BOOL max) +{ + Window win = X11DRV_get_whole_window( hwnd ); + TRACE("%p max=%s\n", hwnd, max?"TRUE":"FALSE"); + + /* GNOME style */ + if(WM_has_win_state) + { + XEvent xev; + + wine_tsx11_lock(); + xev.xclient.type = ClientMessage; + xev.xclient.window = win; + xev.xclient.message_type = x11drv_atom(_WIN_STATE); + xev.xclient.format = 32; + xev.xclient.serial = 0; + xev.xclient.display = thread_display(); + xev.xclient.send_event = True; + xev.xclient.data.l[0] = WIN_STATE_MAXIMIZED_VERT | WIN_STATE_MAXIMIZED_HORIZ; + xev.xclient.data.l[1] = 0; + if(max) + xev.xclient.data.l[1] = WIN_STATE_MAXIMIZED_VERT | WIN_STATE_MAXIMIZED_HORIZ; + XSendEvent(thread_display(), root_window, False, SubstructureNotifyMask, &xev); + wine_tsx11_unlock(); + + return TRUE; + } + + /* KDE 2 style */ + if(WM_has_net_wm_state) + { + XEvent xev; + + wine_tsx11_lock(); + xev.xclient.type = ClientMessage; + xev.xclient.window = win; + xev.xclient.message_type = x11drv_atom(_NET_WM_STATE); + xev.xclient.serial = 0; + xev.xclient.display = thread_display(); + xev.xclient.send_event = True; + xev.xclient.format = 32; + if(max) + xev.xclient.data.l[0] = _NET_WM_STATE_ADD; + else + xev.xclient.data.l[0] = _NET_WM_STATE_REMOVE; + xev.xclient.data.l[1] = x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ); + xev.xclient.data.l[2] = x11drv_atom(_NET_WM_STATE_MAXIMIZED_VERT); + XSendEvent(thread_display(), root_window, False, SubstructureNotifyMask, &xev); + wine_tsx11_unlock(); + + return TRUE; + } + + /* KDE 1 style */ + if(x11drv_atom(KWM_MAXIMIZE_WINDOW)!=None) + { + wine_tsx11_lock(); + XChangeProperty( thread_display(), win, x11drv_atom(KWM_MAXIMIZE_WINDOW), + x11drv_atom(KWM_MAXIMIZE_WINDOW), 8, PropModeReplace, (unsigned char*)&max, 1 ); + wine_tsx11_unlock(); + return TRUE; + } + + return FALSE; +} + + +/*********************************************************************** + * X11DRV_WMMinimizeWindow + * + * See the ICCCM section 4.1.4. Changing Window State for more details. + * http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.4 + */ +static BOOL X11DRV_WMMinimizeWindow(HWND hwnd) +{ + XEvent xev; + + TRACE("%p\n", hwnd); + + wine_tsx11_lock(); + + xev.xclient.type = ClientMessage; + xev.xclient.window = X11DRV_get_whole_window( hwnd ); + xev.xclient.message_type = x11drv_atom(WM_CHANGE_STATE); + xev.xclient.serial = 0; + xev.xclient.display = thread_display(); + xev.xclient.send_event = True; + xev.xclient.format = 32; + xev.xclient.data.l[0] = IconicState; + xev.xclient.data.l[2] = 0; + XSendEvent(thread_display(), root_window, False, SubstructureNotifyMask, &xev); + + wine_tsx11_unlock(); + + return TRUE; +} + + +/*********************************************************************** * ShowWindow (X11DRV.@) */ BOOL X11DRV_ShowWindow( HWND hwnd, INT cmd ) { + Display *display = thread_display(); WND *wndPtr; HWND parent; LONG style = GetWindowLongW( hwnd, GWL_STYLE ); BOOL wasVisible = (style & WS_VISIBLE) != 0; BOOL showFlag = TRUE; + BOOL sendWmMaximize, maximize; RECT newPos = {0, 0, 0, 0}; UINT swp = 0; TRACE("hwnd=%p, cmd=%d, wasVisible %d\n", hwnd, cmd, wasVisible); + /* check if we should request an action from the window manager */ + sendWmMaximize = FALSE; + maximize = FALSE; + if(WM_has_win_state || WM_has_net_wm_state || (x11drv_atom(KWM_RUNNING)!=None) ) + { + if ((root_window == DefaultRootWindow(display)) && + GetAncestor(hwnd,GA_PARENT) == GetDesktopWindow()) + { + if (cmd == SW_MAXIMIZE) + { + sendWmMaximize = TRUE; + maximize = TRUE; + } + } + } + switch(cmd) { case SW_HIDE: @@ -614,14 +744,27 @@ BOOL X11DRV_ShowWindow( HWND hwnd, INT cmd ) case SW_SHOWMINNOACTIVE: swp |= SWP_NOACTIVATE | SWP_NOZORDER; /* fall through */ - case SW_MINIMIZE: case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */ if (style & WS_CHILD) swp |= SWP_NOACTIVATE | SWP_NOZORDER; /* fall through */ - case SW_SHOWMINIMIZED: - swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED; - swp |= WINPOS_MinMaximize( hwnd, cmd, &newPos ); - if ((style & WS_MINIMIZE) && wasVisible) return TRUE; + case SW_MINIMIZE: + + /* handle minimize a different way */ + if ((root_window == DefaultRootWindow(display)) && + GetAncestor(hwnd,GA_PARENT) == GetDesktopWindow()) + { + if( !(style & WS_MINIMIZE) ) + { + X11DRV_WMMinimizeWindow( hwnd ); + WIN_SetStyle( hwnd, WS_MINIMIZE, WS_MAXIMIZE ); + } + return wasVisible; + } + + swp |= SWP_FRAMECHANGED; + if( !(style & WS_MINIMIZE) ) + swp |= WINPOS_MinMaximize( hwnd, SW_MINIMIZE, &newPos ); + else swp |= SWP_NOSIZE | SWP_NOMOVE; break; case SW_SHOWMAXIMIZED: /* same as SW_MAXIMIZE */ @@ -637,6 +780,14 @@ BOOL X11DRV_ShowWindow( HWND hwnd, INT cmd ) break; case SW_SHOW: if (wasVisible) return TRUE; + + if (getenv("CX_HACK_JINITIATOR")) /* Hide Java Console */ + { + CHAR buf[16]; + + if (GetWindowTextA(hwnd, buf, 16) && !strcmp(buf, "Java Console")) + return FALSE; + } swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE; if (style & WS_CHILD) swp |= SWP_NOACTIVATE | SWP_NOZORDER; break; @@ -723,6 +874,10 @@ BOOL X11DRV_ShowWindow( HWND hwnd, INT cmd ) } else WIN_ReleasePtr( wndPtr ); + /* ask the window manager to maximize this window for us */ + if( sendWmMaximize ) + X11DRV_WMMaximizeWindow(hwnd, maximize); + /* if previous state was minimized Windows sets focus to the window */ if (style & WS_MINIMIZE) SetFocus( hwnd ); @@ -885,6 +1040,109 @@ void X11DRV_handle_desktop_resize( unsigned int width, unsigned int height ) /*********************************************************************** + * X11DRV_GetXWMWindowState + * + * Check whether the X Window Manager thinks the window is maximized + * + * return TRUE if the check was possible + */ +static BOOL X11DRV_GetXWMWindowState(Display* d, Window w, BOOL *maximized) +{ + int r; + unsigned long left = 0, ret_length = 0; + int ret_format = 0; + Atom ret_atom = None; + + /* GNOME style _WIN_STATE */ + if( WM_has_win_state ) + { + unsigned char *data = NULL; + + wine_tsx11_lock(); + + r = XGetWindowProperty( d, w, x11drv_atom(_WIN_STATE), 0L, 1, False, AnyPropertyType, + &ret_atom, &ret_format, &ret_length, &left, &data); + if(r==Success) + { + if(ret_atom!=None) + { + TRACE("_win_state=%d\n", *data); + if( (*data & WIN_STATE_MAXIMIZED_VERT) && + (*data & WIN_STATE_MAXIMIZED_HORIZ) ) + *maximized = TRUE; + else + *maximized = FALSE; + } + XFree(data); + } + + wine_tsx11_unlock(); + + return ((r==Success) && (ret_atom!=None)); + } + + /* KDE 2 style _NET_WM_STATE */ + if( WM_has_net_wm_state ) + { + long *data = NULL; + int i, vert_max = 0, horz_max = 0; + + wine_tsx11_lock(); + r = XGetWindowProperty( + d, w, x11drv_atom(_NET_WM_STATE), 0L, 10L, False, AnyPropertyType, + &ret_atom, &ret_format, &ret_length, &left, (unsigned char **)&data); + if(r==Success) + { + if(ret_atom!=None) + { + for(i=0; ix, y = event->y; + BOOL max = FALSE; + HWND parent; + RECT ignore; /* suggested restore/maximize size */ if (!hwnd) return; if (!(data = X11DRV_get_win_data( hwnd ))) return; + parent = GetAncestor( hwnd, GA_PARENT ); /* Get geometry */ - if (!event->send_event) /* normal event, need to map coordinates to the root */ + if (!event->send_event && data->toplevel) { + /* normal event, need to map coordinates to the root */ Window child; wine_tsx11_lock(); XTranslateCoordinates( event->display, data->whole_window, root_window, 0, 0, &x, &y, &child ); wine_tsx11_unlock(); } + + /* HACK: find out the real window position... if it doesn't match ignore the ConfigureNotify */ + if (data->toplevel) + { + Window ignore_root; + int ignore_x, ignore_y; + unsigned int height, width, ignore_depth, ignore_border; + + wine_tsx11_lock(); + XGetGeometry(event->display, data->whole_window, &ignore_root, + &ignore_x, &ignore_y, &width, &height, &ignore_border, &ignore_depth); + wine_tsx11_unlock(); + + if ( (width!=event->width) || (height!=event->height ) ) + { + TRACE("Discarding old ConfigureNotify message for hwnd %p\n",hwnd); + return; + } + } + rect.left = x; rect.top = y; rect.right = x + event->width; rect.bottom = y + event->height; - OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top ); - TRACE( "win %p new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n", + if (event->send_event || data->toplevel) + OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top ); + TRACE( "win %p new X rect %d,%d,%dx%d (event %d,%d,%dx%d) send=%d\n", hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, - event->x, event->y, event->width, event->height ); + event->x, event->y, event->width, event->height, event->send_event); X11DRV_X_to_window_rect( data, &rect ); + if (event->send_event || data->toplevel) MapWindowPoints( 0, parent, (POINT *)&rect, 2 ); + + /* where possible, this code attempts to synchronize the window manager's + Maximized state with wine's internal one */ + if(X11DRV_GetXWMWindowState(event->display, data->whole_window, &max)) + { + TRACE("xmax %d zoomed %d\n", max, IsZoomed(hwnd)); + + if( IsZoomed(hwnd) && !max ) + WINPOS_MinMaximize( hwnd, SW_RESTORE, &ignore ); + else if( max && !IsZoomed(hwnd) ) + WINPOS_MinMaximize( hwnd, SW_MAXIMIZE, &ignore ); + + TRACE("xmax %d zoomed %d\n", max, IsZoomed(hwnd)); + } + else + { + /* don't allow maximized state if we can't detect it! */ + if (IsZoomed(hwnd) && GetPropA( hwnd, "__wine_x11_managed" )) + WINPOS_MinMaximize( hwnd, SW_RESTORE, &ignore ); + } x = rect.left; y = rect.top; @@ -927,6 +1232,7 @@ void X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) /* Compare what has changed */ GetWindowRect( hwnd, &rect ); + MapWindowPoints( 0, parent, (POINT *)&rect, 2 ); if (rect.left == x && rect.top == y) flags |= SWP_NOMOVE; else TRACE( "%p moving from (%d,%d) to (%d,%d)\n", diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 4053c2f6fcd..effacf25ab2 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -259,6 +259,9 @@ extern int client_side_with_render; extern int client_side_antialias_with_core; extern int client_side_antialias_with_render; extern int using_client_side_fonts; +extern BOOL ignore_gasp; +extern BOOL dont_aa_chinese; + extern void X11DRV_XRender_Init(void); extern void X11DRV_XRender_Finalize(void); extern BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE*, HFONT); @@ -536,7 +539,13 @@ extern int private_color_map; extern int primary_monitor; extern int copy_default_colors; extern int alloc_system_colors; +extern int dxgrab, usedga, usexvidmode; extern int xrender_error_base; +extern int forcealtrelease; +extern BOOL WM_has_win_state; +extern BOOL WM_has_net_wm_state; +extern int applewm_title_height; +extern int find_offscreen_formats; extern BYTE key_state_table[256]; extern POINT cursor_pos; @@ -559,6 +568,7 @@ enum x11drv_atoms XATOM_WM_PROTOCOLS, XATOM_WM_DELETE_WINDOW, XATOM_WM_TAKE_FOCUS, + XATOM_WM_CHANGE_STATE, XATOM_KWM_DOCKWINDOW, XATOM_DndProtocol, XATOM_DndSelection, @@ -572,10 +582,15 @@ enum x11drv_atoms XATOM__NET_WM_PING, XATOM__NET_WM_STATE, XATOM__NET_WM_STATE_FULLSCREEN, + XATOM__NET_WM_STATE_MAXIMIZED_HORZ, + XATOM__NET_WM_STATE_MAXIMIZED_VERT, + XATOM__NET_WM_STATE_SKIP_PAGER, + XATOM__NET_WM_STATE_SKIP_TASKBAR, XATOM__NET_WM_WINDOW_TYPE, XATOM__NET_WM_WINDOW_TYPE_DIALOG, XATOM__NET_WM_WINDOW_TYPE_NORMAL, XATOM__NET_WM_WINDOW_TYPE_UTILITY, + XATOM__WIN_HINTS, XATOM__XEMBED_INFO, XATOM_XdndAware, XATOM_XdndEnter, @@ -598,6 +613,15 @@ enum x11drv_atoms XATOM_text_plain, XATOM_text_rtf, XATOM_text_richtext, + + /* the following are only created if they already exist */ + FIRST_IF_EXISTS_XATOM, + XATOM_KWM_WIN_MAXIMIZED = FIRST_IF_EXISTS_XATOM, + XATOM_KWM_MAXIMIZE_WINDOW, + XATOM_KWM_RUNNING, + XATOM__NET_SUPPORTED, + XATOM__WIN_PROTOCOLS, + XATOM__WIN_STATE, NB_XATOMS }; @@ -605,6 +629,29 @@ extern Atom X11DRV_Atoms[NB_XATOMS - FIRST_XATOM]; #define x11drv_atom(name) (X11DRV_Atoms[XATOM_##name - FIRST_XATOM]) +/* see http://developer.gnome.org/doc/standards/wm/book1.html */ +#define WIN_STATE_STICKY (1<<0) +#define WIN_STATE_MINIMIZED (1<<1) +#define WIN_STATE_MAXIMIZED_VERT (1<<2) +#define WIN_STATE_MAXIMIZED_HORIZ (1<<3) +#define WIN_STATE_HIDDEN (1<<4) +#define WIN_STATE_SHADED (1<<5) +#define WIN_STATE_HID_WORKSPACE (1<<6) +#define WIN_STATE_HID_TRANSIENT (1<<7) +#define WIN_STATE_FIXED_POSITION (1<<8) +#define WIN_STATE_ARRANGE_IGNORE (1<<9) + +#define WIN_HINTS_SKIP_FOCUS (1<<0) +#define WIN_HINTS_SKIP_WINLIST (1<<1) +#define WIN_HINTS_SKIP_TASKBAR (1<<2) +#define WIN_HINTS_GROUP_TRANSIENT (1<<3) +#define WIN_HINTS_FOCUS_ON_CLICK (1<<3) + +/* see http://www.freedesktop.org/standards/wm-spec/ */ +#define _NET_WM_STATE_REMOVE 0 +#define _NET_WM_STATE_ADD 1 +#define _NET_WM_STATE_TOGGLE 2 + /* X11 event driver */ typedef void (*x11drv_event_handler)( HWND hwnd, XEvent *event ); @@ -620,6 +667,7 @@ extern void X11DRV_KeymapNotify( HWND hwnd, XEvent *event ); extern void X11DRV_Expose( HWND hwnd, XEvent *event ); extern void X11DRV_MapNotify( HWND hwnd, XEvent *event ); extern void X11DRV_UnmapNotify( HWND hwnd, XEvent *event ); +extern void X11DRV_DestroyNotify( HWND hwnd, XEvent *event ); extern void X11DRV_ConfigureNotify( HWND hwnd, XEvent *event ); extern void X11DRV_SelectionRequest( HWND hWnd, XEvent *event ); extern void X11DRV_SelectionClear( HWND hWnd, XEvent *event ); @@ -644,7 +692,9 @@ struct x11drv_win_data RECT whole_rect; /* X window rectangle for the whole window relative to parent */ RECT client_rect; /* client area relative to whole window */ XIC xic; /* X input context */ - BOOL managed; /* is window managed? */ + BOOL managed : 1; /* is window managed? */ + BOOL toplevel : 1; /* is it a top-level window? */ + BOOL adopted : 1; /* is it a window adopted from another process? */ struct dce *dce; /* DCE for CS_OWNDC or CS_CLASSDC windows */ unsigned int lock_changes; /* lock count for X11 change requests */ HBITMAP hWMIconBitmap; @@ -693,6 +743,15 @@ extern BOOL X11DRV_SetWindowPos( HWND hwnd, HWND insert_after, const RECT *rectW extern void X11DRV_set_wm_hints( Display *display, struct x11drv_win_data *data ); extern void xinerama_init(void); +extern void X11DRV_handle_desktop_resize(unsigned int width, unsigned int height); +extern void xinerama_init(void); + +extern int X11DRV_ProcessTabletEvent(HWND hwnd, XEvent *event); + +extern INT X11DRV_DIB_MaskToShift(DWORD mask); + +extern UINT WINPOS_MinMaximize( HWND hwnd, UINT cmd, LPRECT rect ); + extern void X11DRV_init_desktop( Window win, unsigned int width, unsigned int height ); extern void X11DRV_handle_desktop_resize(unsigned int width, unsigned int height); extern void X11DRV_Settings_AddDepthModes(void); diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 078a514355e..08d6461cd57 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -40,6 +40,9 @@ #ifdef HAVE_X11_EXTENSIONS_XRENDER_H #include #endif +#ifdef HAVE_X11_EXTENSIONS_APPLEWM_H +#include +#endif #include "windef.h" #include "winbase.h" @@ -73,6 +76,7 @@ RECT virtual_screen_rect; Window root_window; int dxgrab = 0; int usexvidmode = 1; +int forcealtrelease = 0; int usexrandr = 1; int use_xkb = 1; int use_take_focus = 1; @@ -84,10 +88,16 @@ int client_side_with_core = 1; int client_side_with_render = 1; int client_side_antialias_with_core = 1; int client_side_antialias_with_render = 1; +BOOL ignore_gasp = FALSE; +BOOL dont_aa_chinese = FALSE; int copy_default_colors = 128; int alloc_system_colors = 256; DWORD thread_data_tls_index = TLS_OUT_OF_INDEXES; int xrender_error_base = 0; +int applewm_event_base = 0; +int applewm_error_base = 0; +int applewm_title_height = 0; +int find_offscreen_formats = 0; static x11drv_error_callback err_callback; /* current callback for error */ static Display *err_callback_display; /* display callback is set for */ @@ -120,6 +130,7 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = "WM_PROTOCOLS", "WM_DELETE_WINDOW", "WM_TAKE_FOCUS", + "WM_CHANGE_STATE", "KWM_DOCKWINDOW", "DndProtocol", "DndSelection", @@ -133,10 +144,15 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = "_NET_WM_PING", "_NET_WM_STATE", "_NET_WM_STATE_FULLSCREEN", + "_NET_WM_STATE_MAXIMIZED_HORZ", + "_NET_WM_STATE_MAXIMIZED_VERT", + "_NET_WM_STATE_SKIP_PAGER", + "_NET_WM_STATE_SKIP_TASKBAR", "_NET_WM_WINDOW_TYPE", "_NET_WM_WINDOW_TYPE_DIALOG", "_NET_WM_WINDOW_TYPE_NORMAL", "_NET_WM_WINDOW_TYPE_UTILITY", + "_WIN_HINTS", "_XEMBED_INFO", "XdndAware", "XdndEnter", @@ -158,9 +174,17 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = "text/html", "text/plain", "text/rtf", - "text/richtext" + "text/richtext", + /* the following are only created if they already exist */ + "KWM_WIN_MAXIMIZED", + "KWM_MAXIMIZE_WINDOW", + "KWM_RUNNING", + "_NET_SUPPORTED", + "_WIN_PROTOCOLS", + "_WIN_STATE" }; + /*********************************************************************** * ignore_error * @@ -242,13 +266,16 @@ static int error_handler( Display *display, XErrorEvent *error_evt ) error_evt->error_code, error_evt->request_code ); return 0; } + ERR("XERROR: code %d request %d minor %d xid %08lx\n", + error_evt->error_code, + error_evt->request_code, + error_evt->minor_code, + error_evt->resourceid); if (TRACE_ON(synchronous)) { - ERR( "X protocol error: serial=%ld, request_code=%d - breaking into debugger\n", - error_evt->serial, error_evt->request_code ); DebugBreak(); /* force an entry in the debugger */ + old_error_handler( display, error_evt ); } - old_error_handler( display, error_evt ); return 0; } @@ -321,6 +348,10 @@ static void setup_options(void) if (!get_config_key( hkey, appkey, "DXGrab", buffer, sizeof(buffer) )) dxgrab = IS_OPTION_TRUE( buffer[0] ); + if (!get_config_key( hkey, appkey, "OffscreenFormat", buffer, sizeof(buffer) )) { + find_offscreen_formats = atoi( buffer ); + } + if (!get_config_key( hkey, appkey, "UseXVidMode", buffer, sizeof(buffer) )) usexvidmode = IS_OPTION_TRUE( buffer[0] ); @@ -349,6 +380,12 @@ static void setup_options(void) if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithRender", buffer, sizeof(buffer) )) client_side_antialias_with_render = IS_OPTION_TRUE( buffer[0] ); + if (!get_config_key( hkey, appkey, "IgnoreGasp", buffer, sizeof(buffer) )) + ignore_gasp = IS_OPTION_TRUE( buffer[0] ); + + if (!get_config_key( hkey, appkey, "DontAntiAliasChinese", buffer, sizeof(buffer) )) + dont_aa_chinese = IS_OPTION_TRUE( buffer[0] ); + if (!get_config_key( hkey, appkey, "UseXIM", buffer, sizeof(buffer) )) use_xim = IS_OPTION_TRUE( buffer[0] ); @@ -366,11 +403,49 @@ static void setup_options(void) get_config_key( hkey, appkey, "InputStyle", input_style, sizeof(input_style) ); + if (!get_config_key( hkey, appkey, "ForceAltRelease", buffer, sizeof(buffer) )) + forcealtrelease = IS_OPTION_TRUE( buffer[0] ); + if (appkey) RegCloseKey( appkey ); if (hkey) RegCloseKey( hkey ); } +/********************************************************************** + * check_WM_protocols + * + * check if the window manager supports GNOME's _WIN_STATE protocol + */ +static BOOL check_WM_protocol(Display *display, Atom proto_list, Atom proto) +{ + unsigned long r_items=0, r_remaining=0; + Atom r_type=None; + Atom *data=NULL; + int r_format=0, r, i; + + if ( (proto_list == None) || (proto == None) ) + return FALSE; + + r = XGetWindowProperty(display, root_window, proto_list, 0L, 100L, False, XA_ATOM, + &r_type, &r_format, &r_items, &r_remaining, (unsigned char**)&data); + if(r!=Success) + return FALSE; + + if(r_type==XA_ATOM) + { + for(i=0; i= 4.2 + ** In the mean time, we do a total kludge to attempt to address this: + ** we call it twice, and pray that the second time it is + ** initialized (and nudge the stack while we're at it). + ** If it doesn't, we just bail. + ** JPW 02/12/02 + **------------------------------------------------------------------*/ + if(!screen_format) { + WARN("XRenderFindVisualFormat failed; likely XFree bug. Retrying with stack kludge.\n"); + stack_kludge(); + screen_format = pXRenderFindVisualFormat(gdi_display, visual); + } if(!screen_format) { /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */ @@ -220,10 +252,7 @@ LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform) if(!screen_format) /* This fails in buggy versions of libXrender.so */ { wine_tsx11_unlock(); - WINE_MESSAGE( - "Wine has detected that you probably have a buggy version\n" - "of libXrender.so . Because of this client side font rendering\n" - "will be disabled. Please upgrade this library.\n"); + ERR("Your version of X has a buggy XRender extension (need >= 4.2). Disabling XRENDER.\n"); X11DRV_XRender_Installed = FALSE; return; } @@ -485,10 +514,31 @@ static int GetCacheEntry(X11DRV_PDEVICE *physDev, LFANDSIZE *plfsz) GetRasterizerCaps(&status, sizeof(status)); hinter = status.wFlags & WINE_TT_HINTER_ENABLED; } - if(!hinter || !get_gasp_flags(physDev, &flags) || flags & GASP_DOGRAY) + if(!hinter || ignore_gasp || !get_gasp_flags(physDev, &flags) || flags & GASP_DOGRAY) entry->aa_default = AA_Grey; else entry->aa_default = AA_None; + + if(dont_aa_chinese) + { + DWORD size = GetFontData(physDev->hdc, MS_OS2_TAG, 0, NULL, 0); + if(size != GDI_ERROR) + { + WORD *os2 = HeapAlloc(GetProcessHeap(), 0, size); + DWORD csb0; + + GetFontData(physDev->hdc, MS_OS2_TAG, 0, os2, size); + if(get_be_word(*os2) >= 1) + { + csb0 = get_be_word(*(os2 + 0x27)) << 16; + csb0 |= get_be_word(*(os2 + 0x28)); + TRACE("csb0 = %08x\n", csb0); + if(csb0 & 0x00140000) + entry->aa_default = AA_None; + } + HeapFree(GetProcessHeap(), 0, os2); + } + } } else entry->aa_default = AA_None; @@ -595,8 +645,8 @@ void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev) if(physDev->xrender->pict) { - TRACE("freeing pict = %lx dc = %p\n", physDev->xrender->pict, physDev->hdc); - XFlush(gdi_display); + TRACE("freeing pict %08lx from dc %p drawable %08lx\n", physDev->xrender->pict, + physDev->hdc, physDev->drawable); pXRenderFreePicture(gdi_display, physDev->xrender->pict); physDev->xrender->pict = 0; } @@ -740,6 +790,11 @@ static BOOL UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format) buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen); + if(!buf) + { + ERR("HeapAlloc of %d bytes failed\n",buflen); + return FALSE; + } GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, NULL); formatEntry->realized[glyph] = TRUE; @@ -1388,6 +1443,17 @@ BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flag if(image_w <= 0 || image_h <= 0) goto no_image; + image = NULL; + if(GetBkMode(hdc) != TRANSPARENT && lf.lfEscapement == 0) { + /* We don't need a XGetImage in this case as we know the bkgnd colour + already. We could also include ETO_OPAQUE here if we know that the + rectangle is larger than the text extents */ + image = XCreateImage(gdi_display, visual, physDev->depth, ZPixmap, 0, NULL, + image_w, image_h, 32, 0); + image->data = calloc(image_h, image->bytes_per_line); + XAddPixel(image, backgroundPixel); + if(image) goto got_image; + } X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL); image = XGetImage(gdi_display, physDev->drawable, image_x, image_y, image_w, image_h, @@ -1417,6 +1483,7 @@ BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flag } if(!image) goto no_image; + got_image: image->red_mask = visual->red_mask; image->green_mask = visual->green_mask; image->blue_mask = visual->blue_mask; diff --git a/dlls/wininet/Makefile.in b/dlls/wininet/Makefile.in index 3f34b714ecd..4d0494e5146 100644 --- a/dlls/wininet/Makefile.in +++ b/dlls/wininet/Makefile.in @@ -6,7 +6,7 @@ VPATH = @srcdir@ MODULE = wininet.dll IMPORTLIB = libwininet.$(IMPLIBEXT) IMPORTS = mpr shlwapi shell32 user32 advapi32 kernel32 ntdll -DELAYIMPORTS = crypt32 +DELAYIMPORTS = secur32 crypt32 EXTRALIBS = @SOCKETLIBS@ C_SRCS = \ diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c index 08c057d85b4..f1db13ffedc 100644 --- a/dlls/wininet/http.c +++ b/dlls/wininet/http.c @@ -55,6 +55,7 @@ #define NO_SHLWAPI_STRFCNS #define NO_SHLWAPI_GDI #include "shlwapi.h" +#include "sspi.h" #include "internet.h" #include "wine/debug.h" @@ -68,6 +69,7 @@ static const WCHAR g_szReferer[] = {'R','e','f','e','r','e','r',0}; static const WCHAR g_szAccept[] = {'A','c','c','e','p','t',0}; static const WCHAR g_szUserAgent[] = {'U','s','e','r','-','A','g','e','n','t',0}; static const WCHAR szHost[] = { 'H','o','s','t',0 }; +static const WCHAR szAuthorization[] = { 'A','u','t','h','o','r','i','z','a','t','i','o','n',0 }; static const WCHAR szProxy_Authorization[] = { 'P','r','o','x','y','-','A','u','t','h','o','r','i','z','a','t','i','o','n',0 }; static const WCHAR szStatus[] = { 'S','t','a','t','u','s',0 }; static const WCHAR szKeepAlive[] = {'K','e','e','p','-','A','l','i','v','e',0}; @@ -88,6 +90,17 @@ static const WCHAR szKeepAlive[] = {'K','e','e','p','-','A','l','i','v','e',0}; #define HTTP_ADDHDR_FLAG_REPLACE 0x80000000 #define HTTP_ADDHDR_FLAG_REQ 0x02000000 +struct HttpAuthInfo +{ + LPWSTR scheme; + CredHandle cred; + CtxtHandle ctx; + TimeStamp exp; + ULONG attr; + void *auth_data; + unsigned int auth_data_len; + BOOL finished; /* finished authenticating */ +}; static void HTTP_CloseHTTPRequestHandle(LPWININETHANDLEHEADER hdr); static void HTTP_CloseHTTPSessionHandle(LPWININETHANDLEHEADER hdr); @@ -105,6 +118,7 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLevel, LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex); static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl); +static UINT HTTP_DecodeBase64(LPCWSTR base64, LPSTR bin); LPHTTPHEADERW HTTP_GetHeader(LPWININETHTTPREQW req, LPCWSTR head) @@ -397,6 +411,176 @@ static void HTTP_AddProxyInfo( LPWININETHTTPREQW lpwhr ) hIC->lpszProxyPassword); } +static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue ) +{ + static const WCHAR szBasic[] = {'B','a','s','i','c',0}; + SECURITY_STATUS sec_status; + struct HttpAuthInfo *pAuthInfo = lpwhr->pAuthInfo; + LPWSTR password = lpwhr->lpHttpSession->lpszPassword; + LPWSTR domain_and_username = lpwhr->lpHttpSession->lpszUserName; + + TRACE("%s\n", debugstr_w(pszAuthValue)); + + if (!domain_and_username) return FALSE; + + if (!pAuthInfo) + { + TimeStamp exp; + + pAuthInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*pAuthInfo)); + if (!pAuthInfo) + return FALSE; + + pAuthInfo->scheme = WININET_strdupW(pszAuthValue); + if (!pAuthInfo->scheme) + { + HeapFree(GetProcessHeap(), 0, pAuthInfo); + return FALSE; + } + SecInvalidateHandle(&pAuthInfo->cred); + SecInvalidateHandle(&pAuthInfo->ctx); + memset(&pAuthInfo->exp, 0, sizeof(pAuthInfo->exp)); + pAuthInfo->attr = 0; + pAuthInfo->auth_data = NULL; + pAuthInfo->auth_data_len = 0; + pAuthInfo->finished = FALSE; + + if (strncmpiW(pszAuthValue, szBasic, sizeof(szBasic)/sizeof(szBasic[0])-1)) + { + SEC_WINNT_AUTH_IDENTITY_W nt_auth_identity; + WCHAR *user = strchrW(domain_and_username, '\\'); + WCHAR *domain = domain_and_username; + + if (user) user++; + else + { + user = domain_and_username; + domain = NULL; + } + nt_auth_identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; + nt_auth_identity.User = user; + nt_auth_identity.UserLength = strlenW(nt_auth_identity.User); + nt_auth_identity.Domain = domain; + nt_auth_identity.DomainLength = domain ? user - domain - 1 : 0; + nt_auth_identity.Password = password; + nt_auth_identity.PasswordLength = strlenW(nt_auth_identity.Password); + + /* FIXME: make sure scheme accepts SEC_WINNT_AUTH_IDENTITY before calling AcquireCredentialsHandle */ + + sec_status = AcquireCredentialsHandleW(NULL, pAuthInfo->scheme, + SECPKG_CRED_OUTBOUND, NULL, + &nt_auth_identity, NULL, + NULL, &pAuthInfo->cred, + &exp); + if (sec_status != SEC_E_OK) + { + WARN("AcquireCredentialsHandleW for scheme %s failed with error 0x%08x\n", + debugstr_w(pAuthInfo->scheme), sec_status); + HeapFree(GetProcessHeap(), 0, pAuthInfo->scheme); + HeapFree(GetProcessHeap(), 0, pAuthInfo); + return FALSE; + } + } + lpwhr->pAuthInfo = pAuthInfo; + } + else if (pAuthInfo->finished) + return FALSE; + + if (strncmpiW(pszAuthValue, pAuthInfo->scheme, strlenW(pAuthInfo->scheme))) + { + ERR("authentication scheme changed from %s to %s\n", + debugstr_w(pAuthInfo->scheme), debugstr_w(pszAuthValue)); + return FALSE; + } + + if (!strncmpW(pszAuthValue, szBasic, sizeof(szBasic)/sizeof(szBasic[0])-1)) + { + int userlen = WideCharToMultiByte(CP_UTF8, 0, domain_and_username, lstrlenW(domain_and_username), NULL, 0, NULL, NULL); + int passlen = WideCharToMultiByte(CP_UTF8, 0, password, lstrlenW(password), NULL, 0, NULL, NULL); + char *auth_data; + + TRACE("basic authentication\n"); + + /* length includes a nul terminator, which will be re-used for the ':' */ + auth_data = HeapAlloc(GetProcessHeap(), 0, userlen + 1 + passlen); + if (!auth_data) + return FALSE; + + WideCharToMultiByte(CP_UTF8, 0, domain_and_username, -1, auth_data, userlen, NULL, NULL); + auth_data[userlen] = ':'; + WideCharToMultiByte(CP_UTF8, 0, password, -1, &auth_data[userlen+1], passlen, NULL, NULL); + + pAuthInfo->auth_data = auth_data; + pAuthInfo->auth_data_len = userlen + 1 + passlen; + pAuthInfo->finished = TRUE; + + return TRUE; + } + else + { + LPCWSTR pszAuthData; + SecBufferDesc out_desc, in_desc; + SecBuffer out, in; + unsigned char *buffer; + ULONG context_req = ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE | + ISC_REQ_MUTUAL_AUTH | ISC_REQ_DELEGATE; + + in.BufferType = SECBUFFER_TOKEN; + in.cbBuffer = 0; + in.pvBuffer = NULL; + + in_desc.ulVersion = 0; + in_desc.cBuffers = 1; + in_desc.pBuffers = ∈ + + pszAuthData = pszAuthValue + strlenW(pAuthInfo->scheme); + if (*pszAuthData == ' ') + { + pszAuthData++; + in.cbBuffer = HTTP_DecodeBase64(pszAuthData, NULL); + in.pvBuffer = HeapAlloc(GetProcessHeap(), 0, in.cbBuffer); + HTTP_DecodeBase64(pszAuthData, in.pvBuffer); + } + + buffer = HeapAlloc(GetProcessHeap(), 0, 0x100); + + out.BufferType = SECBUFFER_TOKEN; + out.cbBuffer = 0x100; + out.pvBuffer = buffer; + + out_desc.ulVersion = 0; + out_desc.cBuffers = 1; + out_desc.pBuffers = &out; + + sec_status = InitializeSecurityContextW(&pAuthInfo->cred, NULL, NULL, + context_req, 0, SECURITY_NETWORK_DREP, + in.pvBuffer ? &in_desc : NULL, + 0, &pAuthInfo->ctx, &out_desc, + &pAuthInfo->attr, &pAuthInfo->exp); + if (sec_status == SEC_E_OK) + { + pAuthInfo->finished = TRUE; + pAuthInfo->auth_data = out.pvBuffer; + pAuthInfo->auth_data_len = out.cbBuffer; + TRACE("sending last auth packet\n"); + } + else if (sec_status == SEC_I_CONTINUE_NEEDED) + { + pAuthInfo->auth_data = out.pvBuffer; + pAuthInfo->auth_data_len = out.cbBuffer; + TRACE("sending next auth packet\n"); + } + else + { + ERR("InitializeSecurityContextW returned error 0x%08x\n", sec_status); + HeapFree(GetProcessHeap(), 0, out.pvBuffer); + return FALSE; + } + } + + return TRUE; +} + /*********************************************************************** * HTTP_HttpAddRequestHeadersW (internal) */ @@ -890,6 +1074,71 @@ static UINT HTTP_EncodeBase64( LPCSTR bin, unsigned int len, LPWSTR base64 ) } /*********************************************************************** + * HTTP_DecodeBase64 + */ +static UINT HTTP_DecodeBase64( LPCWSTR base64, LPSTR bin ) +{ + static char HTTP_Base64Dec[256]; + unsigned int n = 0; + + /* compare against last character to be set to avoid a race */ + if (HTTP_Base64Dec['/'] != 63) + { + static char HTTP_Base64Enc[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + int i; + memset(HTTP_Base64Dec, -1, sizeof(HTTP_Base64Dec)); + for (i = 0; i < strlen(HTTP_Base64Enc); i++) + HTTP_Base64Dec[(unsigned char)HTTP_Base64Enc[i]] = i; + } + + while(*base64) + { + char in[4]; + + if (base64[0] > sizeof(HTTP_Base64Dec) || + ((in[0] = HTTP_Base64Dec[base64[0]]) == -1) || + base64[1] > sizeof(HTTP_Base64Dec) || + ((in[1] = HTTP_Base64Dec[base64[1]]) == -1)) + { + WARN("invalid base64: %s\n", debugstr_w(base64)); + return 0; + } + if (bin) + bin[n] = (unsigned char) (in[0] << 2 | in[1] >> 4); + n++; + + if ((base64[2] == '=') && (base64[3] == '=')) + break; + if (base64[2] > sizeof(HTTP_Base64Dec) || + ((in[2] = HTTP_Base64Dec[base64[2]]) == -1)) + { + WARN("invalid base64: %s\n", debugstr_w(&base64[2])); + return 0; + } + if (bin) + bin[n] = (unsigned char) (in[1] << 4 | in[2] >> 2); + n++; + + if (base64[3] == '=') + break; + if (base64[3] > sizeof(HTTP_Base64Dec) || + ((in[3] = HTTP_Base64Dec[base64[3]]) == -1)) + { + WARN("invalid base64: %s\n", debugstr_w(&base64[3])); + return 0; + } + if (bin) + bin[n] = (unsigned char) (((in[2] << 6) & 0xc0) | in[3]); + n++; + + base64 += 4; + } + + return n; +} + +/*********************************************************************** * HTTP_EncodeBasicAuth * * Encode the basic authentication string for HTTP 1.1 @@ -948,6 +1197,49 @@ static BOOL HTTP_InsertProxyAuthorization( LPWININETHTTPREQW lpwhr, } /*********************************************************************** + * HTTP_InsertAuthorization + * + * Insert or delete the authorization field in the request header. + */ +static BOOL HTTP_InsertAuthorization( LPWININETHTTPREQW lpwhr ) +{ + WCHAR *authorization = NULL; + + if (lpwhr->pAuthInfo && lpwhr->pAuthInfo->auth_data_len) + { + static const WCHAR wszSpace[] = {' ',0}; + unsigned int len; + + /* scheme + space + base64 encoded data (3/2/1 bytes data -> 4 bytes of characters) */ + len = strlenW(lpwhr->pAuthInfo->scheme)+1+((lpwhr->pAuthInfo->auth_data_len+2)*4)/3; + authorization = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR)); + if (!authorization) + return FALSE; + + strcpyW(authorization, lpwhr->pAuthInfo->scheme); + strcatW(authorization, wszSpace); + HTTP_EncodeBase64(lpwhr->pAuthInfo->auth_data, + lpwhr->pAuthInfo->auth_data_len, + authorization+strlenW(authorization)); + + /* clear the data as it isn't valid now that it has been sent to the + * server */ + HeapFree(GetProcessHeap(), 0, lpwhr->pAuthInfo->auth_data); + lpwhr->pAuthInfo->auth_data = NULL; + lpwhr->pAuthInfo->auth_data_len = 0; + } + + TRACE("Inserting authorization: %s\n", debugstr_w(authorization)); + + HTTP_ProcessHeader(lpwhr, szAuthorization, authorization, + HTTP_ADDHDR_FLAG_REPLACE | HTTP_ADDHDR_FLAG_REQ); + + HeapFree(GetProcessHeap(), 0, authorization); + + return TRUE; +} + +/*********************************************************************** * HTTP_DealWithProxy */ static BOOL HTTP_DealWithProxy( LPWININETAPPINFOW hIC, @@ -1227,7 +1519,6 @@ static const WCHAR szAccept_Language[] = { 'A','c','c','e','p','t','-','L','a',' static const WCHAR szAccept_Ranges[] = { 'A','c','c','e','p','t','-','R','a','n','g','e','s',0 }; static const WCHAR szAge[] = { 'A','g','e',0 }; static const WCHAR szAllow[] = { 'A','l','l','o','w',0 }; -static const WCHAR szAuthorization[] = { 'A','u','t','h','o','r','i','z','a','t','i','o','n',0 }; static const WCHAR szCache_Control[] = { 'C','a','c','h','e','-','C','o','n','t','r','o','l',0 }; static const WCHAR szConnection[] = { 'C','o','n','n','e','c','t','i','o','n',0 }; static const WCHAR szContent_Base[] = { 'C','o','n','t','e','n','t','-','B','a','s','e',0 }; @@ -2313,6 +2604,7 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, lpwhr->hdr.dwFlags & INTERNET_FLAG_KEEP_CONNECTION ? szKeepAlive : szClose, HTTP_ADDHDR_FLAG_REQ | HTTP_ADDHDR_FLAG_REPLACE); + HTTP_InsertAuthorization(lpwhr); /* if there's a proxy username and password, add it to the headers */ HTTP_AddProxyInfo(lpwhr); @@ -2397,7 +2689,25 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, } } } - + if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTH) && bSuccess) + { + DWORD dwCode,dwCodeLength=sizeof(DWORD); + WCHAR szAuthValue[2048]; + dwBufferSize=2048; + if (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,&dwCode,&dwCodeLength,NULL) && + (dwCode == HTTP_STATUS_DENIED)) + { + DWORD dwIndex = 0; + while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_WWW_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex)) + { + if (HTTP_DoAuthorization(lpwhr, szAuthValue)) + { + loop_next = TRUE; + break; + } + } + } + } } else bSuccess = TRUE; @@ -2489,6 +2799,8 @@ HINTERNET HTTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, } if (lpszUserName && lpszUserName[0]) lpwhs->lpszUserName = WININET_strdupW(lpszUserName); + if (lpszPassword && lpszPassword[0]) + lpwhs->lpszPassword = WININET_strdupW(lpszPassword); lpwhs->nServerPort = nServerPort; lpwhs->nHostPort = nServerPort; @@ -2973,6 +3285,17 @@ static VOID HTTP_CloseConnection(LPWININETHTTPREQW lpwhr) if (!NETCON_connected(&lpwhr->netConnection)) return; + if (lpwhr->pAuthInfo) + { + DeleteSecurityContext(&lpwhr->pAuthInfo->ctx); + FreeCredentialsHandle(&lpwhr->pAuthInfo->cred); + + HeapFree(GetProcessHeap(), 0, lpwhr->pAuthInfo->auth_data); + HeapFree(GetProcessHeap(), 0, lpwhr->pAuthInfo->scheme); + HeapFree(GetProcessHeap(), 0, lpwhr->pAuthInfo); + lpwhr->pAuthInfo = NULL; + } + lpwhs = lpwhr->lpHttpSession; hIC = lpwhs->lpAppInfo; @@ -3061,6 +3384,7 @@ static void HTTP_CloseHTTPSessionHandle(LPWININETHANDLEHEADER hdr) HeapFree(GetProcessHeap(), 0, lpwhs->lpszHostName); HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName); + HeapFree(GetProcessHeap(), 0, lpwhs->lpszPassword); HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName); HeapFree(GetProcessHeap(), 0, lpwhs); } diff --git a/dlls/wininet/internet.c b/dlls/wininet/internet.c index 6345a5b8905..84d298993d8 100644 --- a/dlls/wininet/internet.c +++ b/dlls/wininet/internet.c @@ -2189,6 +2189,14 @@ static BOOL INET_QueryOptionHelper(BOOL bIsUnicode, HINTERNET hInternet, DWORD d } case INTERNET_OPTION_SECURITY_FLAGS: FIXME("INTERNET_OPTION_SECURITY_FLAGS: Stub\n"); + if (*lpdwBufferLength < sizeof(DWORD)) + SetLastError(ERROR_INSUFFICIENT_BUFFER); + else + { + *(DWORD *)lpBuffer = 0; + bSuccess = TRUE; + } + *lpdwBufferLength = sizeof(DWORD); break; case INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT: diff --git a/dlls/wininet/internet.h b/dlls/wininet/internet.h index 49c7930023a..c1476de1936 100644 --- a/dlls/wininet/internet.h +++ b/dlls/wininet/internet.h @@ -166,6 +166,7 @@ typedef struct LPWSTR lpszHostName; /* the final destination of the request */ LPWSTR lpszServerName; /* the name of the server we directly connect to */ LPWSTR lpszUserName; + LPWSTR lpszPassword; INTERNET_PORT nHostPort; /* the final destination port of the request */ INTERNET_PORT nServerPort; /* the port of the server we directly connect to */ struct sockaddr_in socketAddress; @@ -184,6 +185,8 @@ typedef struct } HTTPHEADERW, *LPHTTPHEADERW; +struct HttpAuthInfo; + typedef struct { WININETHANDLEHEADER hdr; @@ -198,6 +201,7 @@ typedef struct DWORD dwContentRead; /* bytes of the content read so far */ HTTPHEADERW *pCustHeaders; DWORD nCustHeaders; + struct HttpAuthInfo *pAuthInfo; } WININETHTTPREQW, *LPWININETHTTPREQW; diff --git a/dlls/wininet/netconnection.c b/dlls/wininet/netconnection.c index ec2b18dac4c..9633f54319f 100644 --- a/dlls/wininet/netconnection.c +++ b/dlls/wininet/netconnection.c @@ -118,10 +118,37 @@ BOOL NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) if (useSSL) { #if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H + const char *libcrypto_name_candidates[] = {SONAME_LIBCRYPTO, + "libcrypto.so.0.9.7", + "libcrypto.so.0.9.7a", + "libcrypto.so.0.9.7f", + "libcrypto.so.0.9.8", + "libcrypto.so.0.9.8a", + "libcrypto.so.6", + "libcrypto.so.5", + "libcrypto.so.4", + "libcrypto.so.0", + NULL}; + int i; + const char *libssl_name_candidates[] = {SONAME_LIBSSL, + "libssl.so.0.9.7", + "libssl.so.0.9.7a", + "libssl.so.0.9.7f", + "libssl.so.0.9.8", + "libssl.so.0.9.8a", + "libssl.so.6", + "libssl.so.5", + "libssl.so.4", + "libssl.so.0", + NULL}; + TRACE("using SSL connection\n"); - if (OpenSSL_ssl_handle) /* already initialized everything */ + if (OpenSSL_ssl_handle) /* already initialized everything */ return TRUE; - OpenSSL_ssl_handle = wine_dlopen(SONAME_LIBSSL, RTLD_NOW, NULL, 0); + + for (i = 0; libssl_name_candidates[i] && !OpenSSL_ssl_handle; i++ ) + OpenSSL_ssl_handle = wine_dlopen(libssl_name_candidates[i], RTLD_NOW, NULL, 0); + if (!OpenSSL_ssl_handle) { ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n", @@ -129,7 +156,10 @@ BOOL NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); return FALSE; } - OpenSSL_crypto_handle = wine_dlopen(SONAME_LIBCRYPTO, RTLD_NOW, NULL, 0); + + for (i = 0; libcrypto_name_candidates[i] && !OpenSSL_crypto_handle; i++ ) + OpenSSL_crypto_handle = wine_dlopen(libcrypto_name_candidates[i], RTLD_NOW, NULL, 0); + if (!OpenSSL_crypto_handle) { ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n", diff --git a/dlls/wininet/utility.c b/dlls/wininet/utility.c index 34e72d0f668..29c67abb2ec 100644 --- a/dlls/wininet/utility.c +++ b/dlls/wininet/utility.c @@ -43,6 +43,17 @@ WINE_DEFAULT_DEBUG_CHANNEL(wininet); #define TIME_STRING_LEN 30 +/* critical section to protect non-rentrant gethostbyname */ +static CRITICAL_SECTION cs_gethostbyname; +static CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &cs_gethostbyname, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": cs_gethostbyname") } +}; +static CRITICAL_SECTION cs_gethostbyname = { &critsect_debug, -1, 0, 0, 0, 0 }; + + time_t ConvertTimeString(LPCWSTR asctime) { WCHAR tmpChar[TIME_STRING_LEN]; @@ -151,20 +162,30 @@ BOOL GetAddress(LPCWSTR lpszServerName, INTERNET_PORT nServerPort, name = HeapAlloc(GetProcessHeap(), 0, sz+1); WideCharToMultiByte( CP_UNIXCP, 0, lpszServerName, len, name, sz, NULL, NULL ); name[sz] = 0; + + /* FIXME: gethostbyname is not thread-safe, so we work around this by + * wrapping it in a critical section. In the long term we should try to + * use getaddrinfo because not only is it thread-safe, but it is also IPv6 + * compatible too. */ + EnterCriticalSection(&cs_gethostbyname); + phe = gethostbyname(name); HeapFree( GetProcessHeap(), 0, name ); if (NULL == phe) { TRACE("Failed to get hostname: (%s)\n", debugstr_w(lpszServerName) ); + LeaveCriticalSection(&cs_gethostbyname); return FALSE; } memset(psa,0,sizeof(struct sockaddr_in)); - memcpy((char *)&psa->sin_addr, phe->h_addr, phe->h_length); + memcpy((char *)&psa->sin_addr, phe->h_addr, min(phe->h_length, sizeof(psa->sin_addr))); psa->sin_family = phe->h_addrtype; psa->sin_port = htons((u_short)nServerPort); + LeaveCriticalSection(&cs_gethostbyname); + return TRUE; } diff --git a/dlls/winspool.drv/info.c b/dlls/winspool.drv/info.c index 7fc3e733877..8ecf795fc82 100644 --- a/dlls/winspool.drv/info.c +++ b/dlls/winspool.drv/info.c @@ -3615,6 +3615,63 @@ static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName, } /********************************************************************* + * WINSPOOL_GetPrinter_1 + * + * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf. + * The strings are either stored as unicode or ascii. + */ +static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1, + LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded, + BOOL unicode) +{ + DWORD size, left = cbBuf; + BOOL space = (cbBuf > 0); + LPBYTE ptr = buf; + + *pcbNeeded = 0; + + if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size, + unicode)) { + if(space && size <= left) { + pi1->pName = (LPWSTR)ptr; + ptr += size; + left -= size; + } else + space = FALSE; + *pcbNeeded += size; + } + + /* FIXME: pDescription should be something like "Name,Driver_Name,". */ + if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size, + unicode)) { + if(space && size <= left) { + pi1->pDescription = (LPWSTR)ptr; + ptr += size; + left -= size; + } else + space = FALSE; + *pcbNeeded += size; + } + + if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size, + unicode)) { + if(space && size <= left) { + pi1->pComment = (LPWSTR)ptr; + ptr += size; + left -= size; + } else + space = FALSE; + *pcbNeeded += size; + } + + if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */ + + if(!space && pi1) /* zero out pi1 if we can't completely fill buf */ + memset(pi1, 0, sizeof(*pi1)); + + return space; +} +/********************************************************************* * WINSPOOL_GetPrinter_2 * * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf. @@ -4046,11 +4103,8 @@ static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName, switch(dwLevel) { case 1: - RegCloseKey(hkeyPrinters); - if (lpdwReturned) - *lpdwReturned = number; - return TRUE; - + used = number * sizeof(PRINTER_INFO_1W); + break; case 2: used = number * sizeof(PRINTER_INFO_2W); break; @@ -4092,6 +4146,12 @@ static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName, } switch(dwLevel) { + case 1: + WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf, + left, &needed, unicode); + used += needed; + if(pi) pi += sizeof(PRINTER_INFO_1W); + break; case 2: WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf, left, &needed, unicode); @@ -4145,8 +4205,8 @@ static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName, * RETURNS: * * If level is set to 1: - * Not implemented yet! - * Returns TRUE with an empty list. + * Returns an array of PRINTER_INFO_1 data structures in the + * lpbPrinters buffer. * * If level is set to 2: * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL. diff --git a/dlls/winspool.drv/wspool.c b/dlls/winspool.drv/wspool.c index 27c39e6fa70..54f8944522e 100644 --- a/dlls/winspool.drv/wspool.c +++ b/dlls/winspool.drv/wspool.c @@ -39,15 +39,21 @@ HINSTANCE WINSPOOL_hInstance = NULL; */ BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD reason, LPVOID lpReserved) { + static HMODULE hWineps; + switch (reason) { case DLL_PROCESS_ATTACH: { + /* Hack to avoid loading/unloading wineps many times */ + hWineps = LoadLibraryA("WINEPS.DRV"); WINSPOOL_hInstance = hInstance; + DisableThreadLibraryCalls(hInstance); WINSPOOL_LoadSystemPrinters(); break; } case DLL_PROCESS_DETACH: + if(hWineps) FreeLibrary(hWineps); break; } diff --git a/include/Makefile.in b/include/Makefile.in index da9ae3c492f..f1dd34ded49 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -19,6 +19,8 @@ IDL_H_SRCS = \ hlink.idl \ htiframe.idl \ iads.idl \ + imnact.idl \ + imnxport.idl \ indexsrv.idl \ mediaobj.idl \ mimeinfo.idl \ diff --git a/include/config.h.in b/include/config.h.in index 599ea65c7c6..a543fa433ff 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -300,6 +300,9 @@ /* Define to 1 if you have the `ldap_parse_reference' function. */ #undef HAVE_LDAP_PARSE_REFERENCE +/* Define if you have the X AppleWM extension */ +#undef HAVE_LIBAPPLEWM + /* Define if you have libaudioIO */ #undef HAVE_LIBAUDIOIO @@ -882,6 +885,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H +/* Define to 1 if you have the header file. */ +#undef HAVE_USB_H + /* Define to 1 if you have the `usleep' function. */ #undef HAVE_USLEEP @@ -903,6 +909,9 @@ /* Define to 1 if you have the `waitpid' function. */ #undef HAVE_WAITPID +/* Define to 1 if you have the header file. */ +#undef HAVE_X11_EXTENSIONS_APPLEWM_H + /* Define to 1 if you have the header file. */ #undef HAVE_X11_EXTENSIONS_SHAPE_H diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index a254128a4b5..78fe80d2f5b 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -862,6 +862,7 @@ struct select_request struct select_reply { struct reply_header __header; + int priority; }; #define SELECT_ALL 1 #define SELECT_ALERTABLE 2 @@ -1692,6 +1693,7 @@ struct create_mapping_request int size_low; int protect; obj_handle_t file_handle; + int hack_val; /* VARARG(name,unicode_str); */ }; struct create_mapping_reply @@ -1743,6 +1745,8 @@ struct get_mapping_info_reply obj_handle_t mapping; obj_handle_t shared_file; int shared_size; + int id; + int hack_val; }; @@ -4662,6 +4666,6 @@ union generic_reply struct allocate_locally_unique_id_reply allocate_locally_unique_id_reply; }; -#define SERVER_PROTOCOL_VERSION 289 +#define SERVER_PROTOCOL_VERSION 213 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/include/wine/wined3d_caps.h b/include/wine/wined3d_caps.h index 58cfb57b419..95b400e4eef 100644 --- a/include/wine/wined3d_caps.h +++ b/include/wine/wined3d_caps.h @@ -19,6 +19,12 @@ #ifndef __WINE_WINED3D_CAPS_H #define __WINE_WINED3D_CAPS_H +#define WINED3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD 0x00000020L +#define WINED3DCAPS3_LINEAR_TO_SRGB_PRESENTATION 0x00000080L +#define WINED3DCAPS3_COPY_TO_VIDMEM 0x00000100L +#define WINED3DCAPS3_COPY_TO_SYSTEMMEM 0x00000200L +#define WINED3DCAPS3_RESERVED 0x8000001FL + #define WINED3DDEVCAPS2_STREAMOFFSET 0x00000001 #define WINED3DDEVCAPS2_DMAPNPATCH 0x00000002 #define WINED3DDEVCAPS2_ADAPTIVETESSRTPATCH 0x00000004 diff --git a/include/wine/wined3d_gl.h b/include/wine/wined3d_gl.h index dbb76a1ecc5..1b4744f7678 100644 --- a/include/wine/wined3d_gl.h +++ b/include/wine/wined3d_gl.h @@ -1147,7 +1147,7 @@ typedef void (APIENTRY * PGLFNFINISHFENCENVPROC) (GLuint); typedef GLboolean (APIENTRY * PGLFNISFENCENVPROC) (GLuint); typedef void (APIENTRY * PGLFNGETFENCEIVNVPROC) (GLuint, GLenum, GLint *); /* GL_APPLE_fence */ -#ifndef GL_NV_fence +#ifndef GL_APPLE_fence #define GL_DRAW_PIXELS_APPLE 0x8A0A #define GL_FENCE_APPLE 0x84F3 #endif @@ -1159,6 +1159,10 @@ typedef void (APIENTRY * PGLFNFINISHFENCEAPPLEPROC) (GLuint); typedef GLboolean (APIENTRY * PGLFNISFENCEAPPLEPROC) (GLuint); typedef GLboolean (APIENTRY * PGLFNTESTOBJECTAPPLEPROC) (GLenum, GLuint); typedef void (APIENTRY * PGLFNFINISHOBJECTAPPLEPROC) (GLenum, GLuint); +/* GL_APPLE_client_storage */ +#ifndef GL_APPLE_client_storage +#define GL_UNPACK_CLIENT_STORAGE_APPLE 0x85B2 +#endif /* GL_ATI_envmap_bumpmap */ #ifndef GL_ATI_envmap_bumpmap #define GL_BUMP_ROT_MATRIX_ATI 0x8775 @@ -1540,6 +1544,7 @@ typedef enum _GL_SupportedExt { ATI_ENVMAP_BUMPMAP, /* APPLE */ APPLE_FENCE, + APPLE_CLIENT_STORAGE, OPENGL_SUPPORTED_EXT_END } GL_SupportedExt; diff --git a/libs/wine/collation.c b/libs/wine/collation.c index 446b03dc4e2..e4e6b860dd7 100644 --- a/libs/wine/collation.c +++ b/libs/wine/collation.c @@ -75,34 +75,34 @@ const unsigned int collation_table[12800] = 0x00000000, 0x02010111, 0x02020111, 0x02030111, 0x02040111, 0x02050111, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x02090111, 0x024b0111, 0x02700111, 0x02a90111, 0x09e00111, 0x02aa0111, 0x02a70111, 0x02690111, - 0x027a0111, 0x027b0111, 0x02a20111, 0x039f0111, 0x022d0111, 0x02210111, 0x02550111, 0x02a40111, - 0x0a0b0111, 0x0a0c0111, 0x0a0d0111, 0x0a0e0111, 0x0a0f0111, 0x0a100111, 0x0a110111, 0x0a120111, - 0x0a130111, 0x0a140111, 0x02370111, 0x02350111, 0x03a30111, 0x03a40111, 0x03a50111, 0x024e0111, - 0x02a10111, 0x0a150151, 0x0a290141, 0x0a3d0151, 0x0a490151, 0x0a650151, 0x0a910151, 0x0a990151, + 0x01290111, 0x020c0111, 0x020d0111, 0x020f0111, 0x02100111, 0x02140111, 0x02190111, 0x01200111, + 0x021b0111, 0x022d0111, 0x02350111, 0x02a70111, 0x02370111, 0x01210111, 0x024b0111, 0x024c0111, + 0x0a0b0111, 0x0a0c0111, 0x0a0d0111, 0x0a0e0111, 0x0a0f0181, 0x0a100111, 0x0a110111, 0x0a120111, + 0x0a130111, 0x0a140111, 0x024e0111, 0x024f0111, 0x02a90111, 0x02aa0111, 0x030a0111, 0x02550111, + 0x025f0111, 0x0a150151, 0x0a290141, 0x0a3d0151, 0x0a490151, 0x0a650151, 0x0a910151, 0x0a990151, 0x0ab90151, 0x0ad30161, 0x0ae70141, 0x0af70141, 0x0b030161, 0x0b2b0151, 0x0b330151, 0x0b4b0161, 0x0b670141, 0x0b730141, 0x0b7f0141, 0x0ba70151, 0x0bbf0151, 0x0bd70141, 0x0bef0151, 0x0bfb0141, - 0x0c030151, 0x0c070141, 0x0c130141, 0x027c0111, 0x02a60111, 0x027d0111, 0x020f0111, 0x021b0111, - 0x020c0111, 0x0a150111, 0x0a290111, 0x0a3d0111, 0x0a490111, 0x0a650111, 0x0a910111, 0x0a990111, + 0x0c030151, 0x0c070141, 0x0c130141, 0x02700111, 0x02780111, 0x02790111, 0x027a0111, 0x027b0111, + 0x027c0111, 0x0a150111, 0x0a290111, 0x0a3d0111, 0x0a490111, 0x0a650111, 0x0a910111, 0x0a990111, 0x0ab90111, 0x0ad30111, 0x0ae70111, 0x0af70111, 0x0b030111, 0x0b2b0111, 0x0b330111, 0x0b4b0111, 0x0b670111, 0x0b730111, 0x0b7f0111, 0x0ba70111, 0x0bbf0111, 0x0bd70111, 0x0bef0111, 0x0bfb0111, - 0x0c030111, 0x0c070111, 0x0c130111, 0x027e0111, 0x03a70111, 0x027f0111, 0x03aa0111, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02060111, 0x00000000, 0x00000000, + 0x0c030111, 0x0c070111, 0x0c130111, 0x027d0111, 0x027e0111, 0x027f0111, 0x029c0111, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x02090141, 0x024c0111, 0x09df0111, 0x09e10111, 0x09de0111, 0x09e20111, 0x03a80111, 0x029c0111, - 0x02140111, 0x029f0111, 0x0a150181, 0x02780111, 0x03a60111, 0x02200111, 0x02a00111, 0x02100111, - 0x030a0111, 0x03a00111, 0x0a0d0151, 0x0a0e0151, 0x020d0111, 0x0c9f0121, 0x029d0111, 0x025f0111, - 0x02190111, 0x0a0c0151, 0x0b4b01a1, 0x02790111, 0x0a0c0171, 0x0a0c0171, 0x0a0e0171, 0x024f0111, + 0x01290121, 0x029d0111, 0x03a40111, 0x03a50111, 0x03a60111, 0x03a70111, 0x029f0111, 0x03a80111, + 0x02a00111, 0x03aa0111, 0x0a150181, 0x03a00111, 0x09de0111, 0x01220111, 0x09df0111, 0x02a10111, + 0x09e00111, 0x039f0111, 0x0a0d0151, 0x0a0e0151, 0x02a20111, 0x09e10111, 0x09e20111, 0x09ef0111, + 0x02a40111, 0x0a0c0151, 0x0b4b01a1, 0x03a10111, 0x0a0c0171, 0x0a0c0171, 0x0a0c0171, 0x02a60111, 0x0a150151, 0x0a150151, 0x0a150151, 0x0a150151, 0x0a150151, 0x0a150151, 0x0a190121, 0x0a3d0151, 0x0a650151, 0x0a650151, 0x0a650151, 0x0a650151, 0x0ad30161, 0x0ad30161, 0x0ad30161, 0x0ad30161, 0x0a5d0121, 0x0b330151, 0x0b4b0161, 0x0b4b0161, 0x0b4b0161, 0x0b4b0161, 0x0b4b0161, 0x03a20111, - 0x0b530121, 0x0bd70141, 0x0bd70141, 0x0bd70141, 0x0bd70141, 0x0c070141, 0x0c3b0121, 0x0ba70131, + 0x0b530121, 0x0bd70141, 0x0bd70141, 0x0bd70141, 0x0bd70141, 0x0c070141, 0x0bd40121, 0x0ba70131, 0x0a150111, 0x0a150111, 0x0a150111, 0x0a150111, 0x0a150111, 0x0a150111, 0x0a190111, 0x0a3d0111, 0x0a650111, 0x0a650111, 0x0a650111, 0x0a650111, 0x0ad30111, 0x0ad30111, 0x0ad30111, 0x0ad30111, - 0x0a5d0111, 0x0b330111, 0x0b4b0111, 0x0b4b0111, 0x0b4b0111, 0x0b4b0111, 0x0b4b0111, 0x03a10111, - 0x0b530111, 0x0bd70111, 0x0bd70111, 0x0bd70111, 0x0bd70111, 0x0c070111, 0x0c3b0111, 0x0c070111, + 0x0a5d0111, 0x0b330111, 0x0b4b0111, 0x0b4b0111, 0x0b4b0111, 0x0b4b0111, 0x0b4b0111, 0x03a30111, + 0x0b530111, 0x0bd70111, 0x0bd70111, 0x0bd70111, 0x0bd70111, 0x0c070111, 0x0bd40111, 0x0c070111, /* 0x0100 .. 0x01ff */ 0x0a150151, 0x0a150111, 0x0a150151, 0x0a150111, 0x0a150151, 0x0a150111, 0x0a3d0151, 0x0a3d0111, 0x0a3d0151, 0x0a3d0111, 0x0a3d0151, 0x0a3d0111, 0x0a3d0151, 0x0a3d0111, 0x0a490151, 0x0a490111, @@ -189,7 +189,7 @@ const unsigned int collation_table[12800] = 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x020d0111, 0x02140111, 0x0c910121, 0x025f0111, 0x0c950131, 0x0c990121, 0x0c9b0121, 0xffffffff, 0x0ca20121, 0xffffffff, 0x0ca80121, 0x0cac0121, 0x0c9b0111, 0x0c910121, 0x0c920131, 0x0c930121, 0x0c940121, 0x0c950131, 0x0c980121, 0x0c990121, - 0x0c9a0131, 0x0c9b0121, 0x0c9d0131, 0x0c9e0121, 0x0c9f0131, 0x0ca00121, 0x0ca10121, 0x0ca20121, + 0x0c9a0131, 0x0c9b0121, 0x0c9d0131, 0x0c9e0121, 0x0c9f0121, 0x0ca00121, 0x0ca10121, 0x0ca20121, 0x0ca30131, 0x0ca50131, 0xffffffff, 0x0ca60131, 0x0ca70121, 0x0ca80121, 0x0ca90131, 0x0caa0121, 0x0cab0121, 0x0cac0121, 0x0c9b0121, 0x0ca80121, 0x0c910111, 0x0c950111, 0x0c990111, 0x0c9b0111, 0x0ca80111, 0x0c910111, 0x0c920111, 0x0c930111, 0x0c940111, 0x0c950111, 0x0c980111, 0x0c990111, @@ -929,12 +929,12 @@ const unsigned int collation_table[12800] = 0xffffffff, 0xffffffff, 0x0cac0111, 0x0cac0111, 0x0cac0111, 0xffffffff, 0x0cac0111, 0x0cac0111, 0x0ca20121, 0x0ca20121, 0x0cac0121, 0x0cac0121, 0x0cac0121, 0x020d0111, 0x02180111, 0xffffffff, /* 0x2000 .. 0x20ff */ - 0x02090131, 0x02090131, 0x02090131, 0x02090131, 0x02090131, 0x02090131, 0x02090131, 0x02090141, - 0x02090131, 0x02090131, 0x02090131, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x02090121, 0x02090121, 0x02090121, 0x02090121, 0x02090121, 0x02090121, 0x02090121, 0x02090131, + 0x02090121, 0x02090121, 0x02090121, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02250111, 0x02250121, 0x02260111, 0x02270111, 0x02280111, 0x02290111, 0x03a90111, 0x021c0111, 0x026a0111, 0x026b0111, 0x026c0111, 0x026d0111, 0x02710111, 0x02720111, 0x02730111, 0x02740111, 0x02ae0111, 0x02af0111, 0x02b00111, 0x02b10111, 0x02550131, 0x02550131, 0x02550131, 0x02b20111, - 0x02070111, 0x02080111, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02090141, + 0x02070111, 0x02080111, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02090131, 0x02ac0111, 0x02ad0111, 0x02b60111, 0x02b60121, 0x02b60121, 0x02b70111, 0x02b70121, 0x02b70121, 0x02b90111, 0x026e0111, 0x026f0111, 0x02ba0111, 0x024b0131, 0x02540111, 0x02110111, 0x02bb0111, 0x02bc0111, 0x02bd0111, 0x02be0111, 0x02b30111, 0x02a50111, 0x02860111, 0x02870111, 0xffffffff, @@ -1292,7 +1292,7 @@ const unsigned int collation_table[12800] = 0x09a90111, 0x09aa0111, 0x09ab0111, 0x09ac0111, 0x09ad0111, 0x09ae0111, 0x09af0111, 0x09b00111, 0x09b10111, 0x09b20111, 0x09b30111, 0x09b40111, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, /* 0x3000 .. 0x30ff */ - 0x02090121, 0x02340111, 0x025e0111, 0x02b80111, 0x09b50111, 0x09d70111, 0x192c0111, 0x0a0b0111, + 0x02090111, 0x02340111, 0x025e0111, 0x02b80111, 0x09b50111, 0x09d70111, 0x192c0111, 0x0a0b0111, 0x02880111, 0x02890111, 0x028a0111, 0x028b0111, 0x028c0111, 0x028d0111, 0x028e0111, 0x028f0111, 0x02900111, 0x02910111, 0x09b60111, 0x09b70111, 0x02920111, 0x02930111, 0x02940111, 0x02950111, 0x02960111, 0x02970111, 0x02980111, 0x02990111, 0x022a0111, 0x02750111, 0x02760111, 0x02770111, @@ -1407,14 +1407,14 @@ const unsigned int collation_table[12800] = 0x0a0c0131, 0x0a0c0131, 0x0a0c0131, 0x0a0c0131, 0x0a0d0131, 0x0a0d0131, 0x0a0d0131, 0x0a0d0131, 0x0a0d0131, 0x0ab901a1, 0x0a490191, 0x0a1501a1, 0x0a290181, 0x0b4b01b1, 0x0b670181, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfb400151, 0xfb400151, 0xfb400151, 0xfb400151, 0xfb400151, - 0x0b670181, 0x0b3301b1, 0x0c9f0141, 0x0b2b01a1, 0x0af70171, 0x0af70181, 0x0b2b01b1, 0x0a990181, - 0x0a3d01a1, 0x0af70171, 0x0b670181, 0x0b3301b1, 0x0c9f0141, 0x0c9f0141, 0x0b2b01a1, 0x0af70171, - 0x0ab901b1, 0x0af70171, 0x0b2b01b1, 0x0a990181, 0x0bbf01a1, 0x0c9f0141, 0x0b2b01a1, 0x0a490191, - 0x0af70171, 0x0a910191, 0x0b3301b1, 0x0c9f0141, 0x0b2b01a1, 0x0a3d01a1, 0x0af70171, 0x0b2b01a1, + 0x0b670181, 0x0b3301b1, 0x0c9f0131, 0x0b2b01a1, 0x0af70171, 0x0af70181, 0x0b2b01b1, 0x0a990181, + 0x0a3d01a1, 0x0af70171, 0x0b670181, 0x0b3301b1, 0x0c9f0131, 0x0c9f0131, 0x0b2b01a1, 0x0af70171, + 0x0ab901b1, 0x0af70171, 0x0b2b01b1, 0x0a990181, 0x0bbf01a1, 0x0c9f0131, 0x0b2b01a1, 0x0a490191, + 0x0af70171, 0x0a910191, 0x0b3301b1, 0x0c9f0131, 0x0b2b01a1, 0x0a3d01a1, 0x0af70171, 0x0b2b01a1, 0x0a3d01a1, 0x0b2b01a1, 0x0af70171, 0x0b2b01a1, 0x0a3d01a1, 0x0b2b01a1, 0x0af70171, 0x0b2b01a1, 0x0b2b01a1, 0x0b670191, 0x0af70171, 0x0b2b01b1, 0x0a990181, 0x0b7f01a1, 0x0b7f01a1, 0x0b7f01a1, - 0x0b670181, 0x0b3301b1, 0x0c9f0141, 0x0b2b01a1, 0x0b670181, 0x0b3301b1, 0x0c9f0141, 0x0b2b01a1, - 0x0af70171, 0x0b2b01b1, 0x0b670181, 0x0b3301b1, 0x0c9f0141, 0x0b2b01a1, 0x0af70171, 0x0b2b01b1, + 0x0b670181, 0x0b3301b1, 0x0c9f0131, 0x0b2b01a1, 0x0b670181, 0x0b3301b1, 0x0c9f0131, 0x0b2b01a1, + 0x0af70171, 0x0b2b01b1, 0x0b670181, 0x0b3301b1, 0x0c9f0131, 0x0b2b01a1, 0x0af70171, 0x0b2b01b1, 0x0af70171, 0x0b2b01b1, 0x0a150191, 0x0a290191, 0x0a3d01a1, 0x0a3d01a1, 0x0a3d01b1, 0x0a3d01b1, 0x0a490191, 0x0a990181, 0x0ab901a1, 0x0ab901b1, 0x0ad301b1, 0x0af70181, 0x0af70181, 0x0af70171, 0x0b0301c1, 0x0b0301c1, 0x0b0301c1, 0x0b0301c1, 0x0b2b01a1, 0x0b2b01a1, 0x0b2b01a1, 0x0b670191, @@ -1601,7 +1601,7 @@ const unsigned int collation_table[12800] = 0xffffffff, 0x02110121, 0x02110121, 0x02110121, 0x02110121, 0x021b0131, 0x021b0131, 0x021b0131, 0x022d0131, 0x02340121, 0x02550141, 0xffffffff, 0x02350131, 0x02370131, 0x024e0141, 0x024b0141, 0x02280121, 0x027a0141, 0x027b0131, 0x027e0131, 0x027f0131, 0x02920121, 0x02930121, 0x02a90131, - 0x02a70131, 0x02a20131, 0x039f0141, 0x02210131, 0x03a30131, 0x03a50131, 0x03a40131, 0xffffffff, + 0x02a70131, 0x02a20131, 0x039f0141, 0x02210121, 0x03a30131, 0x03a50131, 0x03a40131, 0xffffffff, 0x02a60131, 0x09e00131, 0x02aa0131, 0x02a10131, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00006831, 0x00006821, 0x00006921, 0xffffffff, 0x00006a21, 0xffffffff, 0x00006b31, 0x00006b21, 0x00006c31, 0x00006c21, 0x00006d31, 0x00006d21, 0x00006e31, 0x00006e21, 0x00006f31, 0x00006f21, @@ -1622,8 +1622,8 @@ const unsigned int collation_table[12800] = 0x0f480141, 0x0f490161, 0x0f490151, 0x0f490131, 0x0f490141, 0x0f2d0151, 0x0f2d0141, 0x0f2d0151, 0x0f2d0141, 0x0f2d0151, 0x0f2d0141, 0x0f2d0151, 0x0f2d0141, 0xffffffff, 0xffffffff, 0x00000000, /* 0xff00 .. 0xffff */ - 0xffffffff, 0x024b0121, 0x02700121, 0x02a90121, 0x09e00121, 0x02aa0121, 0x02a70121, 0x02690121, - 0x027a0121, 0x027b0121, 0x02a20121, 0x039f0121, 0x022d0121, 0x02210121, 0x02550121, 0x02a40121, + 0xffffffff, 0x024b0121, 0x02700121, 0x02a90121, 0x09e00121, 0x02aa0121, 0x02a70121, 0x02690111, + 0x027a0121, 0x027b0121, 0x02a20121, 0x039f0121, 0x022d0121, 0x02210111, 0x02550121, 0x02a40121, 0x0a0b0121, 0x0a0c0121, 0x0a0d0121, 0x0a0e0121, 0x0a0f0121, 0x0a100121, 0x0a110121, 0x0a120121, 0x0a130121, 0x0a140121, 0x02370121, 0x02350121, 0x03a30121, 0x03a40121, 0x03a50121, 0x024e0121, 0x02a10121, 0x0a150161, 0x0a290151, 0x0a3d0161, 0x0a490161, 0x0a650161, 0x0a910161, 0x0a990161, diff --git a/libs/wine/ldt.c b/libs/wine/ldt.c index ceb8db423f8..def759a12f5 100644 --- a/libs/wine/ldt.c +++ b/libs/wine/ldt.c @@ -119,6 +119,8 @@ extern int i386_set_ldt(int, union descriptor *, int); #ifdef __APPLE__ #include +#include +static pthread_mutex_t ldt_mutex = PTHREAD_MUTEX_INITIALIZER; #endif #endif /* __i386__ */ @@ -230,8 +232,10 @@ static int internal_set_entry( unsigned short sel, const LDT_ENTRY *entry ) if ((ret = sysi86(SI86DSCR, &ldt_mod)) == -1) perror("sysi86"); } #elif defined(__APPLE__) + pthread_mutex_lock(&ldt_mutex); if ((ret = i386_set_ldt(index, (union ldt_entry *)entry, 1)) < 0) perror("i386_set_ldt"); + pthread_mutex_unlock(&ldt_mutex); #else fprintf( stderr, "No LDT support on this platform\n" ); exit(1); diff --git a/loader/Makefile.in b/loader/Makefile.in index 2b3d457c564..5254537c7ad 100644 --- a/loader/Makefile.in +++ b/loader/Makefile.in @@ -54,14 +54,14 @@ $(MODULE): $(MAIN_BINARY) install:: $(WINE_BINARIES) $(MANPAGES) $(INSTALLDIRS) for f in $(WINE_BINARIES); do \ if [ "$(MAIN_BINARY)" = "$$f" ]; \ - then $(INSTALL_PROGRAM) $$f $(DESTDIR)$(bindir)/$(MODULE); \ + then $(INSTALL_PROGRAM) $$f $(DESTDIR)$(bindir)/wineloader; \ else $(INSTALL_PROGRAM) $$f $(DESTDIR)$(bindir)/$$f; \ fi; \ done $(INSTALL_DATA) wine.man $(DESTDIR)$(mandir)/man$(prog_manext)/wine.$(prog_manext) uninstall:: - -cd $(DESTDIR)$(bindir) && $(RM) $(WINE_BINARIES) $(MODULE) + -cd $(DESTDIR)$(bindir) && $(RM) $(WINE_BINARIES) wineloader $(RM) $(DESTDIR)$(mandir)/man$(prog_manext)/wine.$(prog_manext) clean:: diff --git a/loader/main.c b/loader/main.c index 5e0f330caa4..1d39aae94ef 100644 --- a/loader/main.c +++ b/loader/main.c @@ -31,14 +31,15 @@ #include "main.h" #ifdef __APPLE__ - -asm(".zerofill WINE_DOS, WINE_DOS, ___wine_dos, 0x60000000"); +asm(".zerofill WINE_DOS, WINE_DOS, ___wine_dos, 0x50100000"); +asm(".zerofill WINE_OLE32, WINE_OLE32, ___wine_ole32, 0x100000"); asm(".zerofill WINE_SHARED_HEAP, WINE_SHARED_HEAP, ___wine_shared_heap, 0x02000000"); -extern char __wine_dos[0x60000000], __wine_shared_heap[0x02000000]; +extern char __wine_dos[0x50100000], __wine_ole32[0x100000], __wine_shared_heap[0x02000000]; static const struct wine_preload_info wine_main_preload_info[] = { { __wine_dos, sizeof(__wine_dos) }, /* DOS area + PE exe */ + { __wine_ole32, sizeof(__wine_ole32) }, /* For ole32 to always load at the same address */ { __wine_shared_heap, sizeof(__wine_shared_heap) }, /* shared user data + shared heap */ { 0, 0 } /* end of list */ }; diff --git a/loader/preloader.c b/loader/preloader.c index 0034e9a948c..b7043bd0e89 100644 --- a/loader/preloader.c +++ b/loader/preloader.c @@ -108,7 +108,7 @@ static struct wine_preload_info preload_info[] = { - { (void *)0x00000000, 0x60000000 }, /* low memory area */ + { (void *)0x00000000, 0x68000000 }, /* low memory area */ { (void *)0x7f000000, 0x02000000 }, /* top-down allocations + shared heap */ { 0, 0 }, /* PE exe range set with WINEPRELOADRESERVE */ { 0, 0 } /* end of list */ diff --git a/programs/Makefile.in b/programs/Makefile.in index f164c0b90cd..a857731f4b0 100644 --- a/programs/Makefile.in +++ b/programs/Makefile.in @@ -47,22 +47,18 @@ SUBDIRS = \ # Sub-directories to run make install into INSTALLSUBDIRS = \ - clock \ cmd \ control \ eject \ expand \ explorer \ hh \ - icinfo \ iexplore \ msiexec \ notepad \ oleview \ - progman \ regedit \ regsvr32 \ - rpcss \ rundll32 \ spoolsv \ start \ @@ -73,33 +69,16 @@ INSTALLSUBDIRS = \ winecfg \ wineconsole \ winedbg \ - winefile \ winemenubuilder \ - winemine \ winepath \ winevdm \ winhelp \ - winver \ wordpad \ xcopy # Programs to install in bin directory INSTALLPROGS = \ - msiexec \ - notepad \ - progman \ - regedit \ - regsvr32 \ - uninstaller \ - wineboot \ - winebrowser \ - winecfg \ - wineconsole \ - winedbg \ - winefile \ - winemine \ - winepath \ - winhelp + INSTALLDIRS = $(DESTDIR)$(bindir) diff --git a/programs/explorer/systray.c b/programs/explorer/systray.c index b93d209998c..56384c89375 100644 --- a/programs/explorer/systray.c +++ b/programs/explorer/systray.c @@ -248,15 +248,12 @@ static void add_icon(NOTIFYICONDATAW *nid) /* create the adaptor window */ icon->window = CreateWindowEx(WS_EX_TRAYWINDOW, adaptor_classname, adaptor_windowname, - WS_CLIPSIBLINGS | WS_CAPTION, + WS_CLIPSIBLINGS | WS_CAPTION | (hide_systray ? 0 : WS_VISIBLE), CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, NULL, icon); - if (!hide_systray) - ShowWindow(icon->window, SW_SHOWNA); - /* create icon tooltip */ /* Register tooltip classes if this is the first icon */ @@ -382,23 +379,26 @@ static LRESULT WINAPI listener_wndproc(HWND window, UINT msg, static BOOL is_systray_hidden(void) { - const WCHAR show_systray_keyname[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\', - 'X','1','1',' ','D','r','i','v','e','r',0}; - const WCHAR show_systray_valuename[] = {'S','h','o','w','S','y','s','t','r','a','y',0}; + const WCHAR hide_systray_keyname[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\', + 'S','y','s','t','r','a','y',0}; + const WCHAR hide_systray_valuename[] = {'H','i','d','d','e','n',0}; + DWORD hidden; HKEY hkey; + DWORD size; + DWORD type; BOOL ret = FALSE; - /* @@ Wine registry key: HKCU\Software\Wine\X11 Driver */ - if (RegOpenKeyW(HKEY_CURRENT_USER, show_systray_keyname, &hkey) == ERROR_SUCCESS) + /* @@ Wine registry key: HKCU\Software\Wine\Systray */ + if (RegOpenKeyW(HKEY_CURRENT_USER, hide_systray_keyname, &hkey) == ERROR_SUCCESS) { - WCHAR value[10]; - DWORD type, size = sizeof(value); - if (RegQueryValueExW(hkey, show_systray_valuename, 0, &type, (LPBYTE)&value, &size) == ERROR_SUCCESS) + size = sizeof(hidden); + if (RegQueryValueExW(hkey, hide_systray_valuename, 0, &type, (LPBYTE)&hidden, &size) == ERROR_SUCCESS && type == REG_DWORD) { - ret = IS_OPTION_FALSE(value[0]); + if (hidden != 0) ret = TRUE; } RegCloseKey(hkey); } + return ret; } diff --git a/programs/regedit/Pt.rc b/programs/regedit/Pt.rc index c87b99d4b98..3baaeb9fce1 100644 --- a/programs/regedit/Pt.rc +++ b/programs/regedit/Pt.rc @@ -409,6 +409,44 @@ END /*****************************************************************/ + +/* + * Dialog + */ + +LANGUAGE LANG_PORTUGUESE, SUBLANG_NEUTRAL + +IDD_DIALOG1 DIALOG DISCARDABLE 50, 50, 268, 98 +STYLE DS_3DLOOK | DS_CONTROL | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | + WS_BORDER +FONT 8, "MS Shell Dlg" +BEGIN +END + + +LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN + +IDD_DIALOG2 DIALOG DISCARDABLE 0, 0, 187, 95 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "OK",IDOK,130,7,50,14 + PUSHBUTTON "Cancelar",IDCANCEL,130,24,50,14 +END + +LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE + +IDD_DIALOG2 DIALOG DISCARDABLE 0, 0, 187, 95 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Diálogo" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "OK",IDOK,130,7,50,14 + PUSHBUTTON "Cancelar",IDCANCEL,130,24,50,14 +END + + /* * TEXTINCLUDE */ diff --git a/programs/regedit/regedit.c b/programs/regedit/regedit.c index 1ede60ffda5..d923a952b35 100644 --- a/programs/regedit/regedit.c +++ b/programs/regedit/regedit.c @@ -91,6 +91,12 @@ BOOL ProcessCmdLine(LPSTR lpCmdLine) s++; ch = *s; + if (!ch || isspace(ch)) + { + /* this is a file name: '-' */ + s--; + break; + } ch2 = *(s+1); chu = toupper(ch); if (!ch2 || isspace(ch2)) { @@ -169,6 +175,13 @@ BOOL PerformRegAction(REGEDIT_ACTION action, LPSTR s) while(filename[0]) { char* realname = NULL; int size; + + if (strcmp(filename,"-")==0) + { + reg_file=stdin; + goto process; + } + size=SearchPath(NULL,filename,NULL,0,NULL,NULL); if (size>0) { @@ -188,6 +201,7 @@ BOOL PerformRegAction(REGEDIT_ACTION action, LPSTR s) fprintf(stderr,"%s: Can't open file \"%s\"\n", getAppName(), filename); exit(1); } +process: processRegLines(reg_file, doSetValue); if (realname) { diff --git a/programs/regedit/regproc.c b/programs/regedit/regproc.c index 16a2b8c1d65..96913a9c3c0 100644 --- a/programs/regedit/regproc.c +++ b/programs/regedit/regproc.c @@ -1087,11 +1087,22 @@ static void export_hkey(FILE *file, HKEY key, */ static FILE *REGPROC_open_export_file(CHAR *file_name) { - FILE *file = fopen(file_name, "w"); - if (!file) { - perror(""); - fprintf(stderr,"%s: Can't open file \"%s\"\n", getAppName(), file_name); - exit(1); + FILE *file; + + if (strcmp(file_name,"-")==0) + { + file=stdout; + } + else + { + file = fopen(file_name, "w"); + if (!file) + { + perror(""); + fprintf(stderr,"%s: Can't open file \"%s\"\n", + getAppName(), file_name); + exit(1); + } } fputs("REGEDIT4\n", file); return file; diff --git a/programs/taskmgr/taskmgr.c b/programs/taskmgr/taskmgr.c index d59bd19d651..3eef012dae8 100644 --- a/programs/taskmgr/taskmgr.c +++ b/programs/taskmgr/taskmgr.c @@ -155,7 +155,6 @@ static BOOL OnCreate(HWND hWnd) #if 1 hApplicationPage = CreateDialog(hInst, MAKEINTRESOURCE(IDD_APPLICATION_PAGE), hWnd, ApplicationPageWndProc); hProcessPage = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PROCESS_PAGE), hWnd, ProcessPageWndProc); - hPerformancePage = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PERFORMANCE_PAGE), hWnd, PerformancePageWndProc); #else hApplicationPage = CreateDialog(hInst, MAKEINTRESOURCE(IDD_APPLICATION_PAGE), hTabWnd, ApplicationPageWndProc); hProcessPage = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PROCESS_PAGE), hTabWnd, ProcessPageWndProc); @@ -173,11 +172,14 @@ static BOOL OnCreate(HWND hWnd) item.mask = TCIF_TEXT; item.pszText = szTemp; SendMessage(hTabWnd, TCM_INSERTITEM, 1, (LPARAM)&item); + +#if 0 _tcscpy(szTemp, _T("Performance")); memset(&item, 0, sizeof(TCITEM)); item.mask = TCIF_TEXT; item.pszText = szTemp; SendMessage(hTabWnd, TCM_INSERTITEM, 2, (LPARAM)&item); +#endif /* Size everything correctly */ GetClientRect(hWnd, &rc); @@ -404,9 +406,9 @@ static void LoadSettings(void) TaskManagerSettings.ShowProcessesFromAllUsers = FALSE; /* Server-only? */ TaskManagerSettings.Column_ImageName = TRUE; TaskManagerSettings.Column_PID = TRUE; - TaskManagerSettings.Column_CPUUsage = TRUE; - TaskManagerSettings.Column_CPUTime = TRUE; - TaskManagerSettings.Column_MemoryUsage = TRUE; + TaskManagerSettings.Column_CPUUsage = FALSE; + TaskManagerSettings.Column_CPUTime = FALSE; + TaskManagerSettings.Column_MemoryUsage = FALSE; TaskManagerSettings.Column_MemoryUsageDelta = FALSE; TaskManagerSettings.Column_PeakMemoryUsage = FALSE; TaskManagerSettings.Column_PageFaults = FALSE; diff --git a/programs/taskmgr/taskmgr.rc b/programs/taskmgr/taskmgr.rc index 64cb16b98df..a89d66657fb 100644 --- a/programs/taskmgr/taskmgr.rc +++ b/programs/taskmgr/taskmgr.rc @@ -27,6 +27,7 @@ #include "De.rc" #include "En.rc" #include "Fr.rc" +#include "Ja.rc" #include "Ko.rc" #include "Nl.rc" #include "No.rc" diff --git a/programs/uninstaller/Makefile.in b/programs/uninstaller/Makefile.in index 7855811b9cf..5898e54b370 100644 --- a/programs/uninstaller/Makefile.in +++ b/programs/uninstaller/Makefile.in @@ -4,7 +4,8 @@ SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = uninstaller.exe APPMODE = -mconsole -municode -IMPORTS = shlwapi user32 gdi32 advapi32 kernel32 +IMPORTS = advapi32 kernel32 +DELAYIMPORTS = shlwapi user32 gdi32 C_SRCS = \ main.c diff --git a/programs/wineboot/shutdown.c b/programs/wineboot/shutdown.c index 5f8dadf1c1e..6533df147d3 100644 --- a/programs/wineboot/shutdown.c +++ b/programs/wineboot/shutdown.c @@ -23,6 +23,7 @@ #include "winbase.h" #include "winuser.h" #include "tlhelp32.h" +#include "wine/unicode.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(wineboot); @@ -108,6 +109,7 @@ static DWORD_PTR send_end_session_messages( struct window_info *win, UINT count, SendMessageTimeoutW( win[i].hwnd, WM_ENDSESSION, ret, 0, flags, 0, &result ); } +#if 0 /* CODEWEAVERS HACK: avoid killing winewrapper, other processes will be killed in kill_processes */ if (ret) { HANDLE handle = OpenProcess( PROCESS_TERMINATE, FALSE, win[0].pid ); @@ -118,6 +120,7 @@ static DWORD_PTR send_end_session_messages( struct window_info *win, UINT count, CloseHandle( handle ); } } +#endif return ret; } @@ -166,8 +169,12 @@ void kill_processes( BOOL kill_desktop ) process.dwSize = sizeof(process); for (res = Process32FirstW( snapshot, &process ); res; res = Process32NextW( snapshot, &process )) { + static const WCHAR winewrapperW[] = {'w','i','n','e','w','r','a','p','p','e','r',0}; if (process.th32ProcessID == GetCurrentProcessId()) continue; if (process.th32ProcessID == desktop_pid) continue; + /* CODEWEAVERS HACK: don't kill winewrapper so end-of-installation + * detection works properly */ + if (strstrW( process.szExeFile, winewrapperW )) continue; WINE_TRACE("killing process %04x %s\n", process.th32ProcessID, wine_dbgstr_w(process.szExeFile) ); if (!(handle = OpenProcess( PROCESS_TERMINATE, FALSE, process.th32ProcessID ))) diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c index 27babc7525f..58c21ee7dae 100644 --- a/programs/wineboot/wineboot.c +++ b/programs/wineboot/wineboot.c @@ -791,12 +791,35 @@ int main( int argc, char *argv[] ) if (end_session) { - if (!shutdown_close_windows( force )) return 1; + if (!shutdown_close_windows( force )) + { + puts("Cancelled."); /* hack for cxsetup */ + return 1; + } } if (end_session || kill) kill_processes( shutdown ); if (shutdown) return 0; + else /* Codeweavers hack: let reboot.exe do the reboot processing */ + { + static const WCHAR rebootW[] = { '\\','r','e','b','o','o','t','.','e','x','e',0 }; + WCHAR cmdline[MAX_PATH + sizeof(rebootW)/sizeof(WCHAR)]; + PROCESS_INFORMATION pi; + STARTUPINFOW si; + + GetSystemDirectoryW( cmdline, MAX_PATH ); + lstrcatW( cmdline, rebootW ); + memset( &si, 0, sizeof si ); + si.cb = sizeof si; + if (CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi )) + { + CloseHandle( pi.hProcess ); + CloseHandle( pi.hThread ); + return 0; + } + WINE_ERR("Failed to start reboot\n"); + } if (restart) ops = SETUP; diff --git a/programs/winebrowser/main.c b/programs/winebrowser/main.c index 7bea32c9420..ba34768e2bc 100644 --- a/programs/winebrowser/main.c +++ b/programs/winebrowser/main.c @@ -105,8 +105,13 @@ static int open_http_url( const char *url ) static int open_mailto_url( const char *url ) { +#ifdef __APPLE__ + static const char *defaultmailers = + "/usr/bin/open"; +#else static const char *defaultmailers = "xdg-email,mozilla-thunderbird,thunderbird,evolution"; +#endif char mailers[256]; DWORD length, type; diff --git a/programs/winecfg/Pt.rc b/programs/winecfg/Pt.rc index 13d9f565d5e..2d39a1d7ceb 100644 --- a/programs/winecfg/Pt.rc +++ b/programs/winecfg/Pt.rc @@ -232,6 +232,71 @@ END LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN +IDD_DRIVE_EDIT DIALOG DISCARDABLE 0, 0, 203, 169 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Configuração de unidade" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "&OK",ID_BUTTON_OK,145,150,50,13 + LTEXT "Letra:",IDC_STATIC,5,23,26,9 + EDITTEXT IDC_EDIT_LABEL,63,114,78,13,ES_AUTOHSCROLL + LTEXT "Rótulo:",IDC_STATIC_LABEL,33,117,29,12 + LTEXT "Série:",IDC_STATIC_SERIAL,33,127,29,12 + EDITTEXT IDC_EDIT_SERIAL,63,124,78,13,ES_AUTOHSCROLL + LTEXT "Tipo:",IDC_STATIC,5,54,21,10 + EDITTEXT IDC_EDIT_PATH,31,5,117,13,ES_AUTOHSCROLL + LTEXT "Caminho:",IDC_STATIC,5,10,20,9 + COMBOBOX IDC_COMBO_LETTER,31,20,77,60,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Procurar...",IDC_BUTTON_BROWSE_PATH,154,5,40,13 + COMBOBOX IDC_COMBO_TYPE,31,36,77,60,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Mostrar Avançado",IDC_BUTTON_SHOW_HIDE_ADVANCED,134,34,60,16 + CONTROL "Autodetectar do dispositivo:",IDC_RADIO_AUTODETECT,"Button", + BS_AUTORADIOBUTTON,21,79,93,10 + EDITTEXT IDC_EDIT_DEVICE,33,89,108,13,ES_AUTOHSCROLL + PUSHBUTTON "Procurar...",IDC_BUTTON_BROWSE_DEVICE,148,89,40,13 + CONTROL "Associar manualmente:",IDC_RADIO_ASSIGN,"Button", + BS_AUTORADIOBUTTON,21,104,69,10 + GROUPBOX "Rótulo e número de série",IDC_BOX_LABELSERIAL,6,68,189,79 + +END + +LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE + +IDD_DRIVE_EDIT DIALOG DISCARDABLE 0, 0, 203, 169 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Configuração de unidade" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "&OK",ID_BUTTON_OK,145,150,50,13 + LTEXT "Letra:",IDC_STATIC,5,23,26,9 + EDITTEXT IDC_EDIT_LABEL,63,114,78,13,ES_AUTOHSCROLL + LTEXT "Rótulo:",IDC_STATIC_LABEL,33,117,29,12 + LTEXT "Série:",IDC_STATIC_SERIAL,33,127,29,12 + EDITTEXT IDC_EDIT_SERIAL,63,124,78,13,ES_AUTOHSCROLL + LTEXT "Tipo:",IDC_STATIC,5,54,21,10 + EDITTEXT IDC_EDIT_PATH,31,5,117,13,ES_AUTOHSCROLL + LTEXT "Localização:",IDC_STATIC,5,10,20,9 + COMBOBOX IDC_COMBO_LETTER,31,20,77,60,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Procurar...",IDC_BUTTON_BROWSE_PATH,154,5,40,13 + COMBOBOX IDC_COMBO_TYPE,31,36,77,60,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Mostrar Avançado",IDC_BUTTON_SHOW_HIDE_ADVANCED,134,34,60,16 + CONTROL "Autodetectar dispositivo:",IDC_RADIO_AUTODETECT,"Button", + BS_AUTORADIOBUTTON,21,79,93,10 + EDITTEXT IDC_EDIT_DEVICE,33,89,108,13,ES_AUTOHSCROLL + PUSHBUTTON "Procurar...",IDC_BUTTON_BROWSE_DEVICE,148,89,40,13 + CONTROL "Associar manualmente:",IDC_RADIO_ASSIGN,"Button", + BS_AUTORADIOBUTTON,21,104,69,10 + GROUPBOX "Rótulo e número de série",IDC_BOX_LABELSERIAL,6,68,189,79 + +END + + +LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN + IDD_AUDIOCFG DIALOG DISCARDABLE 0, 0, 260, 250 STYLE WS_CHILD | WS_DISABLED FONT 8, "MS Shell Dlg" diff --git a/programs/wineconsole/wineconsole_Pt.rc b/programs/wineconsole/wineconsole_Pt.rc index a54d1f7f160..9242ab6f09d 100644 --- a/programs/wineconsole/wineconsole_Pt.rc +++ b/programs/wineconsole/wineconsole_Pt.rc @@ -104,7 +104,7 @@ FONT 8, "MS Shell Dlg" AUTORADIOBUTTON "&Grande", IDC_OPT_CURSOR_LARGE, 14, 43, 44, 10, WS_TABSTOP GROUPBOX "Controlo", -1, 75, 11, 125, 44, BS_GROUPBOX - LTEXT "Popup Menu", -1, 79, 23, 40, 10 + LTEXT "Menu", -1, 79, 23, 40, 10 AUTOCHECKBOX "&Controlo", IDC_OPT_CONF_CTRL, 129, 23, 60, 10, WS_TABSTOP AUTOCHECKBOX "&Rotação", IDC_OPT_CONF_SHIFT, 129, 33, 60, 10, WS_TABSTOP LTEXT "Edição rápida", -1, 79, 43, 50, 10 diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c index 7c537cab4e7..499dc6cb2a2 100644 --- a/programs/winemenubuilder/winemenubuilder.c +++ b/programs/winemenubuilder/winemenubuilder.c @@ -73,6 +73,8 @@ #include #include +#include "wine/winbase16.h" + #include "wine/unicode.h" #include "wine/debug.h" #include "wine.xpm" @@ -83,7 +85,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(menubuilder); (csidl)==CSIDL_COMMON_DESKTOPDIRECTORY) #define in_startmenu(csidl) ((csidl)==CSIDL_STARTMENU || \ (csidl)==CSIDL_COMMON_STARTMENU) - +static const DWORD locations[] = { + CSIDL_STARTMENU, + CSIDL_COMMON_STARTMENU, + CSIDL_DESKTOPDIRECTORY, + CSIDL_COMMON_DESKTOPDIRECTORY +}; +#define LOCATION_COUNT sizeof(locations)/sizeof(locations[0]) + /* link file formats */ #include "pshpack1.h" @@ -143,6 +152,158 @@ typedef struct * FIXME: should not use stdio */ +#ifdef __APPLE__ + #define CREATE_ICO_FILES 1 +#else + #undef CREATE_ICO_FILES +#endif + +#if CREATE_ICO_FILES + #define EXPORTED_ICON_EXT "ico" +#else + #define EXPORTED_ICON_EXT "xpm" +#endif + + +#if CREATE_ICO_FILES + +static BOOL SaveIconResAsXPM(const BITMAPINFO *pIcon, const char *szICOFileName, LPCWSTR commentW) +{ + BITMAPINFOHEADER* pHdr = (BITMAPINFOHEADER*)pIcon; + FILE* fICOFile; + ICONDIR iconDir; + ICONDIRENTRY dirEntry; + BOOL ret = FALSE; + + fICOFile = fopen(szICOFileName, "w"); + if (!fICOFile) + return FALSE; + + /* Create the directory header */ + iconDir.idReserved = 0; + iconDir.idType = 1; + iconDir.idCount = 1; + if (fwrite(&iconDir, 1, sizeof(iconDir), fICOFile) != sizeof(iconDir)) + goto error; + + /* Create the directory entry */ + dirEntry.bWidth = pHdr->biWidth; + dirEntry.bHeight = pHdr->biHeight / 2; + dirEntry.bColorCount = pHdr->biClrUsed; + dirEntry.bReserved = 0; + dirEntry.wPlanes = pHdr->biPlanes; + dirEntry.wBitCount = pHdr->biBitCount; + dirEntry.dwBytesInRes = pHdr->biSize + pHdr->biClrUsed*sizeof(RGBQUAD) + pHdr->biSizeImage; + dirEntry.dwImageOffset = sizeof(iconDir) + sizeof(dirEntry); + + if (fwrite(&dirEntry, 1, sizeof(dirEntry), fICOFile) != sizeof(dirEntry)) + goto error; + + /* Copy the image */ + if (fwrite(pIcon, 1, dirEntry.dwBytesInRes, fICOFile) != dirEntry.dwBytesInRes) + goto error; + + ret = TRUE; + +error: + fclose(fICOFile); + if (!ret) + unlink(szICOFileName); + return ret; +} + +static BOOL extract_icon_dir(HMODULE hModule, GRPICONDIR* pIconDir, const char *szICOFileName, LPCWSTR commentW) +{ + FILE* fICOFile; + HRSRC hResInfo; + HGLOBAL hResData; + BITMAPINFO *pIcon; + DWORD imageOffset; + int i; + BOOL ret = FALSE; + + fICOFile = fopen(szICOFileName, "w"); + if (!fICOFile) + { + WINE_ERR("fopen(\"%s\", \"w\") failed, errno %d\n", szICOFileName, errno); + return FALSE; + } + + /* Copy the directory header */ + /* The first part of a GRPICONDIR matches an ICONDIR */ + if (fwrite(pIconDir, 1, sizeof(ICONDIR), fICOFile) != sizeof(ICONDIR)) + { + WINE_ERR("fwrite(pIconDir) failed, errno %d\n", errno); + goto error; + } + + imageOffset = sizeof(ICONDIR) + pIconDir->idCount * sizeof(ICONDIRENTRY); + + /* Copy the directory entries */ + for (i = 0; i < pIconDir->idCount; i++) + { + ICONDIRENTRY dirEntry; + /* ICONDIRENTRY and GRPICONDIRENTRY are identical up to the last field */ + memcpy(&dirEntry, &pIconDir->idEntries[i], offsetof(ICONDIRENTRY, dwImageOffset)); + dirEntry.dwImageOffset = imageOffset; + imageOffset += dirEntry.dwBytesInRes; + + if (fwrite(&dirEntry, 1, sizeof(dirEntry), fICOFile) != sizeof(dirEntry)) + { + WINE_ERR("fwrite(dirEntry) failed, i = %d/%d, errno %d\n", i, pIconDir->idCount, errno); + goto error; + } + } + + /* Copy the images */ + for (i = 0; i < pIconDir->idCount; i++) + { + hResInfo = FindResourceW + ( + hModule, + MAKEINTRESOURCEW(pIconDir->idEntries[i].nID), + (LPCWSTR) RT_ICON + ); + if (!hResInfo) + { + WINE_ERR("FindResourceW failed, i = %d/%d, nID = %hd/%p, error %u\n", i, pIconDir->idCount, pIconDir->idEntries[i].nID, MAKEINTRESOURCEW(pIconDir->idEntries[i].nID), GetLastError()); + goto error; + } + + if (!(hResData = LoadResource(hModule, hResInfo))) + { + WINE_ERR("LoadResource failed, i = %d/%d, error %u\n", i, pIconDir->idCount, GetLastError()); + goto error; + } + + if ( + !(pIcon = LockResource(hResData)) || + fwrite(pIcon, 1, pIconDir->idEntries[i].dwBytesInRes, fICOFile) != + pIconDir->idEntries[i].dwBytesInRes + ) + { + if (!pIcon) + WINE_ERR("LockResource failed, i = %d/%d, error %u\n", i, pIconDir->idCount, GetLastError()); + else + WINE_ERR("fwrite failed, i = %d/%d, dwBytesInRes = %u, errno %d\n", i, pIconDir->idCount, pIconDir->idEntries[i].dwBytesInRes, errno); + FreeResource(hResData); + goto error; + } + + FreeResource(hResData); + } + + ret = TRUE; + +error: + fclose(fICOFile); + if (!ret) + unlink(szICOFileName); + return ret; +} + +#else + static BOOL SaveIconResAsXPM(const BITMAPINFO *pIcon, const char *szXPMFileName, LPCWSTR commentW) { FILE *fXPMFile; @@ -248,6 +409,50 @@ static BOOL SaveIconResAsXPM(const BITMAPINFO *pIcon, const char *szXPMFileName, return FALSE; } +static BOOL extract_icon_dir(HMODULE hModule, GRPICONDIR* pIconDir, const char *szXPMFileName, LPCWSTR commentW) +{ + BITMAPINFO *pIcon; + int nMax = 0; + int nMaxBits = 0; + LPCWSTR lpName = NULL; + int i; + HRSRC hResInfo; + HGLOBAL hResData; + BOOL ret = FALSE; + + for (i = 0; i < pIconDir->idCount; i++) + { + if ((pIconDir->idEntries[i].wBitCount >= nMaxBits) && (pIconDir->idEntries[i].wBitCount <= 8)) + { + nMaxBits = pIconDir->idEntries[i].wBitCount; + + if ((pIconDir->idEntries[i].bHeight * pIconDir->idEntries[i].bWidth) >= nMax) + { + lpName = MAKEINTRESOURCEW(pIconDir->idEntries[i].nID); + nMax = pIconDir->idEntries[i].bHeight * pIconDir->idEntries[i].bWidth; + } + } + } + + if ((hResInfo = FindResourceW(hModule, lpName, (LPCWSTR)RT_ICON))) + { + if ((hResData = LoadResource(hModule, hResInfo))) + { + if ((pIcon = LockResource(hResData))) + { + if(SaveIconResAsXPM(pIcon, szXPMFileName, commentW)) + ret = TRUE; + } + + FreeResource(hResData); + } + } + + return ret; +} + +#endif + static BOOL CALLBACK EnumResNameProc(HMODULE hModule, LPCWSTR lpszType, LPWSTR lpszName, LONG_PTR lParam) { ENUMRESSTRUCT *sEnumRes = (ENUMRESSTRUCT *) lParam; @@ -265,14 +470,9 @@ static BOOL extract_icon32(LPCWSTR szFileName, int nIndex, const char *szXPMFile { HMODULE hModule; HRSRC hResInfo; - LPCWSTR lpName = NULL; HGLOBAL hResData; GRPICONDIR *pIconDir; - BITMAPINFO *pIcon; ENUMRESSTRUCT sEnumRes; - int nMax = 0; - int nMaxBits = 0; - int i; BOOL ret = FALSE; hModule = LoadLibraryExW(szFileName, 0, LOAD_LIBRARY_AS_DATAFILE); @@ -286,8 +486,8 @@ static BOOL extract_icon32(LPCWSTR szFileName, int nIndex, const char *szXPMFile if (nIndex < 0) { hResInfo = FindResourceW(hModule, MAKEINTRESOURCEW(-nIndex), (LPCWSTR)RT_GROUP_ICON); - WINE_TRACE("FindResourceW (%s) called, return %p, error %d\n", - wine_dbgstr_w(szFileName), hResInfo, GetLastError()); + WINE_TRACE("FindResourceW (%s, %d/%p) called, return %p, error %d\n", + wine_dbgstr_w(szFileName), -nIndex, MAKEINTRESOURCEW(-nIndex), hResInfo, GetLastError()); } else { @@ -307,19 +507,7 @@ static BOOL extract_icon32(LPCWSTR szFileName, int nIndex, const char *szXPMFile { if ((pIconDir = LockResource(hResData))) { - for (i = 0; i < pIconDir->idCount; i++) - { - if ((pIconDir->idEntries[i].wBitCount >= nMaxBits) && (pIconDir->idEntries[i].wBitCount <= 8)) - { - nMaxBits = pIconDir->idEntries[i].wBitCount; - - if ((pIconDir->idEntries[i].bHeight * pIconDir->idEntries[i].bWidth) >= nMax) - { - lpName = MAKEINTRESOURCEW(pIconDir->idEntries[i].nID); - nMax = pIconDir->idEntries[i].bHeight * pIconDir->idEntries[i].bWidth; - } - } - } + ret = extract_icon_dir(hModule, pIconDir, szXPMFileName, szFileName); } FreeResource(hResData); @@ -331,33 +519,150 @@ static BOOL extract_icon32(LPCWSTR szFileName, int nIndex, const char *szXPMFile FreeLibrary(hModule); return FALSE; } - - if ((hResInfo = FindResourceW(hModule, lpName, (LPCWSTR)RT_ICON))) + + FreeLibrary(hModule); + return ret; +} + +static BOOL extract_icon16(LPCWSTR szFileName, const char *szXPMFileName) +{ + BITMAPINFO *pIcon; + int len; + HINSTANCE16 hInstance16; + HRSRC16 hRsrc; + HGLOBAL16 handle; + char *file_name; + BOOL ret = FALSE; + + len = WideCharToMultiByte(CP_ACP, 0, szFileName, -1, NULL, 0, NULL, NULL); + file_name = HeapAlloc(GetProcessHeap(), 0, len); + WideCharToMultiByte(CP_ACP, 0, szFileName, -1, file_name, len, NULL, NULL); + + if ((hInstance16 = LoadLibrary16(file_name)) >= 32) { - if ((hResData = LoadResource(hModule, hResInfo))) + if ((hRsrc = FindResource16( hInstance16, MAKEINTRESOURCE(1), (LPSTR)RT_ICON ))) { - if ((pIcon = LockResource(hResData))) + if ((handle = LoadResource16( hInstance16, hRsrc ))) { - if(SaveIconResAsXPM(pIcon, szXPMFileName, szFileName)) - ret = TRUE; + if ((pIcon = LockResource16(handle))) + { + if (SaveIconResAsXPM(pIcon, szXPMFileName, szFileName)) + ret = TRUE; + } + FreeResource16( handle ); } - - FreeResource(hResData); } } - FreeLibrary(hModule); + HeapFree(GetProcessHeap(), 0, file_name); + FreeLibrary16( hInstance16); return ret; } static BOOL ExtractFromEXEDLL(LPCWSTR szFileName, int nIndex, const char *szXPMFileName) { - if (!extract_icon32(szFileName, nIndex, szXPMFileName) /*&& - !extract_icon16(szFileName, szXPMFileName)*/) + if (!extract_icon32(szFileName, nIndex, szXPMFileName) && + !extract_icon16(szFileName, szXPMFileName)) return FALSE; return TRUE; } +#if CREATE_ICO_FILES + +static int ExtractFromICO(LPCWSTR szFileName, const char *szICOFileName) +{ + char* szFileNameA; + FILE* fTest; + off_t fileSize, dataSize = 0, imagesStart; + ICONDIR iconDir; + ICONDIRENTRY dirEntry; + int i; + int ret = 0; + + /* Verify that the file seems to be a valid ICO file */ + szFileNameA = wine_get_unix_file_name(szFileName); + if (!(fTest = fopen(szFileNameA, "r"))) + { + WINE_WARN("unable to open '%s' for reading: %s\n", szFileNameA, strerror(errno)); + goto error1; + } + + if (fseek(fTest, 0, SEEK_END)) + { + WINE_WARN("failed to seek to end of '%s': %s\n", szFileNameA, strerror(errno)); + goto error2; + } + if ((fileSize = ftello(fTest)) == -1) + { + WINE_WARN("failed to tell position in '%s': %s\n", szFileNameA, strerror(errno)); + goto error2; + } + if (fseek(fTest, 0, SEEK_SET)) + { + WINE_WARN("failed to seek to beginning of '%s': %s\n", szFileNameA, strerror(errno)); + goto error2; + } + + if (fread(&iconDir, 1, sizeof(iconDir), fTest) != sizeof(iconDir)) + { + WINE_WARN("failed to read %lu bytes from '%s': %s\n", sizeof(iconDir), szFileNameA, strerror(errno)); + goto error2; + } + dataSize += sizeof(iconDir); + + if (iconDir.idReserved != 0 || iconDir.idType != 1) + { + WINE_TRACE("'%s' doesn't seem to be a valid ICO file: idReserved = %hd (should be 0), idType = %hd (should be 1)\n", szFileNameA, iconDir.idReserved, iconDir.idType); + goto error2; + } + + imagesStart = sizeof(iconDir) + iconDir.idCount * sizeof(dirEntry); + for (i = 0; i < iconDir.idCount; i++) + { + if (fread(&dirEntry, 1, sizeof(dirEntry), fTest) != sizeof(dirEntry)) + { + WINE_WARN("failed to read %lu bytes from '%s': %s\n", sizeof(dirEntry), szFileNameA, strerror(errno)); + goto error2; + } + dataSize += sizeof(dirEntry); + + if ( + dirEntry.bWidth == 0 || + dirEntry.bHeight == 0 || + dirEntry.bReserved != 0 || + dirEntry.dwBytesInRes == 0 || + dirEntry.dwBytesInRes > fileSize || + dirEntry.dwImageOffset < imagesStart || + dirEntry.dwImageOffset > fileSize - dirEntry.dwBytesInRes + ) + { + WINE_TRACE("'%s' doesn't seem to be a valid ICO file: for entry %d, bWidth = %d, bHeight = %d, bReserved = %d, dwBytesInRes = %u, dwImageOffset = %u, fileSize = %ld, imagesStart = %ld\n", szFileNameA, i, (int)dirEntry.bWidth, (int)dirEntry.bHeight, (int)dirEntry.bReserved, dirEntry.dwBytesInRes, dirEntry.dwImageOffset, (long)fileSize, (long)imagesStart); + goto error2; + } + dataSize += dirEntry.dwBytesInRes; + } + + if (dataSize > fileSize) + { + WINE_TRACE("'%s' doesn't seem to be a valid ICO file: dataSize = %ld (should be less than fileSize, %ld)\n", szFileNameA, (long)dataSize, (long)fileSize); + goto error2; + } + + /* Seems to be a valid ICO file. Copy it. */ + if (CopyFileA(szFileNameA, szICOFileName, FALSE)) + ret = 1; + else + WINE_ERR("Failed to copy '%s' to '%s', error %u\n", szFileNameA, szICOFileName, GetLastError()); + +error2: + fclose(fTest); +error1: + HeapFree(GetProcessHeap(), 0, szFileNameA); + return ret; +} + +#else + static int ExtractFromICO(LPCWSTR szFileName, const char *szXPMFileName) { FILE *fICOFile; @@ -423,6 +728,8 @@ static int ExtractFromICO(LPCWSTR szFileName, const char *szXPMFileName) return 0; } +#endif + static BOOL create_default_icon( const char *filename, const char* comment ) { FILE *fXPM; @@ -470,7 +777,7 @@ static char *extract_icon( LPCWSTR path, int index) { int nodefault = 1; unsigned short crc; - char *iconsdir, *ico_path, *ico_name, *xpm_path; + char *iconsdir, *ico_path, *ico_name, *new_icon_path; char* s; HKEY hkey; int n; @@ -549,26 +856,26 @@ static char *extract_icon( LPCWSTR path, int index) crc=crc16(ico_path); /* Try to treat the source file as an exe */ - xpm_path=HeapAlloc(GetProcessHeap(), 0, strlen(iconsdir)+1+4+1+strlen(ico_name)+1+12+1+3); - sprintf(xpm_path,"%s/%04x_%s.%d.xpm",iconsdir,crc,ico_name,index); - if (ExtractFromEXEDLL( path, index, xpm_path )) + new_icon_path=HeapAlloc(GetProcessHeap(), 0, strlen(iconsdir)+1+4+1+strlen(ico_name)+1+12+1+3); + sprintf(new_icon_path,"%s/%04x_%s.%d.%s",iconsdir,crc,ico_name,index,EXPORTED_ICON_EXT); + if (ExtractFromEXEDLL( path, index, new_icon_path )) goto end; /* Must be something else, ignore the index in that case */ - sprintf(xpm_path,"%s/%04x_%s.xpm",iconsdir,crc,ico_name); - if (ExtractFromICO( path, xpm_path)) + sprintf(new_icon_path,"%s/%04x_%s.%s",iconsdir,crc,ico_name,EXPORTED_ICON_EXT); + if (ExtractFromICO( path, new_icon_path)) goto end; if (!nodefault) - if (create_default_icon( xpm_path, ico_path )) + if (create_default_icon( new_icon_path, ico_path )) goto end; - HeapFree( GetProcessHeap(), 0, xpm_path ); - xpm_path=NULL; + HeapFree( GetProcessHeap(), 0, new_icon_path ); + new_icon_path=NULL; end: HeapFree(GetProcessHeap(), 0, iconsdir); HeapFree(GetProcessHeap(), 0, ico_path); - return xpm_path; + return new_icon_path; } static BOOL DeferToRunOnce(LPWSTR link) @@ -611,38 +918,18 @@ static BOOL DeferToRunOnce(LPWSTR link) return ! r; } -/* This escapes \ in filenames */ -static LPSTR escape(LPCWSTR arg) +static LPSTR to_utf8(LPCWSTR strW) { - LPSTR narg, x; - LPCWSTR esc; - int len = 0, n; - - esc = arg; - while((esc = strchrW(esc, '\\'))) - { - esc++; - len++; - } + LPSTR str; + int len; - len += WideCharToMultiByte(CP_UNIXCP, 0, arg, -1, NULL, 0, NULL, NULL); - narg = HeapAlloc(GetProcessHeap(), 0, len); - - x = narg; - while (*arg) - { - n = WideCharToMultiByte(CP_UNIXCP, 0, arg, 1, x, len, NULL, NULL); - x += n; - len -= n; - if (*arg == '\\') - *x++='\\'; /* escape \ */ - arg++; - } - *x = 0; - return narg; + len = WideCharToMultiByte(CP_UTF8, 0, strW, -1, NULL, 0, NULL, NULL); + str = HeapAlloc(GetProcessHeap(), 0, len); + WideCharToMultiByte(CP_UTF8, 0, strW, -1, str, len, NULL, NULL); + return str; } -static int fork_and_wait( const char *linker, const char *link_name, const char *path, +static int fork_and_wait( const char *linker, const char *link_root, const char *link_path, const char *path, int desktop, const char *args, const char *icon_name, const char *workdir, const char *description ) { @@ -650,14 +937,17 @@ static int fork_and_wait( const char *linker, const char *link_name, const char const char *argv[20]; int retcode; - WINE_TRACE( "linker app='%s' link='%s' mode=%s " + WINE_TRACE( "linker app='%s' root='%s' link='%s' mode=%s " "path='%s' args='%s' icon='%s' workdir='%s' descr='%s'\n", - linker, link_name, desktop ? "desktop" : "menu", + linker, link_root, link_path, desktop ? "desktop" : "menu", path, args, icon_name, workdir, description ); argv[pos++] = linker ; + argv[pos++] = "--utf8"; + argv[pos++] = "--root"; + argv[pos++] = link_root; argv[pos++] = "--link"; - argv[pos++] = link_name; + argv[pos++] = link_path; argv[pos++] = "--path"; argv[pos++] = path; argv[pos++] = desktop ? "--desktop" : "--menu"; @@ -689,65 +979,19 @@ static int fork_and_wait( const char *linker, const char *link_name, const char return retcode; } -/* Return a heap-allocated copy of the unix format difference between the two - * Windows-format paths. - * locn is the owning location - * link is within locn - */ -static char *relative_path( LPCWSTR link, LPCWSTR locn ) -{ - char *unix_locn, *unix_link; - char *relative = NULL; - - unix_locn = wine_get_unix_file_name(locn); - unix_link = wine_get_unix_file_name(link); - if (unix_locn && unix_link) - { - size_t len_unix_locn, len_unix_link; - len_unix_locn = strlen (unix_locn); - len_unix_link = strlen (unix_link); - if (len_unix_locn < len_unix_link && memcmp (unix_locn, unix_link, len_unix_locn) == 0 && unix_link[len_unix_locn] == '/') - { - size_t len_rel; - char *p = strrchr (unix_link + len_unix_locn, '/'); - p = strrchr (p, '.'); - if (p) - { - *p = '\0'; - len_unix_link = p - unix_link; - } - len_rel = len_unix_link - len_unix_locn; - relative = HeapAlloc(GetProcessHeap(), 0, len_rel); - if (relative) - { - memcpy (relative, unix_link + len_unix_locn + 1, len_rel); - } - } - } - if (!relative) - WINE_WARN("Could not separate the relative link path of %s in %s\n", wine_dbgstr_w(link), wine_dbgstr_w(locn)); - HeapFree(GetProcessHeap(), 0, unix_locn); - HeapFree(GetProcessHeap(), 0, unix_link); - return relative; -} - /*********************************************************************** * * GetLinkLocation * * returns TRUE if successful - * *loc will contain CS_DESKTOPDIRECTORY, CS_STARTMENU, CS_STARTUP etc. + * *loc will contain CS_DESKTOPDIRECTORY, CS_STARTMENU, etc. * *relative will contain the address of a heap-allocated copy of the portion * of the filename that is within the specified location, in unix form */ -static BOOL GetLinkLocation( LPCWSTR linkfile, DWORD *loc, char **relative ) +static BOOL GetLinkLocation( LPCWSTR linkfile, DWORD *loc, WCHAR* *root ) { WCHAR filename[MAX_PATH], buffer[MAX_PATH]; DWORD len, i, r, filelen; - const DWORD locations[] = { - CSIDL_STARTUP, CSIDL_DESKTOPDIRECTORY, CSIDL_STARTMENU, - CSIDL_COMMON_STARTUP, CSIDL_COMMON_DESKTOPDIRECTORY, - CSIDL_COMMON_STARTMENU }; WINE_TRACE("%s\n", wine_dbgstr_w(linkfile)); filelen=GetFullPathNameW( linkfile, MAX_PATH, filename, NULL ); @@ -756,7 +1000,7 @@ static BOOL GetLinkLocation( LPCWSTR linkfile, DWORD *loc, char **relative ) WINE_TRACE("%s\n", wine_dbgstr_w(filename)); - for( i=0; i= 5 && lstrcmpiW(item.cFileName+len-4, wLNK)==0)) + { + lstrcpyW(path+lendir+1, item.cFileName); + if (item.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if (!(item.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) /* skip symlinks */ + { + if (!Process_Dir(path)) + rc=FALSE; + } + } + else + { + WINE_TRACE(" link %s\n", wine_dbgstr_w(path)); + if (!Process_Link(path, FALSE)) + rc=FALSE; + } + } + } + + if (!FindNextFileW(hFind, &item)) + { + if (GetLastError() != ERROR_NO_MORE_FILES) + { + WINE_TRACE("got error %d while scanning the '%s' directory\n", GetLastError(), wine_dbgstr_w(dir)); + rc=FALSE; + } + FindClose(hFind); + break; + } + } + + HeapFree(GetProcessHeap(), 0, path); + return rc; +} + +static BOOL Process_All_Links() +{ + WCHAR dir[MAX_PATH+2]; /* +2 for Process_Dir */ + DWORD i, len; + BOOL rc; + + rc=TRUE; + for (i = 0; i < LOCATION_COUNT; i++) + { + if (!SHGetSpecialFolderPathW(0, dir, locations[i], FALSE)) + { + WINE_TRACE("unable to get the path of folder %08x\n", locations[i]); + /* Some special folders are not defined in some bottles + * so this is not an error + */ + continue; + } + + len = lstrlenW(dir); + if (len >= MAX_PATH) + { + /* We've just trashed memory! Hopefully we are OK */ + WINE_TRACE("Ignoring special folder %08x because its path is too long: %s\n", locations[i], wine_dbgstr_w(dir)); + rc=FALSE; + continue; + } + + if (!Process_Dir(dir)) + rc=FALSE; + } + return rc; +} static CHAR *next_token( LPSTR *p ) { @@ -1165,6 +1478,14 @@ int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show break; if( !lstrcmpA( token, "-r" ) ) bAgain = TRUE; + else if( !lstrcmpA( token, "-a" ) ) + { + if (!Process_All_Links()) + { + WINE_ERR("failed to build some menu items\n"); + ret = 1; + } + } else if( token[0] == '-' ) { WINE_ERR( "unknown option %s\n",token); -- 2.11.4.GIT