From 246dbaf363d7b3308adb1eae9dc888c13bb8b585 Mon Sep 17 00:00:00 2001 From: Jan Zerebecki Date: Thu, 21 Aug 2008 07:21:59 +0200 Subject: [PATCH] push d2761731c253bfe9a5961252b22d8cea093833f5 --- configure | 303 ++++ configure.ac | 4 +- dlls/appwiz.cpl/No.rc | 79 + dlls/appwiz.cpl/appwiz.rc | 1 + dlls/crypt32/decode.c | 131 +- dlls/crypt32/encode.c | 94 +- dlls/crypt32/msg.c | 67 +- dlls/crypt32/tests/encode.c | 318 ++++ dlls/crypt32/tests/msg.c | 20 + dlls/d3d8/d3d8_private.h | 4 +- dlls/d3d8/device.c | 12 +- dlls/d3d9/tests/visual.c | 120 ++ dlls/d3dx8/d3dx8.spec | 2 +- dlls/d3dx8/mesh.c | 70 + dlls/d3dx8/tests/mesh.c | 51 +- dlls/d3dxof/d3dxof.c | 12 - dlls/ddraw/ddraw.c | 1 - dlls/ddraw/utils.c | 5 + dlls/dinput/keyboard.c | 26 +- dlls/dinput/mouse.c | 39 +- dlls/dplayx/dplay.c | 30 + dlls/dplayx/tests/dplayx.c | 3251 +++++++++++++++++++++++++++++++++- dlls/kernel32/comm.c | 2 +- dlls/kernel32/profile.c | 37 +- dlls/kernel32/tests/profile.c | 38 + dlls/mstask/tests/Makefile.in | 1 + dlls/mstask/tests/task.c | 239 +++ dlls/msvcirt/msvcirt.c | 58 + dlls/msvcirt/msvcirt.spec | 6 +- dlls/ntdll/file.c | 20 + dlls/ntdll/threadpool.c | 1 + dlls/ole32/tests/marshal.c | 23 +- dlls/secur32/secur32.c | 8 +- dlls/secur32/tests/secur32.c | 12 +- dlls/user32/menu.c | 13 +- dlls/user32/tests/input.c | 39 + dlls/user32/tests/win.c | 3 + dlls/winealsa.drv/waveout.c | 2 +- dlls/wined3d/arb_program_shader.c | 314 +++- dlls/wined3d/ati_fragment_shader.c | 16 +- dlls/wined3d/baseshader.c | 18 +- dlls/wined3d/context.c | 14 +- dlls/wined3d/device.c | 23 +- dlls/wined3d/directx.c | 226 ++- dlls/wined3d/glsl_shader.c | 18 + dlls/wined3d/nvidia_texture_shader.c | 7 + dlls/wined3d/state.c | 5 + dlls/wined3d/surface.c | 87 +- dlls/wined3d/utils.c | 38 +- dlls/wined3d/wined3d_private.h | 17 + dlls/winedos/vga.c | 1 + dlls/winedos/vxd.c | 2 + dlls/wineoss.drv/audio.c | 2 + dlls/winhttp/Makefile.in | 1 + dlls/winhttp/main.c | 24 - dlls/winhttp/request.c | 515 ++++++ dlls/winhttp/session.c | 29 +- dlls/winhttp/tests/winhttp.c | 261 ++- dlls/winhttp/winhttp.spec | 2 +- dlls/winhttp/winhttp_private.h | 9 +- include/Makefile.in | 1 + include/config.h.in | 9 + include/d3drmobj.h | 173 ++ include/d3dx8mesh.h | 1 + include/mstask.idl | 31 + include/wincrypt.h | 69 +- include/winerror.h | 43 + programs/regedit/childwnd.c | 78 + programs/regedit/edit.c | 30 +- programs/regedit/framewnd.c | 62 +- programs/regedit/main.c | 13 + programs/regedit/main.h | 18 +- programs/regedit/regproc.c | 15 +- programs/regedit/regproc.h | 1 + programs/regedit/treeview.c | 59 + programs/uninstaller/Bg.rc | 18 - programs/uninstaller/Da.rc | 18 - programs/uninstaller/De.rc | 17 - programs/uninstaller/En.rc | 18 - programs/uninstaller/Eo.rc | 18 - programs/uninstaller/Es.rc | 18 - programs/uninstaller/Fi.rc | 18 - programs/uninstaller/Fr.rc | 18 - programs/uninstaller/Hu.rc | 18 - programs/uninstaller/It.rc | 18 - programs/uninstaller/Ko.rc | 18 - programs/uninstaller/Makefile.in | 2 +- programs/uninstaller/Nl.rc | 18 - programs/uninstaller/No.rc | 18 - programs/uninstaller/Pl.rc | 18 - programs/uninstaller/Pt.rc | 17 - programs/uninstaller/Ru.rc | 18 - programs/uninstaller/Si.rc | 18 - programs/uninstaller/Sv.rc | 18 - programs/uninstaller/Tr.rc | 18 - programs/uninstaller/main.c | 126 +- programs/uninstaller/resource.h | 14 +- programs/uninstaller/rsrc.rc | 5 - programs/uninstaller/uninstaller.ico | Bin 766 -> 0 bytes tools/winapi/msvcmaker | 2 +- 100 files changed, 6901 insertions(+), 962 deletions(-) create mode 100644 dlls/appwiz.cpl/No.rc create mode 100644 dlls/mstask/tests/task.c create mode 100644 dlls/winhttp/request.c create mode 100644 include/d3drmobj.h delete mode 100644 programs/uninstaller/uninstaller.ico diff --git a/configure b/configure index dabc0a79cb5..ba1f97c2563 100755 --- a/configure +++ b/configure @@ -21257,6 +21257,309 @@ _ACEOF fi +{ echo "$as_me:$LINENO: checking for struct stat.st_mtim" >&5 +echo $ECHO_N "checking for struct stat.st_mtim... $ECHO_C" >&6; } +if test "${ac_cv_member_struct_stat_st_mtim+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (ac_aggr.st_mtim) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_member_struct_stat_st_mtim=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (sizeof ac_aggr.st_mtim) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_member_struct_stat_st_mtim=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_member_struct_stat_st_mtim=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_member_struct_stat_st_mtim" >&5 +echo "${ECHO_T}$ac_cv_member_struct_stat_st_mtim" >&6; } +if test $ac_cv_member_struct_stat_st_mtim = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_STAT_ST_MTIM 1 +_ACEOF + + +fi +{ echo "$as_me:$LINENO: checking for struct stat.st_ctim" >&5 +echo $ECHO_N "checking for struct stat.st_ctim... $ECHO_C" >&6; } +if test "${ac_cv_member_struct_stat_st_ctim+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (ac_aggr.st_ctim) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_member_struct_stat_st_ctim=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (sizeof ac_aggr.st_ctim) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_member_struct_stat_st_ctim=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_member_struct_stat_st_ctim=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_member_struct_stat_st_ctim" >&5 +echo "${ECHO_T}$ac_cv_member_struct_stat_st_ctim" >&6; } +if test $ac_cv_member_struct_stat_st_ctim = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_STAT_ST_CTIM 1 +_ACEOF + + +fi +{ echo "$as_me:$LINENO: checking for struct stat.st_atim" >&5 +echo $ECHO_N "checking for struct stat.st_atim... $ECHO_C" >&6; } +if test "${ac_cv_member_struct_stat_st_atim+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (ac_aggr.st_atim) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_member_struct_stat_st_atim=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (sizeof ac_aggr.st_atim) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_member_struct_stat_st_atim=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_member_struct_stat_st_atim=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_member_struct_stat_st_atim" >&5 +echo "${ECHO_T}$ac_cv_member_struct_stat_st_atim" >&6; } +if test $ac_cv_member_struct_stat_st_atim = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_STAT_ST_ATIM 1 +_ACEOF + + +fi { echo "$as_me:$LINENO: checking for struct sockaddr_in6.sin6_scope_id" >&5 diff --git a/configure.ac b/configure.ac index af8a9cb5243..d50d872abe7 100644 --- a/configure.ac +++ b/configure.ac @@ -1606,8 +1606,8 @@ AC_CHECK_MEMBERS([struct option.name],,, #include #endif]) -dnl Check for stat.st_blocks -AC_CHECK_MEMBERS([struct stat.st_blocks]) +dnl Check for stat.st_blocks and ns-resolved times +AC_CHECK_MEMBERS([struct stat.st_blocks,struct stat.st_mtim,struct stat.st_ctim,struct stat.st_atim]) dnl Check for sin6_scope_id AC_CHECK_MEMBERS([struct sockaddr_in6.sin6_scope_id],,, diff --git a/dlls/appwiz.cpl/No.rc b/dlls/appwiz.cpl/No.rc new file mode 100644 index 00000000000..43f503c82f1 --- /dev/null +++ b/dlls/appwiz.cpl/No.rc @@ -0,0 +1,79 @@ +/* +* Add/Remove Programs Norwegian Bokmål resources +* +* Copyright 2008 Alexander N. Sørnes +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA +* +*/ + +LANGUAGE LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL + +STRINGTABLE +{ + IDS_CPL_TITLE, "Legg til/Fjern programmer" + IDS_CPL_DESC, "Lar deg installere ny programvare eller fjerne installerte programmer." + IDS_TAB1_TITLE, "Programmer" + + IDS_UNINSTALL_FAILED, "Klarte ikke kjøre avinstalleringsprogrammet, «%s». Vil du fjerne oppføringen fra listen over installerte programmer?" + IDS_NOT_SPECIFIED, "Ikke oppgitt" + + IDS_COLUMN_NAME, "Navn" + IDS_COLUMN_PUBLISHER, "Utgiver" + IDS_COLUMN_VERSION, "Versjon" +} + +/* TODO: it's best to use the constant WC_LISTVIEW instead of SysListView32 directly, but the Wine resource compiler doesn't seem to like that... */ + +IDD_MAIN DIALOG 0, 0, 320, 220 +STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Installer/Avinstaller" +FONT 8, "MS Sans Serif" +{ + CONTROL "Trykk «Installer» for å installere et program fra en diskett, CD-stasjon eller annet medium.", 1000, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 40, 7, 270, 20 + CONTROL "&Installer ...", IDC_INSTALL, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 246, 26, 64, 14 + CONTROL "", -1, "STATIC", SS_LEFT | SS_SUNKEN | WS_CHILD | WS_VISIBLE, 7, 46, 303, 1 + CONTROL 2, 1001, "STATIC", SS_ICON | WS_CHILD | WS_VISIBLE, 7, 7, 21, 20 + CONTROL "Følgende programmer kan fjernes automatisk. Merk et program og trykk «Legg til/Fjern» for å fjerne det eller endre installerte komponenter", 1002, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 40, 57, 270, 30 + CONTROL "", IDL_PROGRAMS, "SysListView32", LVS_REPORT | LVS_SINGLESEL | LVS_SORTASCENDING | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 7, 90, 303, 100 + CONTROL "Legg til/Fje&rn ...", IDC_ADDREMOVE, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 246, 198, 64, 14 + CONTROL "&Støtteinformasjon ...", IDC_SUPPORT_INFO, "button", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 170, 198, 70, 14 + CONTROL 3, 1003, "STATIC", SS_ICON | WS_CHILD | WS_VISIBLE, 7, 57, 21, 20 +} + +IDD_INFO DIALOG 0, 0, 256, 138 +STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Støtteinformasjon" +FONT 8, "MS Sans Serif" +{ + CONTROL "OK", IDOK, "BUTTON", BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 103, 116, 50, 14 + CONTROL "Følgende informasjon kan brukes til å få teknisk støtte for %s:", IDC_INFO_LABEL, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 12, 9, 228, 19 + CONTROL "Utgiver:", -1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 16, 30, 60, 8 + CONTROL "Versjon:", -1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 16, 40, 60, 8 + CONTROL "Kontakt:", -1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 16, 50, 60, 8 + CONTROL "Støtteinformasjon:", -1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 16, 60, 64, 8 + CONTROL "Kundestøtte, tlf:", -1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 16, 70, 68, 8 + CONTROL "Lesmeg-fil:", -1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 16, 80, 60, 8 + CONTROL "Produktoppdateringer:", -1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 16, 90, 60, 8 + CONTROL "Kommentarer:", -1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 16, 100, 60, 8 + CONTROL "", IDC_INFO_PUBLISHER, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 104, 30, 136, 8 + CONTROL "", IDC_INFO_VERSION, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 104, 40, 136, 8 + CONTROL "", IDC_INFO_CONTACT, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 104, 50, 136, 8 + CONTROL "", IDC_INFO_SUPPORT, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 104, 60, 136, 8 + CONTROL "", IDC_INFO_PHONE, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 104, 70, 136, 8 + CONTROL "", IDC_INFO_README, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 104, 80, 136, 8 + CONTROL "", IDC_INFO_UPDATES, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 104, 90, 136, 8 + CONTROL "", IDC_INFO_COMMENTS, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 104, 100, 136, 8 +} diff --git a/dlls/appwiz.cpl/appwiz.rc b/dlls/appwiz.cpl/appwiz.rc index 8b88911b9b6..b4a8dd5434d 100644 --- a/dlls/appwiz.cpl/appwiz.rc +++ b/dlls/appwiz.cpl/appwiz.rc @@ -27,6 +27,7 @@ #include "En.rc" #include "Nl.rc" +#include "No.rc" LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL diff --git a/dlls/crypt32/decode.c b/dlls/crypt32/decode.c index 89c62eea6c4..1f5348c924f 100644 --- a/dlls/crypt32/decode.c +++ b/dlls/crypt32/decode.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2007 Juan Lang + * Copyright 2005-2008 Juan Lang * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -231,6 +231,8 @@ static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags, SetLastError(ERROR_MORE_DATA); ret = FALSE; } + else + *pcbStructInfo = bytesNeeded; return ret; } @@ -4321,6 +4323,130 @@ static BOOL WINAPI CRYPT_AsnDecodePKCSSignerInfo(DWORD dwCertEncodingType, return ret; } +static BOOL CRYPT_AsnDecodeCMSSignerId(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + CERT_ID *id = (CERT_ID *)pvStructInfo; + BOOL ret = FALSE; + + if (*pbEncoded == ASN_SEQUENCEOF) + { + ret = CRYPT_AsnDecodeIssuerSerialNumber(pbEncoded, cbEncoded, dwFlags, + id ? &id->u.IssuerSerialNumber : NULL, pcbStructInfo, pcbDecoded); + if (ret) + { + if (id) + id->dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; + if (*pcbStructInfo > sizeof(CERT_ISSUER_SERIAL_NUMBER)) + *pcbStructInfo = sizeof(CERT_ID) + *pcbStructInfo - + sizeof(CERT_ISSUER_SERIAL_NUMBER); + else + *pcbStructInfo = sizeof(CERT_ID); + } + } + else if (*pbEncoded == (ASN_CONTEXT | 0)) + { + ret = CRYPT_AsnDecodeOctetsInternal(pbEncoded, cbEncoded, dwFlags, + id ? &id->u.KeyId : NULL, pcbStructInfo, pcbDecoded); + if (ret) + { + if (id) + id->dwIdChoice = CERT_ID_KEY_IDENTIFIER; + if (*pcbStructInfo > sizeof(CRYPT_DATA_BLOB)) + *pcbStructInfo = sizeof(CERT_ID) + *pcbStructInfo - + sizeof(CRYPT_DATA_BLOB); + else + *pcbStructInfo = sizeof(CERT_ID); + } + } + else + SetLastError(CRYPT_E_ASN1_BADTAG); + return ret; +} + +static BOOL CRYPT_AsnDecodeCMSSignerInfoInternal(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + CMSG_CMS_SIGNER_INFO *info = (CMSG_CMS_SIGNER_INFO *)pvStructInfo; + struct AsnDecodeSequenceItem items[] = { + { ASN_INTEGER, offsetof(CMSG_CMS_SIGNER_INFO, dwVersion), + CRYPT_AsnDecodeIntInternal, sizeof(DWORD), FALSE, FALSE, 0, 0 }, + { 0, offsetof(CMSG_CMS_SIGNER_INFO, SignerId), + CRYPT_AsnDecodeCMSSignerId, sizeof(CERT_ID), FALSE, TRUE, + offsetof(CMSG_CMS_SIGNER_INFO, SignerId.u.KeyId.pbData), 0 }, + { ASN_SEQUENCEOF, offsetof(CMSG_CMS_SIGNER_INFO, HashAlgorithm), + CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER), + FALSE, TRUE, offsetof(CMSG_CMS_SIGNER_INFO, HashAlgorithm.pszObjId), 0 }, + { ASN_CONSTRUCTOR | ASN_CONTEXT | 0, + offsetof(CMSG_CMS_SIGNER_INFO, AuthAttrs), + CRYPT_AsnDecodePKCSAttributesInternal, sizeof(CRYPT_ATTRIBUTES), + TRUE, TRUE, offsetof(CMSG_CMS_SIGNER_INFO, AuthAttrs.rgAttr), 0 }, + { ASN_SEQUENCEOF, offsetof(CMSG_CMS_SIGNER_INFO, HashEncryptionAlgorithm), + CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER), + FALSE, TRUE, offsetof(CMSG_CMS_SIGNER_INFO, + HashEncryptionAlgorithm.pszObjId), 0 }, + { ASN_OCTETSTRING, offsetof(CMSG_CMS_SIGNER_INFO, EncryptedHash), + CRYPT_AsnDecodeOctetsInternal, sizeof(CRYPT_DER_BLOB), + FALSE, TRUE, offsetof(CMSG_CMS_SIGNER_INFO, EncryptedHash.pbData), 0 }, + { ASN_CONSTRUCTOR | ASN_CONTEXT | 1, + offsetof(CMSG_CMS_SIGNER_INFO, UnauthAttrs), + CRYPT_AsnDecodePKCSAttributesInternal, sizeof(CRYPT_ATTRIBUTES), + TRUE, TRUE, offsetof(CMSG_CMS_SIGNER_INFO, UnauthAttrs.rgAttr), 0 }, + }; + BOOL ret; + + TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo); + + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo, + pcbDecoded, info ? info->SignerId.u.KeyId.pbData : NULL); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeCMSSignerInfo(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = FALSE; + + TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + __TRY + { + ret = CRYPT_AsnDecodeCMSSignerInfoInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pcbStructInfo, NULL); + if (ret && pvStructInfo) + { + ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo, + pcbStructInfo, *pcbStructInfo); + if (ret) + { + CMSG_CMS_SIGNER_INFO *info; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + info = (CMSG_CMS_SIGNER_INFO *)pvStructInfo; + info->SignerId.u.KeyId.pbData = ((BYTE *)info + + sizeof(CMSG_CMS_SIGNER_INFO)); + ret = CRYPT_AsnDecodeCMSSignerInfoInternal(pbEncoded, + cbEncoded, dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo, + pcbStructInfo, NULL); + } + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + } + __ENDTRY + TRACE("returning %d\n", ret); + return ret; +} + static BOOL CRYPT_DecodeSignerArray(const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) { @@ -4489,6 +4615,9 @@ static CryptDecodeObjectExFunc CRYPT_GetBuiltinDecoder(DWORD dwCertEncodingType, case LOWORD(PKCS7_SIGNER_INFO): decodeFunc = CRYPT_AsnDecodePKCSSignerInfo; break; + case LOWORD(CMS_SIGNER_INFO): + decodeFunc = CRYPT_AsnDecodeCMSSignerInfo; + break; } } else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS)) diff --git a/dlls/crypt32/encode.c b/dlls/crypt32/encode.c index 0d62b02f744..16b4bb86871 100644 --- a/dlls/crypt32/encode.c +++ b/dlls/crypt32/encode.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2007 Juan Lang + * Copyright 2005-2008 Juan Lang * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -3419,6 +3419,95 @@ static BOOL WINAPI CRYPT_AsnEncodePKCSSignerInfo(DWORD dwCertEncodingType, return ret; } +static BOOL WINAPI CRYPT_AsnEncodeCMSSignerInfo(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + BOOL ret = FALSE; + + if (!(dwCertEncodingType & PKCS_7_ASN_ENCODING)) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + + __TRY + { + const CMSG_CMS_SIGNER_INFO *info = (const CMSG_CMS_SIGNER_INFO *)pvStructInfo; + + if (info->SignerId.dwIdChoice != CERT_ID_ISSUER_SERIAL_NUMBER && + info->SignerId.dwIdChoice != CERT_ID_KEY_IDENTIFIER) + SetLastError(E_INVALIDARG); + else if (info->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER && + !info->SignerId.u.IssuerSerialNumber.Issuer.cbData) + SetLastError(E_INVALIDARG); + else + { + struct AsnEncodeSequenceItem items[7] = { + { &info->dwVersion, CRYPT_AsnEncodeInt, 0 }, + }; + struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } }; + DWORD cItem = 1, cSwapped = 0; + + if (info->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER) + { + items[cItem].pvStructInfo = + &info->SignerId.u.IssuerSerialNumber.Issuer; + items[cItem].encodeFunc = + CRYPT_AsnEncodeIssuerSerialNumber; + cItem++; + } + else + { + swapped[cSwapped].tag = ASN_CONTEXT | 0; + swapped[cSwapped].pvStructInfo = &info->SignerId.u.KeyId; + swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeOctets; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; + cItem++; + } + items[cItem].pvStructInfo = &info->HashAlgorithm; + items[cItem].encodeFunc = CRYPT_AsnEncodeAlgorithmIdWithNullParams; + cItem++; + if (info->AuthAttrs.cAttr) + { + swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0; + swapped[cSwapped].pvStructInfo = &info->AuthAttrs; + swapped[cSwapped].encodeFunc = CRYPT_AsnEncodePKCSAttributes; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; + cItem++; + } + items[cItem].pvStructInfo = &info->HashEncryptionAlgorithm; + items[cItem].encodeFunc = CRYPT_AsnEncodeAlgorithmIdWithNullParams; + cItem++; + items[cItem].pvStructInfo = &info->EncryptedHash; + items[cItem].encodeFunc = CRYPT_AsnEncodeOctets; + cItem++; + if (info->UnauthAttrs.cAttr) + { + swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 1; + swapped[cSwapped].pvStructInfo = &info->UnauthAttrs; + swapped[cSwapped].encodeFunc = CRYPT_AsnEncodePKCSAttributes; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; + cItem++; + } + ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem, + dwFlags, pEncodePara, pbEncoded, pcbEncoded); + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + } + __ENDTRY + return ret; +} + BOOL CRYPT_AsnEncodePKCSSignedInfo(CRYPT_SIGNED_INFO *signedInfo, void *pvData, DWORD *pcbData) { @@ -3607,6 +3696,9 @@ static CryptEncodeObjectExFunc CRYPT_GetBuiltinEncoder(DWORD dwCertEncodingType, case LOWORD(PKCS7_SIGNER_INFO): encodeFunc = CRYPT_AsnEncodePKCSSignerInfo; break; + case LOWORD(CMS_SIGNER_INFO): + encodeFunc = CRYPT_AsnEncodeCMSSignerInfo; + break; } } else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS)) diff --git a/dlls/crypt32/msg.c b/dlls/crypt32/msg.c index 63121fdd482..12ee8a38b1f 100644 --- a/dlls/crypt32/msg.c +++ b/dlls/crypt32/msg.c @@ -632,20 +632,62 @@ static BOOL CRYPT_IsValidSigner(CMSG_SIGNER_ENCODE_INFO_WITH_CMS *signer) SetLastError(E_INVALIDARG); return FALSE; } - if (signer->cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS)) + if (signer->cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO)) { - FIXME("CMSG_SIGNER_ENCODE_INFO with CMS fields unsupported\n"); - return FALSE; - } - if (!signer->pCertInfo->SerialNumber.cbData) - { - SetLastError(E_INVALIDARG); - return FALSE; + if (!signer->pCertInfo->SerialNumber.cbData) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + if (!signer->pCertInfo->Issuer.cbData) + { + SetLastError(E_INVALIDARG); + return FALSE; + } } - if (!signer->pCertInfo->Issuer.cbData) + else if (signer->cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS)) { - SetLastError(E_INVALIDARG); - return FALSE; + switch (signer->SignerId.dwIdChoice) + { + case 0: + if (!signer->pCertInfo->SerialNumber.cbData) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + if (!signer->pCertInfo->Issuer.cbData) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + break; + case CERT_ID_ISSUER_SERIAL_NUMBER: + if (!signer->SignerId.IssuerSerialNumber.SerialNumber.cbData) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + if (!signer->SignerId.IssuerSerialNumber.Issuer.cbData) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + break; + case CERT_ID_KEY_IDENTIFIER: + if (!signer->SignerId.KeyId.cbData) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + break; + default: + SetLastError(E_INVALIDARG); + } + if (signer->HashEncryptionAlgorithm.pszObjId) + { + FIXME("CMSG_SIGNER_ENCODE_INFO with CMS fields unsupported\n"); + return FALSE; + } } if (!signer->hCryptProv) { @@ -1251,7 +1293,8 @@ static HCRYPTMSG CSignedEncodeMsg_Open(DWORD dwFlags, SetLastError(E_INVALIDARG); return NULL; } - if (info->cbSize == sizeof(CMSG_SIGNED_ENCODE_INFO_WITH_CMS)) + if (info->cbSize == sizeof(CMSG_SIGNED_ENCODE_INFO_WITH_CMS) && + info->rgAttrCertEncoded) { FIXME("CMSG_SIGNED_ENCODE_INFO with CMS fields unsupported\n"); return NULL; diff --git a/dlls/crypt32/tests/encode.c b/dlls/crypt32/tests/encode.c index 49e495592f2..28542aa5e17 100644 --- a/dlls/crypt32/tests/encode.c +++ b/dlls/crypt32/tests/encode.c @@ -5483,6 +5483,322 @@ static void test_decodePKCSSignerInfo(DWORD dwEncoding) } } +static const BYTE CMSSignerWithKeyId[] = { +0x30,0x14,0x02,0x01,0x00,0x80,0x01,0x01,0x30,0x04,0x06,0x00,0x05,0x00,0x30, +0x04,0x06,0x00,0x05,0x00,0x04,0x00 }; + +static void test_encodeCMSSignerInfo(DWORD dwEncoding) +{ + BOOL ret; + LPBYTE buf = NULL; + DWORD size = 0; + CMSG_CMS_SIGNER_INFO info = { 0 }; + static char oid1[] = "1.2.3", oid2[] = "1.5.6"; + + SetLastError(0xdeadbeef); + ret = CryptEncodeObjectEx(dwEncoding, CMS_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + info.SignerId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; + SetLastError(0xdeadbeef); + ret = CryptEncodeObjectEx(dwEncoding, CMS_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* To be encoded, a signer must have a valid cert ID, where a valid ID may + * be a key id or a issuer serial number with at least the issuer set, and + * the encoding must include PKCS_7_ASN_ENCODING. + * (That isn't enough to be decoded, see decoding tests.) + */ + info.SignerId.IssuerSerialNumber.Issuer.cbData = + sizeof(encodedCommonNameNoNull); + info.SignerId.IssuerSerialNumber.Issuer.pbData = encodedCommonNameNoNull; + SetLastError(0xdeadbeef); + ret = CryptEncodeObjectEx(dwEncoding, CMS_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + if (!(dwEncoding & PKCS_7_ASN_ENCODING)) + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + else + { + ok(ret, "CryptEncodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(minimalPKCSSigner), "Unexpected size %d\n", size); + ok(!memcmp(buf, minimalPKCSSigner, size), "Unexpected value\n"); + LocalFree(buf); + } + } + info.SignerId.IssuerSerialNumber.SerialNumber.cbData = sizeof(serialNum); + info.SignerId.IssuerSerialNumber.SerialNumber.pbData = (BYTE *)serialNum; + SetLastError(0xdeadbeef); + ret = CryptEncodeObjectEx(dwEncoding, CMS_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + if (!(dwEncoding & PKCS_7_ASN_ENCODING)) + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + else + { + ok(ret, "CryptEncodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(PKCSSignerWithSerial), "Unexpected size %d\n", + size); + ok(!memcmp(buf, PKCSSignerWithSerial, size), "Unexpected value\n"); + LocalFree(buf); + } + } + info.SignerId.dwIdChoice = CERT_ID_KEY_IDENTIFIER; + info.SignerId.KeyId.cbData = sizeof(serialNum); + info.SignerId.KeyId.pbData = (BYTE *)serialNum; + SetLastError(0xdeadbeef); + ret = CryptEncodeObjectEx(dwEncoding, CMS_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + if (!(dwEncoding & PKCS_7_ASN_ENCODING)) + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + else + { + ok(ret, "CryptEncodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(CMSSignerWithKeyId), "Unexpected size %d\n", + size); + ok(!memcmp(buf, CMSSignerWithKeyId, size), "Unexpected value\n"); + LocalFree(buf); + } + } + /* While a CERT_ID can have a hash type, that's not allowed in CMS, where + * only the IssuerAndSerialNumber and SubjectKeyIdentifier types are allowed + * (see RFC 3852, section 5.3.) + */ + info.SignerId.dwIdChoice = CERT_ID_SHA1_HASH; + info.SignerId.HashId.cbData = sizeof(hash); + info.SignerId.HashId.pbData = (BYTE *)hash; + SetLastError(0xdeadbeef); + ret = CryptEncodeObjectEx(dwEncoding, CMS_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* Now with a hash algo */ + info.SignerId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; + info.SignerId.IssuerSerialNumber.Issuer.cbData = + sizeof(encodedCommonNameNoNull); + info.SignerId.IssuerSerialNumber.Issuer.pbData = encodedCommonNameNoNull; + info.HashAlgorithm.pszObjId = oid1; + SetLastError(0xdeadbeef); + ret = CryptEncodeObjectEx(dwEncoding, CMS_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + if (!(dwEncoding & PKCS_7_ASN_ENCODING)) + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + else + { + ok(ret, "CryptEncodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(PKCSSignerWithHashAlgo), "Unexpected size %d\n", + size); + ok(!memcmp(buf, PKCSSignerWithHashAlgo, size), + "Unexpected value\n"); + LocalFree(buf); + } + } + info.HashEncryptionAlgorithm.pszObjId = oid2; + SetLastError(0xdeadbeef); + ret = CryptEncodeObjectEx(dwEncoding, CMS_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + if (!(dwEncoding & PKCS_7_ASN_ENCODING)) + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + else + { + ok(ret, "CryptEncodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(PKCSSignerWithHashAndEncryptionAlgo), + "Unexpected size %d\n", size); + ok(!memcmp(buf, PKCSSignerWithHashAndEncryptionAlgo, size), + "Unexpected value\n"); + LocalFree(buf); + } + } + info.EncryptedHash.cbData = sizeof(hash); + info.EncryptedHash.pbData = (BYTE *)hash; + SetLastError(0xdeadbeef); + ret = CryptEncodeObjectEx(dwEncoding, CMS_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + if (!(dwEncoding & PKCS_7_ASN_ENCODING)) + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + else + { + ok(ret, "CryptEncodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(PKCSSignerWithHash), "Unexpected size %d\n", + size); + ok(!memcmp(buf, PKCSSignerWithHash, size), "Unexpected value\n"); + LocalFree(buf); + } + } +} + +static void test_decodeCMSSignerInfo(DWORD dwEncoding) +{ + BOOL ret; + LPBYTE buf = NULL; + DWORD size = 0; + CMSG_CMS_SIGNER_INFO *info; + static char oid1[] = "1.2.3", oid2[] = "1.5.6"; + + /* A CMS signer can't be decoded without a serial number. */ + SetLastError(0xdeadbeef); + ret = CryptDecodeObjectEx(dwEncoding, CMS_SIGNER_INFO, + minimalPKCSSigner, sizeof(minimalPKCSSigner), + CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT, + "Expected CRYPT_E_ASN1_CORRUPT, got %x\n", GetLastError()); + ret = CryptDecodeObjectEx(dwEncoding, CMS_SIGNER_INFO, + PKCSSignerWithSerial, sizeof(PKCSSignerWithSerial), + CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + info = (CMSG_CMS_SIGNER_INFO *)buf; + ok(info->dwVersion == 0, "Expected version 0, got %d\n", + info->dwVersion); + ok(info->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER, + "Expected CERT_ID_ISSUER_SERIAL_NUMBER, got %d\n", + info->SignerId.dwIdChoice); + ok(info->SignerId.IssuerSerialNumber.Issuer.cbData == + sizeof(encodedCommonNameNoNull), "Unexpected size %d\n", + info->SignerId.IssuerSerialNumber.Issuer.cbData); + ok(!memcmp(info->SignerId.IssuerSerialNumber.Issuer.pbData, + encodedCommonNameNoNull, + info->SignerId.IssuerSerialNumber.Issuer.cbData), + "Unexpected value\n"); + ok(info->SignerId.IssuerSerialNumber.SerialNumber.cbData == + sizeof(serialNum), "Unexpected size %d\n", + info->SignerId.IssuerSerialNumber.SerialNumber.cbData); + ok(!memcmp(info->SignerId.IssuerSerialNumber.SerialNumber.pbData, + serialNum, sizeof(serialNum)), "Unexpected value\n"); + LocalFree(buf); + } + ret = CryptDecodeObjectEx(dwEncoding, CMS_SIGNER_INFO, + PKCSSignerWithHashAlgo, sizeof(PKCSSignerWithHashAlgo), + CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + info = (CMSG_CMS_SIGNER_INFO *)buf; + ok(info->dwVersion == 0, "Expected version 0, got %d\n", + info->dwVersion); + ok(info->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER, + "Expected CERT_ID_ISSUER_SERIAL_NUMBER, got %d\n", + info->SignerId.dwIdChoice); + ok(info->SignerId.IssuerSerialNumber.Issuer.cbData == + sizeof(encodedCommonNameNoNull), "Unexpected size %d\n", + info->SignerId.IssuerSerialNumber.Issuer.cbData); + ok(!memcmp(info->SignerId.IssuerSerialNumber.Issuer.pbData, + encodedCommonNameNoNull, + info->SignerId.IssuerSerialNumber.Issuer.cbData), + "Unexpected value\n"); + ok(info->SignerId.IssuerSerialNumber.SerialNumber.cbData == + sizeof(serialNum), "Unexpected size %d\n", + info->SignerId.IssuerSerialNumber.SerialNumber.cbData); + ok(!memcmp(info->SignerId.IssuerSerialNumber.SerialNumber.pbData, + serialNum, sizeof(serialNum)), "Unexpected value\n"); + ok(!strcmp(info->HashAlgorithm.pszObjId, oid1), + "Expected %s, got %s\n", oid1, info->HashAlgorithm.pszObjId); + LocalFree(buf); + } + ret = CryptDecodeObjectEx(dwEncoding, CMS_SIGNER_INFO, + PKCSSignerWithHashAndEncryptionAlgo, + sizeof(PKCSSignerWithHashAndEncryptionAlgo), CRYPT_DECODE_ALLOC_FLAG, + NULL, (BYTE *)&buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + info = (CMSG_CMS_SIGNER_INFO *)buf; + ok(info->dwVersion == 0, "Expected version 0, got %d\n", + info->dwVersion); + ok(info->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER, + "Expected CERT_ID_ISSUER_SERIAL_NUMBER, got %d\n", + info->SignerId.dwIdChoice); + ok(info->SignerId.IssuerSerialNumber.Issuer.cbData == + sizeof(encodedCommonNameNoNull), "Unexpected size %d\n", + info->SignerId.IssuerSerialNumber.Issuer.cbData); + ok(!memcmp(info->SignerId.IssuerSerialNumber.Issuer.pbData, + encodedCommonNameNoNull, + info->SignerId.IssuerSerialNumber.Issuer.cbData), + "Unexpected value\n"); + ok(info->SignerId.IssuerSerialNumber.SerialNumber.cbData == + sizeof(serialNum), "Unexpected size %d\n", + info->SignerId.IssuerSerialNumber.SerialNumber.cbData); + ok(!memcmp(info->SignerId.IssuerSerialNumber.SerialNumber.pbData, + serialNum, sizeof(serialNum)), "Unexpected value\n"); + ok(!strcmp(info->HashAlgorithm.pszObjId, oid1), + "Expected %s, got %s\n", oid1, info->HashAlgorithm.pszObjId); + ok(!strcmp(info->HashEncryptionAlgorithm.pszObjId, oid2), + "Expected %s, got %s\n", oid2, info->HashEncryptionAlgorithm.pszObjId); + LocalFree(buf); + } + ret = CryptDecodeObjectEx(dwEncoding, CMS_SIGNER_INFO, + PKCSSignerWithHash, sizeof(PKCSSignerWithHash), + CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + info = (CMSG_CMS_SIGNER_INFO *)buf; + ok(info->dwVersion == 0, "Expected version 0, got %d\n", + info->dwVersion); + ok(info->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER, + "Expected CERT_ID_ISSUER_SERIAL_NUMBER, got %d\n", + info->SignerId.dwIdChoice); + ok(info->SignerId.IssuerSerialNumber.Issuer.cbData == + sizeof(encodedCommonNameNoNull), "Unexpected size %d\n", + info->SignerId.IssuerSerialNumber.Issuer.cbData); + ok(!memcmp(info->SignerId.IssuerSerialNumber.Issuer.pbData, + encodedCommonNameNoNull, + info->SignerId.IssuerSerialNumber.Issuer.cbData), + "Unexpected value\n"); + ok(info->SignerId.IssuerSerialNumber.SerialNumber.cbData == + sizeof(serialNum), "Unexpected size %d\n", + info->SignerId.IssuerSerialNumber.SerialNumber.cbData); + ok(!memcmp(info->SignerId.IssuerSerialNumber.SerialNumber.pbData, + serialNum, sizeof(serialNum)), "Unexpected value\n"); + ok(!strcmp(info->HashAlgorithm.pszObjId, oid1), + "Expected %s, got %s\n", oid1, info->HashAlgorithm.pszObjId); + ok(!strcmp(info->HashEncryptionAlgorithm.pszObjId, oid2), + "Expected %s, got %s\n", oid2, info->HashEncryptionAlgorithm.pszObjId); + ok(info->EncryptedHash.cbData == sizeof(hash), "Unexpected size %d\n", + info->EncryptedHash.cbData); + ok(!memcmp(info->EncryptedHash.pbData, hash, sizeof(hash)), + "Unexpected value\n"); + LocalFree(buf); + } + ret = CryptDecodeObjectEx(dwEncoding, CMS_SIGNER_INFO, + CMSSignerWithKeyId, sizeof(CMSSignerWithKeyId), + CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + info = (CMSG_CMS_SIGNER_INFO *)buf; + ok(info->dwVersion == 0, "Expected version 0, got %d\n", + info->dwVersion); + ok(info->SignerId.dwIdChoice == CERT_ID_KEY_IDENTIFIER, + "Expected CERT_ID_KEY_IDENTIFIER, got %d\n", + info->SignerId.dwIdChoice); + ok(info->SignerId.KeyId.cbData == sizeof(serialNum), + "Unexpected size %d\n", info->SignerId.KeyId.cbData); + ok(!memcmp(info->SignerId.KeyId.pbData, serialNum, sizeof(serialNum)), + "Unexpected value\n"); + LocalFree(buf); + } +} + static BYTE emptyDNSPermittedConstraints[] = { 0x30,0x06,0xa0,0x04,0x30,0x02,0x82,0x00 }; static BYTE emptyDNSExcludedConstraints[] = { @@ -5969,6 +6285,8 @@ START_TEST(encode) test_decodePKCSAttributes(encodings[i]); test_encodePKCSSignerInfo(encodings[i]); test_decodePKCSSignerInfo(encodings[i]); + test_encodeCMSSignerInfo(encodings[i]); + test_decodeCMSSignerInfo(encodings[i]); test_encodeNameConstraints(encodings[i]); test_decodeNameConstraints(encodings[i]); } diff --git a/dlls/crypt32/tests/msg.c b/dlls/crypt32/tests/msg.c index 0f7dcb6860d..00b4bac5a7b 100644 --- a/dlls/crypt32/tests/msg.c +++ b/dlls/crypt32/tests/msg.c @@ -23,6 +23,8 @@ #include #include #include +#define CMSG_SIGNER_ENCODE_INFO_HAS_CMS_FIELDS +#define CMSG_SIGNED_ENCODE_INFO_HAS_CMS_FIELDS #include #include "wine/test.h" @@ -1104,6 +1106,24 @@ static void test_signed_msg_open(void) CryptMsgClose(msg); } + /* pCertInfo must still be set, but can be empty if the SignerId's issuer + * and serial number are set. + */ + certInfo.Issuer.cbData = 0; + certInfo.SerialNumber.cbData = 0; + signer.SignerId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; + signer.SignerId.IssuerSerialNumber.Issuer.cbData = + sizeof(encodedCommonName); + signer.SignerId.IssuerSerialNumber.Issuer.pbData = + (BYTE *)encodedCommonName; + signer.SignerId.IssuerSerialNumber.SerialNumber.cbData = + sizeof(serialNum); + signer.SignerId.IssuerSerialNumber.SerialNumber.pbData = (BYTE *)serialNum; + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo, + NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + CryptMsgClose(msg); + CryptReleaseContext(signer.hCryptProv, 0); pCryptAcquireContextA(&signer.hCryptProv, cspNameA, MS_DEF_PROV_A, PROV_RSA_FULL, CRYPT_DELETEKEYSET); diff --git a/dlls/d3d8/d3d8_private.h b/dlls/d3d8/d3d8_private.h index 0da18ca2f3b..86adcbac1cc 100644 --- a/dlls/d3d8/d3d8_private.h +++ b/dlls/d3d8/d3d8_private.h @@ -600,7 +600,7 @@ struct IDirect3DVertexShader8Impl { const IDirect3DVertexShader8Vtbl *lpVtbl; LONG ref; - shader_handle *handle; + DWORD handle; IDirect3DVertexDeclaration8 *vertex_declaration; IWineD3DVertexShader *wineD3DVertexShader; }; @@ -623,7 +623,7 @@ typedef struct IDirect3DPixelShader8Impl { const IDirect3DPixelShader8Vtbl *lpVtbl; LONG ref; - shader_handle *handle; + DWORD handle; /* The device, to be replaced by an IDirect3DDeviceImpl */ IWineD3DPixelShader *wineD3DPixelShader; } IDirect3DPixelShader8Impl; diff --git a/dlls/d3d8/device.c b/dlls/d3d8/device.c index d1ae4762f2b..a81bf784495 100644 --- a/dlls/d3d8/device.c +++ b/dlls/d3d8/device.c @@ -1581,9 +1581,9 @@ static HRESULT WINAPI IDirect3DDevice8Impl_CreateVertexShader(LPDIRECT3DDEVICE8 IDirect3DVertexShader8_Release((IUnknown *)object); hrc = E_OUTOFMEMORY; } else { - object->handle = handle; *handle = object; - *ppShader = (handle - This->shader_handles) + VS_HIGHESTFIXEDFXF + 1; + object->handle = (handle - This->shader_handles) + VS_HIGHESTFIXEDFXF + 1; + *ppShader = object->handle; load_local_constants(pDeclaration, object->wineD3DVertexShader); TRACE("(%p) : returning %p (handle %#x)\n", This, object, *ppShader); @@ -1689,7 +1689,7 @@ static HRESULT WINAPI IDirect3DDevice8Impl_GetVertexShader(LPDIRECT3DDEVICE8 ifa IDirect3DVertexShader8Impl *d3d8_shader; hrc = IWineD3DVertexShader_GetParent(pShader, (IUnknown **)&d3d8_shader); IWineD3DVertexShader_Release(pShader); - *ppShader = (d3d8_shader->handle - This->shader_handles) + (VS_HIGHESTFIXEDFXF + 1); + *ppShader = d3d8_shader->handle; } else { *ppShader = 0; hrc = D3D_OK; @@ -1889,9 +1889,9 @@ static HRESULT WINAPI IDirect3DDevice8Impl_CreatePixelShader(LPDIRECT3DDEVICE8 i IDirect3DVertexShader8_Release((IUnknown *)object); hrc = E_OUTOFMEMORY; } else { - object->handle = handle; *handle = object; - *ppShader = (handle - This->shader_handles) + VS_HIGHESTFIXEDFXF + 1; + object->handle = (handle - This->shader_handles) + VS_HIGHESTFIXEDFXF + 1; + *ppShader = object->handle; TRACE("(%p) : returning %p (handle %#x)\n", This, object, *ppShader); } } @@ -1938,7 +1938,7 @@ static HRESULT WINAPI IDirect3DDevice8Impl_GetPixelShader(LPDIRECT3DDEVICE8 ifac IDirect3DPixelShader8Impl *d3d8_shader; hrc = IWineD3DPixelShader_GetParent(object, (IUnknown **)&d3d8_shader); IWineD3DPixelShader_Release(object); - *ppShader = (d3d8_shader->handle - This->shader_handles) + (VS_HIGHESTFIXEDFXF + 1); + *ppShader = d3d8_shader->handle; } else { *ppShader = (DWORD)NULL; } diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c index 7d79db2feb7..6c460b93927 100644 --- a/dlls/d3d9/tests/visual.c +++ b/dlls/d3d9/tests/visual.c @@ -9179,6 +9179,125 @@ static void texop_test(IDirect3DDevice9 *device) if (vertex_declaration) IDirect3DVertexDeclaration9_Release(vertex_declaration); } +static void yuv_color_test(IDirect3DDevice9 *device) { + HRESULT hr; + IDirect3DSurface9 *surface = NULL, *target = NULL; + unsigned int fmt, i; + D3DFORMAT format; + const char *fmt_string; + D3DLOCKED_RECT lr; + IDirect3D9 *d3d; + HRESULT color; + DWORD ref_color_left, ref_color_right; + + struct { + DWORD in; /* The input color */ + DWORD uyvy_left; /* "in" interpreted as uyvy and transformed to RGB, pixel 1/1*/ + DWORD uyvy_right; /* "in" interpreted as uyvy and transformed to RGB, pixel 2/1*/ + DWORD yuy2_left; /* "in" interpreted as yuy2 and transformed to RGB, pixel 1/1 */ + DWORD yuy2_right; /* "in" interpreted as yuy2 and transformed to RGB, pixel 2/1 */ + } test_data[] = { + /* Originally I wanted to avoid being evil, and set Y1 = Y2 to avoid triggering troubles in shader converters, + * but the main difference between YUY2 and UYVY is the swapped ordering of the chroma and luminance + * values. However, handling the two Y's properly could have a big impact on image quality, so be picky about + * that + */ + { 0x00000000, 0x00008700, 0x00008700, 0x00008700, 0x00008700 }, + { 0xff000000, 0x00008700, 0x004bff1c, 0x00b30000, 0x00b30000 }, + { 0x00ff0000, 0x00b30000, 0x00b30000, 0x00008700, 0x004bff1c }, + { 0x0000ff00, 0x004bff1c, 0x00008700, 0x000030e1, 0x000030e1 }, + { 0x000000ff, 0x000030e1, 0x000030e1, 0x004bff1c, 0x00008700 }, + { 0xffff0000, 0x00b30000, 0x00ffd01c, 0x00b30000, 0x00ffd01c }, + { 0xff00ff00, 0x004bff1c, 0x004bff1c, 0x00b300e1, 0x00b300e1 }, + { 0xff0000ff, 0x000030e1, 0x004bffff, 0x00ffd01c, 0x00b30000 }, + { 0x00ffff00, 0x00ffd01c, 0x00b30000, 0x000030e1, 0x004bffff }, + { 0x00ff00ff, 0x00b300e1, 0x00b300e1, 0x004bff1c, 0x004bff1c }, + { 0x0000ffff, 0x004bffff, 0x000030e1, 0x004bffff, 0x000030e1 }, + { 0xffffff00, 0x00ffd01c, 0x00ffd01c, 0x00b300e1, 0x00ff79ff }, + { 0xffff00ff, 0x00b300e1, 0x00ff79ff, 0x00ffd01c, 0x00ffd01c }, + { 0xffffffff, 0x00ff79ff, 0x00ff79ff, 0x00ff79ff, 0x00ff79ff }, + + { 0x4cff4c54, 0x00ff0000, 0x00ff0000, 0x000b8b00, 0x00b6ffa3 }, + { 0x00800080, 0x00000000, 0x00000000, 0x0000ff00, 0x0000ff00 }, + { 0xFF80FF80, 0x00ffffff, 0x00ffffff, 0x00ff00ff, 0x00ff00ff }, + { 0x1c6b1cff, 0x000000fd, 0x000000fd, 0x006dff45, 0x0000d500 }, + }; + + hr = IDirect3DDevice9_GetDirect3D(device, &d3d); + ok(hr == D3D_OK, "IDirect3DDevice9_GetDirect3D failed, hr = %08x\n", hr); + hr = IDirect3DDevice9_GetRenderTarget(device, 0, &target); + ok(hr == D3D_OK, "IDirect3DDevice9_GetRenderTarget failed, hr = %08x\n", hr); + + IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_TEX0); + ok(hr == D3D_OK, "IDirect3DDevice9_SetFVF failed, hr = %08x\n", hr); + + for(fmt = 0; fmt < 2; fmt++) { + if(fmt == 0) { + format = D3DFMT_UYVY; + fmt_string = "D3DFMT_UYVY"; + } else { + format = D3DFMT_YUY2; + fmt_string = "D3DFMT_YUY2"; + } + + /* Some(all?) Windows drivers do not support YUV 3D textures, only 2D surfaces in StretchRect. Thus use + * StretchRect to draw the YUV surface onto the screen instead of drawPrimitive + */ + if(IDirect3D9_CheckDeviceFormat(d3d, 0, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, 0, + D3DRTYPE_SURFACE, format) != D3D_OK) { + skip("%s is not supported\n", fmt_string); + continue; + } + + /* A pixel is effectively 16 bit large, but two pixels are stored together, so the minimum size is 2x1 */ + hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 2, 1, format, D3DPOOL_DEFAULT, &surface, NULL); + ok(hr == D3D_OK, "IDirect3DDevice9_CreateOffscreenPlainSurface failed, hr = %08x\n", hr); + + for(i = 0; i < (sizeof(test_data)/sizeof(test_data[0])); i++) { + if(fmt == 0) { + ref_color_left = test_data[i].uyvy_left; + ref_color_right = test_data[i].uyvy_right; + } else { + ref_color_left = test_data[i].yuy2_left; + ref_color_right = test_data[i].yuy2_right; + } + + memset(&lr, 0, sizeof(lr)); + hr = IDirect3DSurface9_LockRect(surface, &lr, NULL, 0); + ok(hr == D3D_OK, "IDirect3DSurface9_LockRect failed, hr = %08x\n", hr); + *((DWORD *) lr.pBits) = test_data[i].in; + hr = IDirect3DSurface9_UnlockRect(surface); + ok(hr == D3D_OK, "IDirect3DSurface9_UnlockRect failed, hr = %08x\n", hr); + + hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0); + ok(hr == D3D_OK, "IDirect3DDevice9_Clear failed with 0x%08x\n", hr); + hr = IDirect3DDevice9_StretchRect(device, surface, NULL, target, NULL, D3DTEXF_POINT); + ok(hr == D3D_OK, "IDirect3DDevice9_StretchRect failed with 0x%08x\n", hr); + hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL); + ok(SUCCEEDED(hr), "Present failed with 0x%08x\n", hr); + + /* Native D3D can't resist filtering the YUY surface, even though we asked it not to do so above. To + * prevent running into precision problems, read a far left and far right pixel. In the future we may + * want to add tests for the filtered pixels as well. + * + * Unfortunately different implementations(Windows-NV and Mac-ATI tested) interpret some colors vastly + * differently, so we need a max diff of 16 + */ + color = getPixelColor(device, 40, 240); + ok(color_match(color, ref_color_left, 16), + "Input 0x%08x: Got color 0x%08x for pixel 1/1, expected 0x%08x, format %s\n", + test_data[i].in, color, ref_color_left, fmt_string); + color = getPixelColor(device, 600, 240); + ok(color_match(color, ref_color_right, 16), + "Input 0x%08x: Got color 0x%08x for pixel 2/1, expected 0x%08x, format %s\n", + test_data[i].in, color, ref_color_left, fmt_string); + } + IDirect3DSurface9_Release(surface); + } + IDirect3DSurface9_Release(target); + IDirect3D9_Release(d3d); +} + START_TEST(visual) { IDirect3DDevice9 *device_ptr; @@ -9274,6 +9393,7 @@ START_TEST(visual) pointsize_test(device_ptr); tssargtemp_test(device_ptr); np2_stretch_rect_test(device_ptr); + yuv_color_test(device_ptr); if (caps.VertexShaderVersion >= D3DVS_VERSION(1, 1)) { diff --git a/dlls/d3dx8/d3dx8.spec b/dlls/d3dx8/d3dx8.spec index b7c8577654a..3587c6b4e07 100644 --- a/dlls/d3dx8/d3dx8.spec +++ b/dlls/d3dx8/d3dx8.spec @@ -109,7 +109,7 @@ @ stub D3DXWeldVertices @ stub D3DXIntersect @ stdcall D3DXSphereBoundProbe(ptr long ptr ptr) -@ stub D3DXBoxBoundProbe +@ stdcall D3DXBoxBoundProbe(ptr ptr ptr ptr) @ stub D3DXCreatePolygon @ stub D3DXCreateBox @ stub D3DXCreateCylinder diff --git a/dlls/d3dx8/mesh.c b/dlls/d3dx8/mesh.c index 6846d5da982..b9ba9760647 100644 --- a/dlls/d3dx8/mesh.c +++ b/dlls/d3dx8/mesh.c @@ -24,6 +24,76 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3dx); +BOOL WINAPI D3DXBoxBoundProbe(CONST D3DXVECTOR3 *pmin, CONST D3DXVECTOR3 *pmax, CONST D3DXVECTOR3 *prayposition, CONST D3DXVECTOR3 *praydirection) + +/* Algorithm taken from the article: An Efficient and Robust Ray-Box Intersection Algoritm +Amy Williams University of Utah +Steve Barrus University of Utah +R. Keith Morley University of Utah +Peter Shirley University of Utah + +International Conference on Computer Graphics and Interactive Techniques archive +ACM SIGGRAPH 2005 Courses +Los Angeles, California + +This algorithm is free of patents or of copyrights, as confirmed by Peter Shirley himself. + +Algorithm: Consider the box as the intersection of three slabs. Clip the ray +against each slab, if there's anything left of the ray after we're +done we've got an intersection of the ray with the box. +*/ + +{ + FLOAT div, tmin, tmax, tymin, tymax, tzmin, tzmax; + + div = 1.0f / praydirection->x; + if ( div >= 0.0f ) + { + tmin = ( pmin->x - prayposition->x ) * div; + tmax = ( pmax->x - prayposition->x ) * div; + } + else + { + tmin = ( pmax->x - prayposition->x ) * div; + tmax = ( pmin->x - prayposition->x ) * div; + } + + if ( tmax < 0.0f ) return FALSE; + + div = 1.0f / praydirection->y; + if ( div >= 0.0f ) + { + tymin = ( pmin->y - prayposition->y ) * div; + tymax = ( pmax->y - prayposition->y ) * div; + } + else + { + tymin = ( pmax->y - prayposition->y ) * div; + tymax = ( pmin->y - prayposition->y ) * div; + } + + if ( ( tymax < 0.0f ) || ( tmin > tymax ) || ( tymin > tmax ) ) return FALSE; + + if ( tymin > tmin ) tmin = tymin; + if ( tymax < tmax ) tmax = tymax; + + div = 1.0f / praydirection->z; + if ( div >= 0.0f ) + { + tzmin = ( pmin->z - prayposition->z ) * div; + tzmax = ( pmax->z - prayposition->z ) * div; + } + else + { + tzmin = ( pmax->z - prayposition->z ) * div; + tzmax = ( pmin->z - prayposition->z ) * div; + } + + if ( (tzmax < 0.0f ) || ( tmin > tzmax ) || ( tzmin > tmax ) ) return FALSE; + + return TRUE; +} + BOOL WINAPI D3DXSphereBoundProbe(CONST D3DXVECTOR3 *pcenter, FLOAT radius, CONST D3DXVECTOR3 *prayposition, CONST D3DXVECTOR3 *praydirection) { D3DXVECTOR3 difference; diff --git a/dlls/d3dx8/tests/mesh.c b/dlls/d3dx8/tests/mesh.c index 5a5eb676981..e3370de036e 100644 --- a/dlls/d3dx8/tests/mesh.c +++ b/dlls/d3dx8/tests/mesh.c @@ -22,12 +22,57 @@ static void D3DXBoundProbeTest(void) { -/*____________Test the Sphere case________________________*/ - BOOL result; - D3DXVECTOR3 center, raydirection, rayposition; + D3DXVECTOR3 bottom_point, center, top_point, raydirection, rayposition; FLOAT radius; +/*____________Test the Box case___________________________*/ + bottom_point.x = -3.0f; bottom_point.y = -2.0f; bottom_point.z = -1.0f; + top_point.x = 7.0f; top_point.y = 8.0f; top_point.z = 9.0f; + + raydirection.x = -4.0f; raydirection.y = -5.0f; raydirection.z = -6.0f; + rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f; + result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection); + ok(result == TRUE, "expected TRUE, received FALSE\n"); + + raydirection.x = 4.0f; raydirection.y = 5.0f; raydirection.z = 6.0f; + rayposition.x = 5.0f; rayposition.y = 5.0f; rayposition.z = 11.0f; + result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection); + ok(result == FALSE, "expected FALSE, received TRUE\n"); + + rayposition.x = -4.0f; rayposition.y = 1.0f; rayposition.z = -2.0f; + result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection); + ok(result == TRUE, "expected TRUE, received FALSE\n"); + + bottom_point.x = 1.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f; + top_point.x = 1.0f; top_point.y = 0.0f; top_point.z = 0.0f; + rayposition.x = 0.0f; rayposition.y = 1.0f; rayposition.z = 0.0f; + raydirection.x = 0.0f; raydirection.y = 3.0f; raydirection.z = 0.0f; + result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection); + ok(result == FALSE, "expected FALSE, received TRUE\n"); + + bottom_point.x = 1.0f; bottom_point.y = 2.0f; bottom_point.z = 3.0f; + top_point.x = 10.0f; top_point.y = 15.0f; top_point.z = 20.0f; + + raydirection.x = 7.0f; raydirection.y = 8.0f; raydirection.z = 9.0f; + rayposition.x = 3.0f; rayposition.y = 7.0f; rayposition.z = -6.0f; + result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection); + ok(result == TRUE, "expected TRUE, received FALSE\n"); + + bottom_point.x = 0.0f; bottom_point.y = 0.0f; bottom_point.z = 0.0f; + top_point.x = 1.0f; top_point.y = 1.0f; top_point.z = 1.0f; + + raydirection.x = 0.0f; raydirection.y = 1.0f; raydirection.z = .0f; + rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f; + result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection); + ok(result == FALSE, "expected FALSE, received TRUE\n"); + + raydirection.x = 1.0f; raydirection.y = 0.0f; raydirection.z = .0f; + rayposition.x = -3.0f; rayposition.y = 0.0f; rayposition.z = 0.0f; + result = D3DXBoxBoundProbe(&bottom_point, &top_point, &rayposition, &raydirection); + ok(result == TRUE, "expected TRUE, received FALSE\n"); + +/*____________Test the Sphere case________________________*/ radius = sqrt(77.0f); center.x = 1.0f; center.y = 2.0f; center.z = 3.0f; raydirection.x = 2.0f; raydirection.y = -4.0f; raydirection.z = 2.0f; diff --git a/dlls/d3dxof/d3dxof.c b/dlls/d3dxof/d3dxof.c index f16dce173b4..54d78a147dd 100644 --- a/dlls/d3dxof/d3dxof.c +++ b/dlls/d3dxof/d3dxof.c @@ -275,7 +275,6 @@ static BOOL is_space(char c) case ' ': case '\t': return TRUE; - break; } return FALSE; } @@ -295,7 +294,6 @@ static BOOL is_operator(char c) case ',': case ';': return TRUE; - break; } return FALSE; } @@ -311,34 +309,24 @@ static WORD get_operator_token(char c) { case '{': return TOKEN_OBRACE; - break; case '}': return TOKEN_CBRACE; - break; case '[': return TOKEN_OBRACKET; - break; case ']': return TOKEN_CBRACKET; - break; case '(': return TOKEN_OPAREN; - break; case ')': return TOKEN_CPAREN; - break; case '<': return TOKEN_OANGLE; - break; case '>': return TOKEN_CANGLE; - break; case ',': return TOKEN_COMMA; - break; case ';': return TOKEN_SEMICOLON; - break; } return 0; } diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c index 8eac7768991..73982edc777 100644 --- a/dlls/ddraw/ddraw.c +++ b/dlls/ddraw/ddraw.c @@ -2022,7 +2022,6 @@ IDirectDrawImpl_CreateNewSurface(IDirectDrawImpl *This, } /* Get the correct wined3d usage */ if (pDDSD->ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | - DDSCAPS_BACKBUFFER | DDSCAPS_3DDEVICE ) ) { Usage |= WINED3DUSAGE_RENDERTARGET; diff --git a/dlls/ddraw/utils.c b/dlls/ddraw/utils.c index 2c08328595f..5d96b367d1b 100644 --- a/dlls/ddraw/utils.c +++ b/dlls/ddraw/utils.c @@ -249,6 +249,11 @@ PixelFormat_WineD3DtoDD(DDPIXELFORMAT *DDPixelFormat, case WINED3DFMT_UYVY: case WINED3DFMT_YUY2: + DDPixelFormat->u1.dwYUVBitCount = 16; + DDPixelFormat->dwFlags = DDPF_FOURCC; + DDPixelFormat->dwFourCC = WineD3DFormat; + break; + case WINED3DFMT_YV12: case WINED3DFMT_DXT1: case WINED3DFMT_DXT2: diff --git a/dlls/dinput/keyboard.c b/dlls/dinput/keyboard.c index b2c4942bdc0..e0f76fa931c 100644 --- a/dlls/dinput/keyboard.c +++ b/dlls/dinput/keyboard.c @@ -50,6 +50,30 @@ struct SysKeyboardImpl BYTE DInputKeyState[WINE_DINPUT_KEYBOARD_MAX_KEYS]; }; +static BYTE map_dik_code(DWORD scanCode, DWORD vkCode) +{ + static const BYTE asciiCodes[] = + {/*32*/ DIK_SPACE,0,0,0,0,0,0,DIK_APOSTROPHE, \ + /*40*/ 0,0,0,0,DIK_COMMA,DIK_MINUS,DIK_PERIOD,DIK_SLASH, \ + /*48*/ DIK_0,DIK_1,DIK_2,DIK_3,DIK_4,DIK_5,DIK_6,DIK_7, \ + /*56*/ DIK_8,DIK_9,DIK_COLON,DIK_SEMICOLON,0,DIK_EQUALS,0,0, \ + /*64*/ DIK_AT,DIK_A,DIK_B,DIK_C,DIK_D,DIK_E,DIK_F,DIK_G, \ + /*72*/ DIK_H,DIK_I,DIK_J,DIK_K,DIK_L,DIK_M,DIK_N,DIK_O, \ + /*80*/ DIK_P,DIK_Q,DIK_R,DIK_S,DIK_T,DIK_U,DIK_V,DIK_W, \ + /*88*/ DIK_X,DIK_Y,DIK_Z,DIK_LBRACKET,0,DIK_RBRACKET,DIK_CIRCUMFLEX,DIK_UNDERLINE} /*95*/ ; + + BYTE out_code = 0; + WCHAR c = MapVirtualKeyW(vkCode,MAPVK_VK_TO_CHAR); + + if (c > 31 && c < 96) + out_code = asciiCodes[c - 32]; + + if (out_code == 0) + out_code = scanCode; + + return out_code; +} + static void KeyboardCallback( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM lparam ) { SysKeyboardImpl *This = (SysKeyboardImpl *)iface; @@ -63,7 +87,7 @@ static void KeyboardCallback( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM TRACE("(%p) %ld,%ld\n", iface, wparam, lparam); - dik_code = hook->scanCode & 0xff; + dik_code = map_dik_code(hook->scanCode & 0xff,hook->vkCode); /* R-Shift is special - it is an extended key with separate scan code */ if (hook->flags & LLKHF_EXTENDED && dik_code != 0x36) dik_code |= 0x80; diff --git a/dlls/dinput/mouse.c b/dlls/dinput/mouse.c index a3610573940..15727844f03 100644 --- a/dlls/dinput/mouse.c +++ b/dlls/dinput/mouse.c @@ -30,6 +30,7 @@ #include "wingdi.h" #include "winuser.h" #include "winerror.h" +#include "winreg.h" #include "dinput.h" #include "dinput_private.h" @@ -50,6 +51,13 @@ static const IDirectInputDevice8WVtbl SysMouseWvt; typedef struct SysMouseImpl SysMouseImpl; +typedef enum +{ + WARP_DEFAULT, + WARP_DISABLE, + WARP_FORCE_ON +} WARP_MOUSE; + struct SysMouseImpl { struct IDirectInputDevice2AImpl base; @@ -66,6 +74,8 @@ struct SysMouseImpl /* This is for mouse reporting. */ DIMOUSESTATE2 m_state; + + WARP_MOUSE warp_override; }; static void dinput_mouse_hook( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM lparam ); @@ -174,6 +184,8 @@ static SysMouseImpl *alloc_device(REFGUID rguid, const void *mvt, IDirectInputIm SysMouseImpl* newDevice; LPDIDATAFORMAT df = NULL; unsigned i; + char buffer[20]; + HKEY hkey, appkey; newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysMouseImpl)); if (!newDevice) return NULL; @@ -186,6 +198,17 @@ static SysMouseImpl *alloc_device(REFGUID rguid, const void *mvt, IDirectInputIm newDevice->base.dinput = dinput; newDevice->base.event_proc = dinput_mouse_hook; + get_app_key(&hkey, &appkey); + if (!get_config_key(hkey, appkey, "MouseWarpOverride", buffer, sizeof(buffer))) + { + if (!strcasecmp(buffer, "disable")) + newDevice->warp_override = WARP_DISABLE; + else if (!strcasecmp(buffer, "force")) + newDevice->warp_override = WARP_FORCE_ON; + } + if (appkey) RegCloseKey(appkey); + if (hkey) RegCloseKey(hkey); + /* Create copy of default data format */ if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIMouse2.dwSize))) goto failed; memcpy(df, &c_dfDIMouse2, c_dfDIMouse2.dwSize); @@ -306,7 +329,9 @@ static void dinput_mouse_hook( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARA wdata = pt1.y; } - This->need_warp = (pt.x || pt.y) && dwCoop & DISCL_EXCLUSIVE; + This->need_warp = This->warp_override != WARP_DISABLE && + (pt.x || pt.y) && + (dwCoop & DISCL_EXCLUSIVE || This->warp_override == WARP_FORCE_ON); break; } case WM_MOUSEWHEEL: @@ -422,14 +447,18 @@ static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) else ERR("Failed to get RECT: %d\n", GetLastError()); } - + + /* Need a window to warp mouse in. */ + if (This->warp_override == WARP_FORCE_ON && !This->base.win) + This->base.win = GetDesktopWindow(); + /* Get the window dimension and find the center */ GetWindowRect(This->base.win, &rect); This->win_centerX = (rect.right - rect.left) / 2; This->win_centerY = (rect.bottom - rect.top ) / 2; - + /* Warp the mouse to the center of the window */ - if (This->base.dwCoopLevel & DISCL_EXCLUSIVE) + if (This->base.dwCoopLevel & DISCL_EXCLUSIVE || This->warp_override == WARP_FORCE_ON) { This->mapped_center.x = This->win_centerX; This->mapped_center.y = This->win_centerY; @@ -463,7 +492,7 @@ static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface) } /* And put the mouse cursor back where it was at acquire time */ - if (This->base.dwCoopLevel & DISCL_EXCLUSIVE) + if (This->base.dwCoopLevel & DISCL_EXCLUSIVE || This->warp_override == WARP_FORCE_ON) { TRACE(" warping mouse back to (%d , %d)\n", This->org_coords.x, This->org_coords.y); SetCursorPos(This->org_coords.x, This->org_coords.y); diff --git a/dlls/dplayx/dplay.c b/dlls/dplayx/dplay.c index c150d7e8578..ce9cdb6434f 100644 --- a/dlls/dplayx/dplay.c +++ b/dlls/dplayx/dplay.c @@ -793,6 +793,11 @@ static HRESULT WINAPI DP_IF_AddPlayerToGroup TRACE( "(%p)->(%p,0x%08x,0x%08x,%u)\n", This, lpMsgHdr, idGroup, idPlayer, bAnsi ); + if( This->dp2->connectionInitialized == NO_PROVIDER ) + { + return DPERR_UNINITIALIZED; + } + /* Find the group */ if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL ) { @@ -1016,6 +1021,11 @@ static HRESULT WINAPI DP_IF_CreateGroup This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize, dwFlags, bAnsi ); + if( This->dp2->connectionInitialized == NO_PROVIDER ) + { + return DPERR_UNINITIALIZED; + } + /* If the name is not specified, we must provide one */ if( DPID_UNKNOWN == *lpidGroup ) { @@ -3449,6 +3459,11 @@ static HRESULT WINAPI DP_IF_AddGroupToGroup TRACE( "(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup ); + if( This->dp2->connectionInitialized == NO_PROVIDER ) + { + return DPERR_UNINITIALIZED; + } + if( DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) == NULL ) { return DPERR_INVALIDGROUP; @@ -3506,6 +3521,11 @@ static HRESULT WINAPI DP_IF_CreateGroupInGroup This, idParentGroup, lpidGroup, lpGroupName, lpData, dwDataSize, dwFlags, bAnsi ); + if( This->dp2->connectionInitialized == NO_PROVIDER ) + { + return DPERR_UNINITIALIZED; + } + /* Verify that the specified parent is valid */ if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL @@ -3949,6 +3969,11 @@ static HRESULT WINAPI DP_IF_EnumGroupsInGroup This, idGroup, lpguidInstance, lpEnumPlayersCallback2, lpContext, dwFlags, bAnsi ); + if( This->dp2->connectionInitialized == NO_PROVIDER ) + { + return DPERR_UNINITIALIZED; + } + if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL ) { return DPERR_INVALIDGROUP; @@ -4551,6 +4576,11 @@ static HRESULT WINAPI DP_SendEx This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority, dwTimeout, lpContext, lpdwMsgID, bAnsi ); + if( This->dp2->connectionInitialized == NO_PROVIDER ) + { + return DPERR_UNINITIALIZED; + } + /* FIXME: Add parameter checking */ /* FIXME: First call to this needs to acquire a message id which will be * used for multiple sends diff --git a/dlls/dplayx/tests/dplayx.c b/dlls/dplayx/tests/dplayx.c index e8b7f21ef57..4fdc494799e 100644 --- a/dlls/dplayx/tests/dplayx.c +++ b/dlls/dplayx/tests/dplayx.c @@ -49,6 +49,11 @@ ok( IsEqualGUID(expected, result), \ "expected=%s got=%s\n", \ Guid2str(expected), Guid2str(result) ); +#define checkConv(expected, result, function) \ + ok( (expected) == (result), \ + "expected=0x%08x(%s) got=0x%08x(%s)\n", \ + expected, function(expected), \ + result, function(result) ); DEFINE_GUID(appGuid, 0xbdcfe03e, 0xf0ec, 0x415b, 0x82, 0x11, 0x6f, 0x86, 0xd8, 0x19, 0x7f, 0xe1); @@ -209,6 +214,31 @@ static LPCSTR dpResult2str(HRESULT hr) } } +static LPCSTR dpMsgType2str(DWORD dwType) +{ + switch(dwType) + { + case DPSYS_CREATEPLAYERORGROUP: return "DPSYS_CREATEPLAYERORGROUP"; + case DPSYS_DESTROYPLAYERORGROUP: return "DPSYS_DESTROYPLAYERORGROUP"; + case DPSYS_ADDPLAYERTOGROUP: return "DPSYS_ADDPLAYERTOGROUP"; + case DPSYS_DELETEPLAYERFROMGROUP: return "DPSYS_DELETEPLAYERFROMGROUP"; + case DPSYS_SESSIONLOST: return "DPSYS_SESSIONLOST"; + case DPSYS_HOST: return "DPSYS_HOST"; + case DPSYS_SETPLAYERORGROUPDATA: return "DPSYS_SETPLAYERORGROUPDATA"; + case DPSYS_SETPLAYERORGROUPNAME: return "DPSYS_SETPLAYERORGROUPNAME"; + case DPSYS_SETSESSIONDESC: return "DPSYS_SETSESSIONDESC"; + case DPSYS_ADDGROUPTOGROUP: return "DPSYS_ADDGROUPTOGROUP"; + case DPSYS_DELETEGROUPFROMGROUP: return "DPSYS_DELETEGROUPFROMGROUP"; + case DPSYS_SECUREMESSAGE: return "DPSYS_SECUREMESSAGE"; + case DPSYS_STARTSESSION: return "DPSYS_STARTSESSION"; + case DPSYS_CHAT: return "DPSYS_DPSYS_CHAT"; + case DPSYS_SETGROUPOWNER: return "DPSYS_SETGROUPOWNER"; + case DPSYS_SENDCOMPLETE: return "DPSYS_SENDCOMPLETE"; + + default: return "UNKNOWN"; + } +} + static LPCSTR dwFlags2str(DWORD dwFlags, DWORD flagType) { @@ -667,10 +697,10 @@ static void init_TCPIP_provider( LPDIRECTPLAY4 pDP, } -static BOOL FAR PASCAL EnumSessions_cb_join( LPCDPSESSIONDESC2 lpThisSD, - LPDWORD lpdwTimeOut, - DWORD dwFlags, - LPVOID lpContext ) +static BOOL CALLBACK EnumSessions_cb_join( LPCDPSESSIONDESC2 lpThisSD, + LPDWORD lpdwTimeOut, + DWORD dwFlags, + LPVOID lpContext ) { LPDIRECTPLAY4 pDP = (LPDIRECTPLAY4) lpContext; DPSESSIONDESC2 dpsd; @@ -727,10 +757,10 @@ static void test_DirectPlayCreate(void) /* EnumConnections */ -static BOOL FAR PASCAL EnumAddress_cb2( REFGUID guidDataType, - DWORD dwDataSize, - LPCVOID lpData, - LPVOID lpContext ) +static BOOL CALLBACK EnumAddress_cb2( REFGUID guidDataType, + DWORD dwDataSize, + LPCVOID lpData, + LPVOID lpContext ) { lpCallbackData callbackData = (lpCallbackData) lpContext; @@ -986,10 +1016,10 @@ static void test_GetCaps(void) /* Open */ -static BOOL FAR PASCAL EnumSessions_cb2( LPCDPSESSIONDESC2 lpThisSD, - LPDWORD lpdwTimeOut, - DWORD dwFlags, - LPVOID lpContext ) +static BOOL CALLBACK EnumSessions_cb2( LPCDPSESSIONDESC2 lpThisSD, + LPDWORD lpdwTimeOut, + DWORD dwFlags, + LPVOID lpContext ) { LPDIRECTPLAY4 pDP = (LPDIRECTPLAY4) lpContext; DPSESSIONDESC2 dpsd; @@ -1153,10 +1183,10 @@ static void test_Open(void) /* EnumSessions */ -static BOOL FAR PASCAL EnumSessions_cb( LPCDPSESSIONDESC2 lpThisSD, - LPDWORD lpdwTimeOut, - DWORD dwFlags, - LPVOID lpContext ) +static BOOL CALLBACK EnumSessions_cb( LPCDPSESSIONDESC2 lpThisSD, + LPDWORD lpdwTimeOut, + DWORD dwFlags, + LPVOID lpContext ) { lpCallbackData callbackData = (lpCallbackData) lpContext; callbackData->dwCounter1++; @@ -2604,10 +2634,10 @@ static void test_PlayerName(void) /* GetPlayerAccount */ -static BOOL FAR PASCAL EnumSessions_cb_join_secure( LPCDPSESSIONDESC2 lpThisSD, - LPDWORD lpdwTimeOut, - DWORD dwFlags, - LPVOID lpContext ) +static BOOL CALLBACK EnumSessions_cb_join_secure( LPCDPSESSIONDESC2 lpThisSD, + LPDWORD lpdwTimeOut, + DWORD dwFlags, + LPVOID lpContext ) { LPDIRECTPLAY4 pDP = (LPDIRECTPLAY4) lpContext; DPSESSIONDESC2 dpsd; @@ -2780,10 +2810,10 @@ static void test_GetPlayerAccount(void) /* GetPlayerAddress */ -static BOOL FAR PASCAL EnumAddress_cb( REFGUID guidDataType, - DWORD dwDataSize, - LPCVOID lpData, - LPVOID lpContext ) +static BOOL CALLBACK EnumAddress_cb( REFGUID guidDataType, + DWORD dwDataSize, + LPCVOID lpData, + LPVOID lpContext ) { lpCallbackData callbackData = (lpCallbackData) lpContext; static REFGUID types[] = { &DPAID_TotalSize, @@ -3060,27 +3090,3168 @@ static void test_GetPlayerFlags(void) } +/* CreateGroup + CreateGroupInGroup */ -START_TEST(dplayx) +static void test_CreateGroup(void) { - CoInitialize( NULL ); - test_DirectPlayCreate(); - test_EnumConnections(); - test_InitializeConnection(); + LPDIRECTPLAY4 pDP; + DPSESSIONDESC2 dpsd; + DPID idFrom, idTo, dpid, idGroup, idGroupParent; + DPNAME groupName; + HRESULT hr; + UINT i; - test_GetCaps(); - test_Open(); - test_EnumSessions(); - test_SessionDesc(); + LPCSTR lpData = "data"; + DWORD dwDataSize = strlen(lpData)+1; + LPDPMSG_CREATEPLAYERORGROUP lpDataGet = HeapAlloc( GetProcessHeap(), + HEAP_ZERO_MEMORY, + 1024 ); + DWORD dwDataSizeGet = 1024; + CallbackData callbackData; - test_CreatePlayer(); - test_GetPlayerCaps(); - test_PlayerData(); - test_PlayerName(); - test_GetPlayerAccount(); - test_GetPlayerAddress(); - test_GetPlayerFlags(); + + CoCreateInstance( &CLSID_DirectPlay, NULL, CLSCTX_ALL, + &IID_IDirectPlay4A, (LPVOID*) &pDP ); + ZeroMemory( &dpsd, sizeof(DPSESSIONDESC2) ); + dpsd.dwSize = sizeof(DPSESSIONDESC2); + dpsd.guidApplication = appGuid; + dpsd.dwMaxPlayers = 10; + ZeroMemory( &groupName, sizeof(DPNAME) ); + + + /* No service provider */ + hr = IDirectPlayX_CreateGroup( pDP, &idGroup, NULL, NULL, 0, 0 ); + checkHR( DPERR_UNINITIALIZED, hr ); + + hr = IDirectPlayX_CreateGroupInGroup( pDP, 0, &idGroup, NULL, NULL, 0, 0 ); + checkHR( DPERR_UNINITIALIZED, hr ); + + + + init_TCPIP_provider( pDP, "127.0.0.1", 0 ); + + + /* No session */ + hr = IDirectPlayX_CreateGroup( pDP, &idGroup, + NULL, NULL, 0, 0 ); + todo_wine checkHR( DPERR_INVALIDPARAMS, hr ); + + if ( hr == DPERR_UNINITIALIZED ) + { + skip( "CreateGroup not implemented\n" ); + return; + } + + hr = IDirectPlayX_CreateGroupInGroup( pDP, 0, &idGroup, + NULL, NULL, 0, 0 ); + checkHR( DPERR_INVALIDGROUP, hr ); + + hr = IDirectPlayX_CreateGroupInGroup( pDP, 2, &idGroup, + NULL, NULL, 0, 0 ); + checkHR( DPERR_INVALIDGROUP, hr ); + + + hr = IDirectPlayX_Open( pDP, &dpsd, DPOPEN_CREATE ); + checkHR( DP_OK, hr ); + IDirectPlayX_CreatePlayer( pDP, &dpid, + NULL, NULL, NULL, 0, 0 ); + + + + /* With name */ + hr = IDirectPlayX_CreateGroup( pDP, &idGroup, + NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_CreateGroupInGroup( pDP, idGroup, &idGroup, + NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_CreateGroup( pDP, &idGroup, + &groupName, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_CreateGroupInGroup( pDP, idGroup, &idGroup, + &groupName, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + + + groupName.dwSize = sizeof(DPNAME); + groupName.lpszShortNameA = (LPSTR) lpData; + + + hr = IDirectPlayX_CreateGroup( pDP, &idGroup, + &groupName, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_CreateGroupInGroup( pDP, idGroup, &idGroup, + &groupName, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + + + /* Message checking */ + for (i=0; i<6; i++) + { + dwDataSizeGet = 1024; + hr = IDirectPlayX_Receive( pDP, &idFrom, &idTo, 0, + (LPVOID) lpDataGet, &dwDataSizeGet ); + checkHR( DP_OK, hr ); + if ( NULL == lpDataGet->dpnName.lpszShortNameA ) + { + check( 48, dwDataSizeGet ); + } + else + { + check( 48 + dwDataSize, dwDataSizeGet ); + checkStr( lpData, lpDataGet->dpnName.lpszShortNameA ); + } + check( DPID_SYSMSG, idFrom ); + checkConv( DPSYS_CREATEPLAYERORGROUP, lpDataGet->dwType, dpMsgType2str ); + check( DPPLAYERTYPE_GROUP, lpDataGet->dwPlayerType ); + checkFlags( DPGROUP_LOCAL, lpDataGet->dwFlags, FLAGS_DPGROUP ); + } + check_messages( pDP, &dpid, 1, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + + + /* With data */ + hr = IDirectPlayX_CreateGroup( pDP, &idGroup, + NULL, (LPVOID) lpData, -1, 0 ); + checkHR( DPERR_INVALIDPARAMS, hr ); + + hr = IDirectPlayX_CreateGroup( pDP, &idGroup, + NULL, (LPVOID) lpData, 0, 0 ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_CreateGroup( pDP, &idGroup, + NULL, NULL, dwDataSize, 0 ); + checkHR( DPERR_INVALIDPARAMS, hr ); + + hr = IDirectPlayX_CreateGroup( pDP, &idGroup, + NULL, (LPVOID) lpData, dwDataSize, 0 ); + checkHR( DP_OK, hr ); + + + hr = IDirectPlayX_CreateGroupInGroup( pDP, idGroup, &idGroup, + NULL, (LPVOID) lpData, -1, 0 ); + checkHR( DPERR_INVALIDPARAMS, hr ); + + hr = IDirectPlayX_CreateGroupInGroup( pDP, idGroup, &idGroup, + NULL, (LPVOID) lpData, 0, 0 ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_CreateGroupInGroup( pDP, idGroup, &idGroup, + NULL, NULL, dwDataSize, 0 ); + checkHR( DPERR_INVALIDPARAMS, hr ); + + hr = IDirectPlayX_CreateGroupInGroup( pDP, idGroup, &idGroup, + NULL, (LPVOID)lpData, dwDataSize, 0 ); + checkHR( DP_OK, hr ); + + + hr = IDirectPlayX_CreateGroup( pDP, &idGroupParent, + NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + + + /* Message checking */ + for (i=0; i<5; i++) + { + dwDataSizeGet = 1024; + hr = IDirectPlayX_Receive( pDP, &idFrom, &idTo, 0, + (LPVOID) lpDataGet, &dwDataSizeGet ); + checkHR( DP_OK, hr ); + check( 48 + lpDataGet->dwDataSize, dwDataSizeGet ); + check( DPID_SYSMSG, idFrom ); + checkConv( DPSYS_CREATEPLAYERORGROUP, lpDataGet->dwType, dpMsgType2str ); + check( DPPLAYERTYPE_GROUP, lpDataGet->dwPlayerType ); + checkFlags( DPGROUP_LOCAL, lpDataGet->dwFlags, FLAGS_DPGROUP ); + } + check_messages( pDP, &dpid, 1, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + + + /* Flags and idGroupParent */ + hr = IDirectPlayX_CreateGroup( pDP, &idGroup, + NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_CreateGroup( pDP, &idGroup, + NULL, NULL, 0, DPGROUP_HIDDEN ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_CreateGroup( pDP, &idGroup, + NULL, NULL, 0, DPGROUP_STAGINGAREA ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_CreateGroup( pDP, &idGroup, + NULL, NULL, 0, + DPGROUP_HIDDEN | DPGROUP_STAGINGAREA ); + checkHR( DP_OK, hr ); + + + hr = IDirectPlayX_CreateGroupInGroup( pDP, idGroupParent, &idGroup, + NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_CreateGroupInGroup( pDP, idGroupParent, &idGroup, + NULL, NULL, 0, DPGROUP_HIDDEN ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_CreateGroupInGroup( pDP, idGroupParent, &idGroup, + NULL, NULL, 0, DPGROUP_STAGINGAREA ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_CreateGroupInGroup( pDP, idGroupParent, &idGroup, + NULL, NULL, 0, + DPGROUP_HIDDEN | + DPGROUP_STAGINGAREA ); + checkHR( DP_OK, hr ); + + + /* Message checking */ + for (i=0; i<8; i++) + { + dwDataSizeGet = 1024; + hr = IDirectPlayX_Receive( pDP, &idFrom, &idTo, 0, + (LPVOID) lpDataGet, &dwDataSizeGet ); + checkHR( DP_OK, hr ); + check( 48, dwDataSizeGet ); + check( DPID_SYSMSG, idFrom ); + checkConv( DPSYS_CREATEPLAYERORGROUP, lpDataGet->dwType, dpMsgType2str ); + check( DPPLAYERTYPE_GROUP, lpDataGet->dwPlayerType ); + + if ( lpDataGet->dpIdParent != 0 ) + { + check( idGroupParent, lpDataGet->dpIdParent ); + } + + switch (i%4) + { + case 0: + checkFlags( DPGROUP_LOCAL, + lpDataGet->dwFlags, FLAGS_DPGROUP ); + break; + case 1: + checkFlags( DPGROUP_LOCAL | DPGROUP_HIDDEN, + lpDataGet->dwFlags, FLAGS_DPGROUP ); + break; + case 2: + checkFlags( DPGROUP_STAGINGAREA | DPGROUP_LOCAL, + lpDataGet->dwFlags, FLAGS_DPGROUP ); + break; + case 3: + checkFlags( DPGROUP_STAGINGAREA | DPGROUP_LOCAL | DPGROUP_HIDDEN, + lpDataGet->dwFlags, FLAGS_DPGROUP ); + break; + default: break; + } + } + check_messages( pDP, &dpid, 1, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + + + /* If a group is created in C/S mode, no messages are sent */ + + /* - Peer 2 peer */ + IDirectPlayX_Close( pDP ); + + dpsd.dwFlags = 0; + hr = IDirectPlayX_Open( pDP, &dpsd, DPOPEN_CREATE ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreatePlayer( pDP, &dpid, NULL, NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_CreateGroup( pDP, &idGroup, NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + + /* Messages are received */ + check_messages( pDP, &dpid, 1, &callbackData ); + checkStr( "S0,", callbackData.szTrace1 ); + + + /* - Client/Server */ + IDirectPlayX_Close( pDP ); + + dpsd.dwFlags = DPSESSION_CLIENTSERVER; + hr = IDirectPlayX_Open( pDP, &dpsd, DPOPEN_CREATE ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreatePlayer( pDP, &dpid, + NULL, NULL, NULL, 0, + DPPLAYER_SERVERPLAYER ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_CreateGroup( pDP, &idGroup, + NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + + /* No messages */ + check_messages( pDP, &dpid, 1, &callbackData ); + checkStr( "S0,", callbackData.szTrace1 ); /* Or at least there + shouldn't be messages... */ + + + HeapFree( GetProcessHeap(), 0, lpDataGet ); + IDirectPlayX_Release( pDP ); + +} + +/* GroupOwner */ + +static void test_GroupOwner(void) +{ + + LPDIRECTPLAY4 pDP[2]; + DPSESSIONDESC2 dpsd; + DPID dpid[2], idGroup, idOwner; + HRESULT hr; + UINT i; + + + for (i=0; i<2; i++) + { + CoCreateInstance( &CLSID_DirectPlay, NULL, CLSCTX_ALL, + &IID_IDirectPlay4A, (LPVOID*) &pDP[i] ); + } + ZeroMemory( &dpsd, sizeof(DPSESSIONDESC2) ); + dpsd.dwSize = sizeof(DPSESSIONDESC2); + dpsd.guidApplication = appGuid; + dpsd.dwMaxPlayers = 10; + idGroup = 0; + idOwner = 0; + + /* Service provider not initialized */ + hr = IDirectPlayX_GetGroupOwner( pDP[0], idGroup, &idOwner ); + todo_wine checkHR( DPERR_UNINITIALIZED, hr ); + check( 0, idOwner ); + + if ( hr == DP_OK ) + { + skip( "GetGroupOwner not implemented\n" ); + return; + } + + + for (i=0; i<2; i++) + init_TCPIP_provider( pDP[i], "127.0.0.1", 0 ); + + hr = IDirectPlayX_Open( pDP[0], &dpsd, DPOPEN_CREATE ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_EnumSessions( pDP[1], &dpsd, 0, EnumSessions_cb_join, + (LPVOID) pDP[1], 0 ); + checkHR( DP_OK, hr ); + + for (i=0; i<2; i++) + { + hr = IDirectPlayX_CreatePlayer( pDP[i], &dpid[i], + NULL, NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + } + + /* Invalid group */ + hr = IDirectPlayX_GetGroupOwner( pDP[0], idGroup, &idOwner ); + checkHR( DPERR_INVALIDGROUP, hr ); + + hr = IDirectPlayX_CreateGroup( pDP[0], &idGroup, NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + + /* Fails, because we need a lobby session */ + hr = IDirectPlayX_GetGroupOwner( pDP[0], idGroup, &idOwner ); + checkHR( DPERR_UNSUPPORTED, hr ); + + + /* TODO: + * - Make this work + * - Check migration of the ownership of a group + * when the owner leaves + */ + + + IDirectPlayX_Release( pDP[0] ); + IDirectPlayX_Release( pDP[1] ); + +} + +/* EnumPlayers */ + +static BOOL CALLBACK EnumPlayers_cb( DPID dpId, + DWORD dwPlayerType, + LPCDPNAME lpName, + DWORD dwFlags, + LPVOID lpContext ) +{ + lpCallbackData callbackData = (lpCallbackData) lpContext; + char playerIndex = dpid2char( callbackData->dpid, + callbackData->dpidSize, + dpId ); + + + /* Trace to study player ids */ + callbackData->szTrace1[ callbackData->dwCounter1 ] = playerIndex; + callbackData->dwCounter1++; + callbackData->szTrace1[ callbackData->dwCounter1 ] = '\0'; + + /* Trace to study flags received */ + strcat( callbackData->szTrace2, + ( dwFlags2str(dwFlags, FLAGS_DPENUMPLAYERS) + + strlen("DPENUMPLAYERS_") ) ); + strcat( callbackData->szTrace2, ":" ); + + + if ( playerIndex < '5' ) + { + check( DPPLAYERTYPE_PLAYER, dwPlayerType ); + } + else + { + check( DPPLAYERTYPE_GROUP, dwPlayerType ); + } + + return TRUE; + +} + +static BOOL CALLBACK EnumSessions_cb_EnumPlayers( LPCDPSESSIONDESC2 lpThisSD, + LPDWORD lpdwTimeOut, + DWORD dwFlags, + LPVOID lpContext ) +{ + lpCallbackData callbackData = (lpCallbackData) lpContext; + HRESULT hr; + + if (dwFlags & DPESC_TIMEDOUT) + { + return FALSE; + } + + /* guid = NULL */ + callbackData->dwCounter1 = 0; + hr = IDirectPlayX_EnumPlayers( callbackData->pDP, NULL, + EnumPlayers_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DPERR_NOSESSIONS, hr ); + check( 0, callbackData->dwCounter1 ); + + /* guid = appGuid */ + callbackData->dwCounter1 = 0; + hr = IDirectPlayX_EnumPlayers( callbackData->pDP, (LPGUID) &appGuid, + EnumPlayers_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DPERR_NOSESSIONS, hr ); + check( 0, callbackData->dwCounter1 ); + + callbackData->dwCounter1 = 0; + hr = IDirectPlayX_EnumPlayers( callbackData->pDP, (LPGUID) &appGuid, + EnumPlayers_cb, + (LPVOID) &callbackData, + DPENUMPLAYERS_SESSION ); + checkHR( DPERR_NOSESSIONS, hr ); + check( 0, callbackData->dwCounter1 ); + + /* guid = guidInstance */ + callbackData->dwCounter1 = 0; + hr = IDirectPlayX_EnumPlayers( callbackData->pDP, + (LPGUID) &lpThisSD->guidInstance, + EnumPlayers_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DPERR_NOSESSIONS, hr ); + check( 0, callbackData->dwCounter1 ); + + callbackData->dwCounter1 = 0; + hr = IDirectPlayX_EnumPlayers( callbackData->pDP, + (LPGUID) &lpThisSD->guidInstance, + EnumPlayers_cb, + (LPVOID) &callbackData, + DPENUMPLAYERS_SESSION ); + checkHR( DPERR_GENERIC, hr ); /* Why? */ + check( 0, callbackData->dwCounter1 ); + + return TRUE; + +} + +static void test_EnumPlayers(void) +{ + LPDIRECTPLAY4 pDP[3]; + DPSESSIONDESC2 dpsd[3]; + DPID dpid[5+2]; /* 5 players, 2 groups */ + CallbackData callbackData; + HRESULT hr; + UINT i; + + + for (i=0; i<3; i++) + { + CoCreateInstance( &CLSID_DirectPlay, NULL, CLSCTX_ALL, + &IID_IDirectPlay4A, (LPVOID*) &pDP[i] ); + + ZeroMemory( &dpsd[i], sizeof(DPSESSIONDESC2) ); + dpsd[i].dwSize = sizeof(DPSESSIONDESC2); + } + + dpsd[0].guidApplication = appGuid; + dpsd[1].guidApplication = appGuid2; + dpsd[2].guidApplication = GUID_NULL; + + callbackData.dpid = dpid; + callbackData.dpidSize = 5+2; + + + /* Uninitialized service provider */ + callbackData.dwCounter1 = 0; + hr = IDirectPlayX_EnumPlayers( pDP[0], (LPGUID) &appGuid, NULL, + (LPVOID) &callbackData, 0 ); + checkHR( DPERR_UNINITIALIZED, hr ); + check( 0, callbackData.dwCounter1 ); + + + init_TCPIP_provider( pDP[0], "127.0.0.1", 0 ); + init_TCPIP_provider( pDP[1], "127.0.0.1", 0 ); + init_TCPIP_provider( pDP[2], "127.0.0.1", 0 ); + + + /* No session */ + callbackData.dwCounter1 = 0; + hr = IDirectPlayX_EnumPlayers( pDP[0], NULL, EnumPlayers_cb, + (LPVOID) &callbackData, 0 ); + todo_wine checkHR( DPERR_NOSESSIONS, hr ); + check( 0, callbackData.dwCounter1 ); + + if ( hr == DPERR_UNINITIALIZED ) + { + skip( "EnumPlayers not implemented\n" ); + return; + } + + callbackData.dwCounter1 = 0; + hr = IDirectPlayX_EnumPlayers( pDP[0], (LPGUID) &appGuid, EnumPlayers_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DPERR_NOSESSIONS, hr ); + check( 0, callbackData.dwCounter1 ); + + callbackData.dwCounter1 = 0; + hr = IDirectPlayX_EnumPlayers( pDP[0], (LPGUID) &appGuid, EnumPlayers_cb, + (LPVOID) &callbackData, + DPENUMPLAYERS_SESSION ); + checkHR( DPERR_NOSESSIONS, hr ); + check( 0, callbackData.dwCounter1 ); + + + hr = IDirectPlayX_Open( pDP[0], &dpsd[0], DPOPEN_CREATE ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_Open( pDP[1], &dpsd[1], DPOPEN_CREATE ); + checkHR( DP_OK, hr ); + + + /* No players */ + callbackData.dwCounter1 = 0; + hr = IDirectPlayX_EnumPlayers( pDP[0], NULL, EnumPlayers_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DP_OK, hr ); + check( 0, callbackData.dwCounter1 ); + + + /* Create players */ + hr = IDirectPlayX_CreatePlayer( pDP[0], &dpid[0], + NULL, NULL, NULL, 0, + DPPLAYER_SERVERPLAYER ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreatePlayer( pDP[1], &dpid[1], + NULL, NULL, NULL, 0, + 0 ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_CreatePlayer( pDP[0], &dpid[2], + NULL, NULL, NULL, 0, + 0 ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreateGroup( pDP[0], &dpid[5], + NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + + + /* Invalid parameters */ + callbackData.dwCounter1 = 0; + hr = IDirectPlayX_EnumPlayers( pDP[0], (LPGUID) &appGuid, NULL, + (LPVOID) &callbackData, 0 ); + checkHR( DPERR_INVALIDPARAMS, hr ); + check( 0, callbackData.dwCounter1 ); + + callbackData.dwCounter1 = 0; + hr = IDirectPlayX_EnumPlayers( pDP[0], NULL, EnumPlayers_cb, + (LPVOID) &callbackData, + DPENUMPLAYERS_SESSION ); + checkHR( DPERR_INVALIDPARAMS, hr ); + check( 0, callbackData.dwCounter1 ); + + + /* Regular operation */ + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumPlayers( pDP[0], NULL, EnumPlayers_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DP_OK, hr ); + check( 2, callbackData.dwCounter1 ); + checkStr( "20", callbackData.szTrace1 ); + checkStr( "ALL:SERVERPLAYER:", callbackData.szTrace2 ); + + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumPlayers( pDP[1], NULL, EnumPlayers_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DP_OK, hr ); + check( 1, callbackData.dwCounter1 ); + checkStr( "1", callbackData.szTrace1 ); + checkStr( "ALL:", callbackData.szTrace2 ); + + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumPlayers( pDP[0], (LPGUID) &appGuid, EnumPlayers_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DP_OK, hr ); + check( 2, callbackData.dwCounter1 ); /* Guid is ignored */ + checkStr( "20", callbackData.szTrace1 ); + checkStr( "ALL:SERVERPLAYER:", callbackData.szTrace2 ); + + + /* Enumerating from a remote session */ + /* - Session not open */ + callbackData.pDP = pDP[2]; + hr = IDirectPlayX_EnumSessions( pDP[2], &dpsd[2], 0, + EnumSessions_cb_EnumPlayers, + (LPVOID) &callbackData, 0 ); + checkHR( DP_OK, hr ); + + + /* - Open session */ + callbackData.pDP = pDP[2]; + hr = IDirectPlayX_EnumSessions( pDP[2], &dpsd[0], 0, EnumSessions_cb_join, + (LPVOID) pDP[2], 0 ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreatePlayer( pDP[2], &dpid[3], + NULL, NULL, NULL, 0, + DPPLAYER_SPECTATOR ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreatePlayer( pDP[2], &dpid[4], + NULL, NULL, NULL, 0, + 0 ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreateGroup( pDP[2], &dpid[6], + NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumPlayers( pDP[2], NULL, EnumPlayers_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DP_OK, hr ); + check( 4, callbackData.dwCounter1 ); + checkStr( "4302", callbackData.szTrace1 ); + checkStr( "ALL:SPECTATOR:SERVERPLAYER:ALL:", callbackData.szTrace2 ); + + + /* Flag tests */ + + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumPlayers( pDP[2], NULL, EnumPlayers_cb, + (LPVOID) &callbackData, + DPENUMPLAYERS_ALL ); + checkHR( DP_OK, hr ); + check( 4, callbackData.dwCounter1 ); + checkStr( "4302", callbackData.szTrace1 ); + checkStr( "ALL:SPECTATOR:SERVERPLAYER:ALL:", callbackData.szTrace2 ); + + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumPlayers( pDP[2], NULL, EnumPlayers_cb, + (LPVOID) &callbackData, + DPENUMPLAYERS_GROUP ); + checkHR( DP_OK, hr ); + check( 6, callbackData.dwCounter1 ); + checkStr( "430256", callbackData.szTrace1 ); + checkStr( "GROUP:" + "GROUP,DPENUMPLAYERS_SPECTATOR:" + "GROUP,DPENUMPLAYERS_SERVERPLAYER:" + "GROUP:ALL:ALL:", callbackData.szTrace2 ); + + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumPlayers( pDP[2], NULL, EnumPlayers_cb, + (LPVOID) &callbackData, + DPENUMPLAYERS_LOCAL ); + checkHR( DP_OK, hr ); + check( 2, callbackData.dwCounter1 ); + checkStr( "43", callbackData.szTrace1 ); + checkStr( "LOCAL:" + "LOCAL,DPENUMPLAYERS_SPECTATOR:", callbackData.szTrace2 ); + + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumPlayers( pDP[2], NULL, EnumPlayers_cb, + (LPVOID) &callbackData, + DPENUMPLAYERS_SERVERPLAYER ); + checkHR( DP_OK, hr ); + check( 1, callbackData.dwCounter1 ); + checkStr( "0", callbackData.szTrace1 ); + checkStr( "SERVERPLAYER:", callbackData.szTrace2 ); + + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumPlayers( pDP[2], NULL, EnumPlayers_cb, + (LPVOID) &callbackData, + DPENUMPLAYERS_SPECTATOR ); + checkHR( DP_OK, hr ); + check( 1, callbackData.dwCounter1 ); + checkStr( "3", callbackData.szTrace1 ); + checkStr( "SPECTATOR:", callbackData.szTrace2 ); + + + IDirectPlayX_Release( pDP[0] ); + IDirectPlayX_Release( pDP[1] ); + IDirectPlayX_Release( pDP[2] ); + +} + +/* EnumGroups */ + +static BOOL CALLBACK EnumGroups_cb( DPID dpId, + DWORD dwPlayerType, + LPCDPNAME lpName, + DWORD dwFlags, + LPVOID lpContext ) +{ + lpCallbackData callbackData = (lpCallbackData) lpContext; + char playerIndex = dpid2char( callbackData->dpid, + callbackData->dpidSize, + dpId ); + + + /* Trace to study player ids */ + callbackData->szTrace1[ callbackData->dwCounter1 ] = playerIndex; + callbackData->dwCounter1++; + callbackData->szTrace1[ callbackData->dwCounter1 ] = '\0'; + + /* Trace to study flags received */ + strcat( callbackData->szTrace2, + ( dwFlags2str(dwFlags, FLAGS_DPENUMGROUPS) + + strlen("DPENUMGROUPS_") ) ); + strcat( callbackData->szTrace2, ":" ); + + + check( DPPLAYERTYPE_GROUP, dwPlayerType ); + + return TRUE; +} + +static BOOL CALLBACK EnumSessions_cb_EnumGroups( LPCDPSESSIONDESC2 lpThisSD, + LPDWORD lpdwTimeOut, + DWORD dwFlags, + LPVOID lpContext ) +{ + lpCallbackData callbackData = (lpCallbackData) lpContext; + HRESULT hr; + + if (dwFlags & DPESC_TIMEDOUT) + { + return FALSE; + } + + /* guid = NULL */ + callbackData->dwCounter1 = 0; + hr = IDirectPlayX_EnumGroups( callbackData->pDP, NULL, + EnumGroups_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DPERR_NOSESSIONS, hr ); + check( 0, callbackData->dwCounter1 ); + + /* guid = appGuid */ + callbackData->dwCounter1 = 0; + hr = IDirectPlayX_EnumGroups( callbackData->pDP, (LPGUID) &appGuid, + EnumGroups_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DPERR_NOSESSIONS, hr ); + check( 0, callbackData->dwCounter1 ); + + callbackData->dwCounter1 = 0; + hr = IDirectPlayX_EnumGroups( callbackData->pDP, (LPGUID) &appGuid, + EnumGroups_cb, + (LPVOID) &callbackData, + DPENUMGROUPS_SESSION ); + checkHR( DPERR_NOSESSIONS, hr ); + check( 0, callbackData->dwCounter1 ); + + /* guid = guidInstance */ + callbackData->dwCounter1 = 0; + hr = IDirectPlayX_EnumGroups( callbackData->pDP, + (LPGUID) &lpThisSD->guidInstance, + EnumGroups_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DPERR_NOSESSIONS, hr ); + check( 0, callbackData->dwCounter1 ); + + callbackData->dwCounter1 = 0; + hr = IDirectPlayX_EnumGroups( callbackData->pDP, + (LPGUID) &lpThisSD->guidInstance, + EnumGroups_cb, + (LPVOID) &callbackData, + DPENUMGROUPS_SESSION ); + checkHR( DPERR_GENERIC, hr ); /* Why? */ + check( 0, callbackData->dwCounter1 ); + + return TRUE; + +} + +static void test_EnumGroups(void) +{ + LPDIRECTPLAY4 pDP[3]; + DPSESSIONDESC2 dpsd[3]; + DPID dpid[5]; + CallbackData callbackData; + HRESULT hr; + UINT i; + + + for (i=0; i<3; i++) + { + CoCreateInstance( &CLSID_DirectPlay, NULL, CLSCTX_ALL, + &IID_IDirectPlay4A, (LPVOID*) &pDP[i] ); + + ZeroMemory( &dpsd[i], sizeof(DPSESSIONDESC2) ); + dpsd[i].dwSize = sizeof(DPSESSIONDESC2); + } + + dpsd[0].guidApplication = appGuid; + dpsd[1].guidApplication = appGuid2; + dpsd[2].guidApplication = GUID_NULL; + + callbackData.dpid = dpid; + callbackData.dpidSize = 5; + + + /* Uninitialized service provider */ + callbackData.dwCounter1 = 0; + hr = IDirectPlayX_EnumGroups( pDP[0], NULL, EnumGroups_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DPERR_UNINITIALIZED, hr ); + check( 0, callbackData.dwCounter1 ); + + + init_TCPIP_provider( pDP[0], "127.0.0.1", 0 ); + init_TCPIP_provider( pDP[1], "127.0.0.1", 0 ); + init_TCPIP_provider( pDP[2], "127.0.0.1", 0 ); + + + /* No session */ + callbackData.dwCounter1 = 0; + hr = IDirectPlayX_EnumGroups( pDP[0], NULL, EnumGroups_cb, + (LPVOID) &callbackData, 0 ); + todo_wine checkHR( DPERR_NOSESSIONS, hr ); + check( 0, callbackData.dwCounter1 ); + + if ( hr == DPERR_UNINITIALIZED ) + { + skip( "EnumGroups not implemented\n" ); + return; + } + + callbackData.dwCounter1 = 0; + hr = IDirectPlayX_EnumGroups( pDP[0], (LPGUID) &appGuid, EnumGroups_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DPERR_NOSESSIONS, hr ); + check( 0, callbackData.dwCounter1 ); + + callbackData.dwCounter1 = 0; + hr = IDirectPlayX_EnumGroups( pDP[0], (LPGUID) &appGuid, EnumGroups_cb, + (LPVOID) &callbackData, + DPENUMGROUPS_SESSION ); + checkHR( DPERR_NOSESSIONS, hr ); + check( 0, callbackData.dwCounter1 ); + + + hr = IDirectPlayX_Open( pDP[0], &dpsd[0], DPOPEN_CREATE ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_Open( pDP[1], &dpsd[1], DPOPEN_CREATE ); + checkHR( DP_OK, hr ); + + + /* No groups */ + callbackData.dwCounter1 = 0; + hr = IDirectPlayX_EnumGroups( pDP[0], NULL, EnumGroups_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DP_OK, hr ); + check( 0, callbackData.dwCounter1 ); + + + /* Create groups */ + hr = IDirectPlayX_CreateGroup( pDP[0], &dpid[0], + NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreateGroupInGroup( pDP[0], dpid[0], &dpid[3], + NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); /* Not a superior level group, + won't appear in the enumerations */ + hr = IDirectPlayX_CreateGroup( pDP[1], &dpid[1], + NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreateGroup( pDP[0], &dpid[2], + NULL, NULL, 0, DPGROUP_HIDDEN ); + checkHR( DP_OK, hr ); + + + /* Invalid parameters */ + callbackData.dwCounter1 = 0; + hr = IDirectPlayX_EnumGroups( pDP[0], (LPGUID) &appGuid, NULL, + (LPVOID) &callbackData, 0 ); + checkHR( DPERR_INVALIDPARAMS, hr ); + check( 0, callbackData.dwCounter1 ); + + callbackData.dwCounter1 = 0; + hr = IDirectPlayX_EnumGroups( pDP[0], NULL, EnumGroups_cb, + (LPVOID) &callbackData, + DPENUMGROUPS_SESSION ); + checkHR( DPERR_INVALIDPARAMS, hr ); + check( 0, callbackData.dwCounter1 ); + + + /* Regular operation */ + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumGroups( pDP[0], NULL, EnumGroups_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DP_OK, hr ); + check( 2, callbackData.dwCounter1 ); + checkStr( "02", callbackData.szTrace1 ); + checkStr( "ALL:HIDDEN:", callbackData.szTrace2 ); + + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumGroups( pDP[1], NULL, EnumGroups_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DP_OK, hr ); + check( 1, callbackData.dwCounter1 ); + checkStr( "1", callbackData.szTrace1 ); + checkStr( "ALL:", callbackData.szTrace2 ); + + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumGroups( pDP[0], (LPGUID) &appGuid, EnumGroups_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DP_OK, hr ); + check( 2, callbackData.dwCounter1 ); /* Guid is ignored */ + checkStr( "02", callbackData.szTrace1 ); + checkStr( "ALL:HIDDEN:", callbackData.szTrace2 ); + + + /* Enumerating from a remote session */ + /* - Session not open */ + callbackData.pDP = pDP[2]; + hr = IDirectPlayX_EnumSessions( pDP[2], &dpsd[2], 0, + EnumSessions_cb_EnumGroups, + (LPVOID) &callbackData, 0 ); + checkHR( DP_OK, hr ); + + /* - Open session */ + callbackData.pDP = pDP[2]; + hr = IDirectPlayX_EnumSessions( pDP[2], &dpsd[0], 0, EnumSessions_cb_join, + (LPVOID) pDP[2], 0 ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_CreateGroup( pDP[2], &dpid[3], + NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreateGroup( pDP[2], &dpid[4], + NULL, NULL, 0, DPGROUP_STAGINGAREA ); + checkHR( DP_OK, hr ); + + + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumGroups( pDP[2], NULL, EnumGroups_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DP_OK, hr ); + check( 4, callbackData.dwCounter1 ); + checkStr( "0234", callbackData.szTrace1 ); + checkStr( "ALL:HIDDEN:ALL:STAGINGAREA:", callbackData.szTrace2 ); + + /* Flag tests */ + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumGroups( pDP[2], NULL, EnumGroups_cb, + (LPVOID) &callbackData, + DPENUMGROUPS_ALL ); + checkHR( DP_OK, hr ); + check( 4, callbackData.dwCounter1 ); + checkStr( "0234", callbackData.szTrace1 ); + checkStr( "ALL:HIDDEN:ALL:STAGINGAREA:", callbackData.szTrace2 ); + + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumGroups( pDP[2], NULL, EnumGroups_cb, + (LPVOID) &callbackData, + DPENUMGROUPS_HIDDEN ); + checkHR( DP_OK, hr ); + check( 1, callbackData.dwCounter1 ); + checkStr( "2", callbackData.szTrace1 ); + checkStr( "HIDDEN:", callbackData.szTrace2 ); + + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumGroups( pDP[2], NULL, EnumGroups_cb, + (LPVOID) &callbackData, + DPENUMGROUPS_LOCAL ); + checkHR( DP_OK, hr ); + check( 2, callbackData.dwCounter1 ); + checkStr( "34", callbackData.szTrace1 ); + checkStr( "LOCAL:" + "LOCAL,DPENUMGROUPS_STAGINGAREA:", callbackData.szTrace2 ); + + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumGroups( pDP[2], NULL, EnumGroups_cb, + (LPVOID) &callbackData, + DPENUMGROUPS_REMOTE ); + checkHR( DP_OK, hr ); + check( 2, callbackData.dwCounter1 ); + checkStr( "02", callbackData.szTrace1 ); + checkStr( "REMOTE:" + "REMOTE,DPENUMGROUPS_HIDDEN:", callbackData.szTrace2 ); + + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumGroups( pDP[2], NULL, EnumGroups_cb, + (LPVOID) &callbackData, + DPENUMGROUPS_STAGINGAREA ); + checkHR( DP_OK, hr ); + check( 1, callbackData.dwCounter1 ); + checkStr( "4", callbackData.szTrace1 ); + checkStr( "STAGINGAREA:", callbackData.szTrace2 ); + + + IDirectPlayX_Release( pDP[0] ); + IDirectPlayX_Release( pDP[1] ); + IDirectPlayX_Release( pDP[2] ); + +} + +static void test_EnumGroupsInGroup(void) +{ + LPDIRECTPLAY4 pDP[2]; + DPSESSIONDESC2 dpsd[2]; + DPID dpid[6]; + CallbackData callbackData; + HRESULT hr; + UINT i; + + + for (i=0; i<2; i++) + { + CoCreateInstance( &CLSID_DirectPlay, NULL, CLSCTX_ALL, + &IID_IDirectPlay4A, (LPVOID*) &pDP[i] ); + + ZeroMemory( &dpsd[i], sizeof(DPSESSIONDESC2) ); + dpsd[i].dwSize = sizeof(DPSESSIONDESC2); + } + + dpsd[0].guidApplication = appGuid; + dpsd[1].guidApplication = GUID_NULL; + + callbackData.dpid = dpid; + callbackData.dpidSize = 6; + + + /* Uninitialized service provider */ + callbackData.dwCounter1 = 0; + hr = IDirectPlayX_EnumGroupsInGroup( pDP[0], 0, NULL, EnumGroups_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DPERR_UNINITIALIZED, hr ); + check( 0, callbackData.dwCounter1 ); + + + init_TCPIP_provider( pDP[0], "127.0.0.1", 0 ); + init_TCPIP_provider( pDP[1], "127.0.0.1", 0 ); + + hr = IDirectPlayX_Open( pDP[0], &dpsd[0], DPOPEN_CREATE ); + todo_wine checkHR( DP_OK, hr ); + + if ( hr == DPERR_UNINITIALIZED ) + { + skip( "EnumGroupsInGroup not implemented\n" ); + return; + } + + /* Create groups */ + /* + * 0 + * / 2 + * 1 | 3 + * | 4 + * \ 5 (shortcut) + */ + hr = IDirectPlayX_CreateGroup( pDP[0], &dpid[0], + NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreateGroup( pDP[0], &dpid[1], + NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreateGroupInGroup( pDP[0], dpid[1], &dpid[2], + NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreateGroupInGroup( pDP[0], dpid[1], &dpid[3], + NULL, NULL, 0, + DPGROUP_HIDDEN ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreateGroupInGroup( pDP[0], dpid[1], &dpid[4], + NULL, NULL, 0, + DPGROUP_STAGINGAREA ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreateGroup( pDP[0], &dpid[5], + NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_AddGroupToGroup( pDP[0], dpid[1], dpid[5] ); + checkHR( DP_OK, hr ); + + + /* Invalid parameters */ + callbackData.dwCounter1 = 0; + hr = IDirectPlayX_EnumGroupsInGroup( pDP[0], 0, NULL, EnumGroups_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DPERR_INVALIDGROUP, hr ); + check( 0, callbackData.dwCounter1 ); + + callbackData.dwCounter1 = 0; + hr = IDirectPlayX_EnumGroupsInGroup( pDP[0], 10, NULL, EnumGroups_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DPERR_INVALIDGROUP, hr ); + check( 0, callbackData.dwCounter1 ); + + callbackData.dwCounter1 = 0; + hr = IDirectPlayX_EnumGroupsInGroup( pDP[0], dpid[1], (LPGUID) &appGuid, + NULL, (LPVOID) &callbackData, 0 ); + checkHR( DPERR_INVALIDPARAMS, hr ); + check( 0, callbackData.dwCounter1 ); + + callbackData.dwCounter1 = 0; + hr = IDirectPlayX_EnumGroupsInGroup( pDP[0], dpid[1], NULL, EnumGroups_cb, + (LPVOID) &callbackData, + DPENUMGROUPS_SESSION ); + checkHR( DPERR_INVALIDPARAMS, hr ); + check( 0, callbackData.dwCounter1 ); + + + /* Regular operation */ + callbackData.dwCounter1 = 0; + hr = IDirectPlayX_EnumGroupsInGroup( pDP[0], dpid[0], NULL, EnumGroups_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DP_OK, hr ); + check( 0, callbackData.dwCounter1 ); + + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumGroupsInGroup( pDP[0], dpid[1], NULL, EnumGroups_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DP_OK, hr ); + check( 4, callbackData.dwCounter1 ); + checkStr( "5432", callbackData.szTrace1 ); + checkStr( "SHORTCUT:STAGINGAREA:HIDDEN:ALL:", callbackData.szTrace2 ); + + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumGroupsInGroup( pDP[0], dpid[1], (LPGUID) &appGuid, + EnumGroups_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DP_OK, hr ); + check( 4, callbackData.dwCounter1 ); /* Guid is ignored */ + checkStr( "5432", callbackData.szTrace1 ); + checkStr( "SHORTCUT:STAGINGAREA:HIDDEN:ALL:", callbackData.szTrace2 ); + + + /* Enumerating from a remote session */ + /* - Session not open */ + callbackData.pDP = pDP[1]; + hr = IDirectPlayX_EnumSessions( pDP[1], &dpsd[1], 0, + EnumSessions_cb_EnumGroups, + (LPVOID) &callbackData, 0 ); + checkHR( DP_OK, hr ); + + /* - Open session */ + callbackData.pDP = pDP[1]; + hr = IDirectPlayX_EnumSessions( pDP[1], &dpsd[0], 0, EnumSessions_cb_join, + (LPVOID) pDP[2], 0 ); + checkHR( DP_OK, hr ); + + + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumGroupsInGroup( pDP[1], dpid[1], NULL, EnumGroups_cb, + (LPVOID) &callbackData, 0 ); + checkHR( DP_OK, hr ); + check( 4, callbackData.dwCounter1 ); + checkStr( "5432", callbackData.szTrace1 ); + checkStr( "SHORTCUT:STAGINGAREA:HIDDEN:ALL:", callbackData.szTrace2 ); + + /* Flag tests */ + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumGroupsInGroup( pDP[0], dpid[1], NULL, EnumGroups_cb, + (LPVOID) &callbackData, + DPENUMGROUPS_ALL ); + checkHR( DP_OK, hr ); + check( 4, callbackData.dwCounter1 ); + checkStr( "5432", callbackData.szTrace1 ); + checkStr( "SHORTCUT:STAGINGAREA:HIDDEN:ALL:", callbackData.szTrace2 ); + + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumGroupsInGroup( pDP[0], dpid[1], NULL, EnumGroups_cb, + (LPVOID) &callbackData, + DPENUMGROUPS_HIDDEN ); + checkHR( DP_OK, hr ); + check( 1, callbackData.dwCounter1 ); + checkStr( "3", callbackData.szTrace1 ); + checkStr( "HIDDEN:", callbackData.szTrace2 ); + + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumGroupsInGroup( pDP[0], dpid[1], NULL, EnumGroups_cb, + (LPVOID) &callbackData, + DPENUMGROUPS_LOCAL ); + checkHR( DP_OK, hr ); + check( 4, callbackData.dwCounter1 ); + checkStr( "5432", callbackData.szTrace1 ); + checkStr( "LOCAL,DPENUMGROUPS_SHORTCUT:" + "LOCAL,DPENUMGROUPS_STAGINGAREA:" + "LOCAL,DPENUMGROUPS_HIDDEN:LOCAL:", callbackData.szTrace2 ); + + callbackData.dwCounter1 = 0; + hr = IDirectPlayX_EnumGroupsInGroup( pDP[0], dpid[1], NULL, EnumGroups_cb, + (LPVOID) &callbackData, + DPENUMGROUPS_REMOTE ); + checkHR( DP_OK, hr ); + check( 0, callbackData.dwCounter1 ); + + callbackData.dwCounter1 = 0; + hr = IDirectPlayX_EnumGroupsInGroup( pDP[1], dpid[1], NULL, EnumGroups_cb, + (LPVOID) &callbackData, + DPENUMGROUPS_LOCAL ); + checkHR( DP_OK, hr ); + check( 0, callbackData.dwCounter1 ); + + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumGroupsInGroup( pDP[1], dpid[1], NULL, EnumGroups_cb, + (LPVOID) &callbackData, + DPENUMGROUPS_REMOTE ); + checkHR( DP_OK, hr ); + check( 4, callbackData.dwCounter1 ); + checkStr( "5432", callbackData.szTrace1 ); + checkStr( "REMOTE,DPENUMGROUPS_SHORTCUT:" + "REMOTE,DPENUMGROUPS_STAGINGAREA:" + "REMOTE,DPENUMGROUPS_HIDDEN:REMOTE:", callbackData.szTrace2 ); + + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumGroupsInGroup( pDP[0], dpid[1], NULL, EnumGroups_cb, + (LPVOID) &callbackData, + DPENUMGROUPS_SHORTCUT ); + checkHR( DP_OK, hr ); + check( 1, callbackData.dwCounter1 ); + checkStr( "5", callbackData.szTrace1 ); + checkStr( "SHORTCUT:", callbackData.szTrace2 ); + + callbackData.dwCounter1 = 0; + callbackData.szTrace2[0] = 0; + hr = IDirectPlayX_EnumGroupsInGroup( pDP[0], dpid[1], NULL, EnumGroups_cb, + (LPVOID) &callbackData, + DPENUMGROUPS_STAGINGAREA ); + checkHR( DP_OK, hr ); + check( 1, callbackData.dwCounter1 ); + checkStr( "4", callbackData.szTrace1 ); + checkStr( "STAGINGAREA:", callbackData.szTrace2 ); + + + IDirectPlayX_Release( pDP[0] ); + IDirectPlayX_Release( pDP[1] ); + +} + +static void test_groups_p2p(void) +{ + + LPDIRECTPLAY4 pDP[2]; + DPSESSIONDESC2 dpsd; + DPID idPlayer[6], idGroup[3]; + HRESULT hr; + UINT i; + + DWORD dwDataSize = 1024; + LPVOID lpData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 1024 ); + CallbackData callbackData; + + + for (i=0; i<2; i++) + { + CoCreateInstance( &CLSID_DirectPlay, NULL, CLSCTX_ALL, + &IID_IDirectPlay4A, (LPVOID*) &pDP[i] ); + } + ZeroMemory( &dpsd, sizeof(DPSESSIONDESC2) ); + dpsd.dwSize = sizeof(DPSESSIONDESC2); + dpsd.guidApplication = appGuid; + dpsd.dwMaxPlayers = 10; + + + init_TCPIP_provider( pDP[0], "127.0.0.1", 0 ); + init_TCPIP_provider( pDP[1], "127.0.0.1", 0 ); + + hr = IDirectPlayX_Open( pDP[0], &dpsd, DPOPEN_CREATE ); + todo_wine checkHR( DP_OK, hr ); + hr = IDirectPlayX_EnumSessions( pDP[1], &dpsd, 0, EnumSessions_cb_join, + (LPVOID) pDP[1], 0 ); + todo_wine checkHR( DP_OK, hr ); + + if ( hr == DPERR_UNINITIALIZED ) + { + skip( "dplay not implemented enough for this test yet\n" ); + return; + } + + + /* Create players */ + hr = IDirectPlayX_CreatePlayer( pDP[0], &idPlayer[0], + NULL, NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreatePlayer( pDP[0], &idPlayer[1], + NULL, NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreatePlayer( pDP[0], &idPlayer[2], + NULL, NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreatePlayer( pDP[1], &idPlayer[3], + NULL, NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreatePlayer( pDP[1], &idPlayer[4], + NULL, NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreatePlayer( pDP[1], &idPlayer[5], + NULL, NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_CreateGroup( pDP[0], &idGroup[0], + NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreateGroup( pDP[1], &idGroup[2], + NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreateGroupInGroup( pDP[1], idGroup[2], &idGroup[1], + NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + + + /* Purge queues */ + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "S0," "S1,S0," + "S2,S1,S0," "S2,S1,S0," + "S2,S1,S0," "S2,S1,S0," + "S2,S1,S0," "S2,S1,S0,", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "S3," "S4,S3," + "S5,S4,S3," "S5,S4,S3," + "S5,S4,S3,", callbackData.szTrace1 ); + + + /* + * Player 0 | | + * Player 1 | Group 0 | pDP 0 + * Player 2 | | + * Player 3 | Group 1 ) | + * Player 4 | | Group 2 | pDP 1 + * Player 5 | | + */ + + /* Build groups */ + hr = IDirectPlayX_AddPlayerToGroup( pDP[0], idGroup[0], idPlayer[0] ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_AddPlayerToGroup( pDP[0], idGroup[0], idPlayer[1] ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_AddPlayerToGroup( pDP[0], idGroup[0], idPlayer[2] ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_AddPlayerToGroup( pDP[1], idGroup[1], idPlayer[3] ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_AddPlayerToGroup( pDP[1], idGroup[1], idPlayer[4] ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_AddPlayerToGroup( pDP[1], idGroup[2], idPlayer[4] ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_AddPlayerToGroup( pDP[1], idGroup[2], idPlayer[5] ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_AddGroupToGroup( pDP[1], idGroup[2], idGroup[1] ); + checkHR( DP_OK, hr ); + + /* Purge queues */ + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "S2,S1,S0," "S2,S1,S0," "S2,S1,S0," + "S2,S1,S0," "S2,S1,S0," "S2,S1,S0," + "S2,S1,S0,", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "S5,S4,S3," "S5,S4,S3," "S5,S4,S3," + "S5,S4,S3," "S5,S4,S3," "S5,S4,S3," + "S5,S4,S3,", callbackData.szTrace1 ); + + + /* Sending broadcast messages, and checking who receives them */ + + dwDataSize = 4; + /* 0 -> * */ + hr = IDirectPlayX_Send( pDP[0], idPlayer[0], DPID_ALLPLAYERS, 0, + lpData, dwDataSize ); + checkHR( DP_OK, hr ); + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "02,01,", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "05,04,03,", callbackData.szTrace1 ); + + /* 0 -> g0 */ + hr = IDirectPlayX_Send( pDP[0], idPlayer[0], idGroup[0], 0, + lpData, dwDataSize ); + checkHR( DP_OK, hr ); + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "02,01,", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + /* 0 -> g1 */ + hr = IDirectPlayX_Send( pDP[0], idPlayer[0], idGroup[1], 0, + lpData, dwDataSize ); + checkHR( DP_OK, hr ); + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "04,03,", callbackData.szTrace1 ); + /* 0 -> g2 */ + hr = IDirectPlayX_Send( pDP[0], idPlayer[0], idGroup[2], 0, + lpData, dwDataSize ); + checkHR( DP_OK, hr ); + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "05,04,", callbackData.szTrace1 ); + + /* 3 -> * */ + hr = IDirectPlayX_Send( pDP[1], idPlayer[3], DPID_ALLPLAYERS, 0, + lpData, dwDataSize ); + checkHR( DP_OK, hr ); + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "32,31,30,", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "35,34,", callbackData.szTrace1 ); + /* 3 -> g0 */ + hr = IDirectPlayX_Send( pDP[1], idPlayer[3], idGroup[0], 0, + lpData, dwDataSize ); + checkHR( DP_OK, hr ); + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "32,31,30,", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + /* 3 -> g1 */ + hr = IDirectPlayX_Send( pDP[1], idPlayer[3], idGroup[1], 0, + lpData, dwDataSize ); + checkHR( DP_OK, hr ); + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "34,", callbackData.szTrace1 ); + /* 3 -> g2 */ + hr = IDirectPlayX_Send( pDP[1], idPlayer[3], idGroup[2], 0, + lpData, dwDataSize ); + checkHR( DP_OK, hr ); + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "35,34,", callbackData.szTrace1 ); + + /* 5 -> * */ + hr = IDirectPlayX_Send( pDP[1], idPlayer[5], DPID_ALLPLAYERS, 0, + lpData, dwDataSize ); + checkHR( DP_OK, hr ); + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "52,51,50,", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "54,53,", callbackData.szTrace1 ); + /* 5 -> g0 */ + hr = IDirectPlayX_Send( pDP[1], idPlayer[5], idGroup[0], 0, + lpData, dwDataSize ); + checkHR( DP_OK, hr ); + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "52,51,50,", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + /* 5 -> g1 */ + hr = IDirectPlayX_Send( pDP[1], idPlayer[5], idGroup[1], 0, + lpData, dwDataSize ); + checkHR( DP_OK, hr ); + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "54,53,", callbackData.szTrace1 ); + /* 5 -> g2 */ + hr = IDirectPlayX_Send( pDP[1], idPlayer[5], idGroup[2], 0, + lpData, dwDataSize ); + checkHR( DP_OK, hr ); + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "54,", callbackData.szTrace1 ); + + + HeapFree( GetProcessHeap(), 0, lpData ); + IDirectPlayX_Release( pDP[0] ); + IDirectPlayX_Release( pDP[1] ); + +} + +static void test_groups_cs(void) +{ + + LPDIRECTPLAY4 pDP[2]; + DPSESSIONDESC2 dpsd; + DPID idPlayer[6], idGroup[3]; + CallbackData callbackData; + HRESULT hr; + UINT i; + + DWORD dwDataSize = 1024; + LPVOID lpData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 1024 ); + + + for (i=0; i<2; i++) + { + CoCreateInstance( &CLSID_DirectPlay, NULL, CLSCTX_ALL, + &IID_IDirectPlay4A, (LPVOID*) &pDP[i] ); + } + ZeroMemory( &dpsd, sizeof(DPSESSIONDESC2) ); + dpsd.dwSize = sizeof(DPSESSIONDESC2); + dpsd.guidApplication = appGuid; + dpsd.dwMaxPlayers = 10; + + + init_TCPIP_provider( pDP[0], "127.0.0.1", 0 ); + init_TCPIP_provider( pDP[1], "127.0.0.1", 0 ); + + dpsd.dwFlags = DPSESSION_CLIENTSERVER; + hr = IDirectPlayX_Open( pDP[0], &dpsd, DPOPEN_CREATE ); + todo_wine checkHR( DP_OK, hr ); + dpsd.dwFlags = 0; + hr = IDirectPlayX_EnumSessions( pDP[1], &dpsd, 0, EnumSessions_cb_join, + (LPVOID) pDP[1], 0 ); + todo_wine checkHR( DP_OK, hr ); + + if ( hr == DPERR_UNINITIALIZED ) + { + skip( "dplay not implemented enough for this test yet\n" ); + return; + } + + + /* Create players */ + hr = IDirectPlayX_CreatePlayer( pDP[0], &idPlayer[0], + NULL, NULL, NULL, 0, 0 ); + checkHR( DPERR_ACCESSDENIED, hr ); + hr = IDirectPlayX_CreatePlayer( pDP[0], &idPlayer[0], + NULL, NULL, NULL, 0, + DPPLAYER_SERVERPLAYER ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreatePlayer( pDP[0], &idPlayer[1], + NULL, NULL, NULL, 0, 0 ); + checkHR( DPERR_ACCESSDENIED, hr ); + hr = IDirectPlayX_CreatePlayer( pDP[1], &idPlayer[1], + NULL, NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreatePlayer( pDP[1], &idPlayer[2], + NULL, NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreatePlayer( pDP[1], &idPlayer[3], + NULL, NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreatePlayer( pDP[1], &idPlayer[4], + NULL, NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreatePlayer( pDP[1], &idPlayer[5], + NULL, NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_CreateGroup( pDP[0], &idGroup[0], + NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreateGroup( pDP[1], &idGroup[2], + NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_CreateGroupInGroup( pDP[1], idGroup[2], &idGroup[1], + NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + + + /* Purge queues */ + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "S0,S0,S0,S0,S0,S0,", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "S1," "S2,S1," "S3,S2,S1," "S4,S3,S2,S1," + "S5,S4,S3,S2,S1," "S5,S4,S3,S2,S1,", callbackData.szTrace1 ); + + /* + * Player 0 | | pDP 0 + * Player 1 | Group 0 | + * Player 2 | | + * Player 3 | Group 1 ) | + * Player 4 | | Group 2 | pDP 1 + * Player 5 | | + */ + + /* Build groups */ + hr = IDirectPlayX_AddPlayerToGroup( pDP[0], idGroup[0], idPlayer[0] ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_AddPlayerToGroup( pDP[0], idGroup[0], idPlayer[1] ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_AddPlayerToGroup( pDP[0], idGroup[0], idPlayer[2] ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_AddPlayerToGroup( pDP[1], idGroup[1], idPlayer[3] ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_AddPlayerToGroup( pDP[1], idGroup[1], idPlayer[4] ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_AddPlayerToGroup( pDP[1], idGroup[2], idPlayer[4] ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_AddPlayerToGroup( pDP[1], idGroup[2], idPlayer[5] ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_AddGroupToGroup( pDP[1], idGroup[2], idGroup[1] ); + checkHR( DP_OK, hr ); + + /* Purge queues */ + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "S0,S0,S0,S0,", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "S5," "S4,S3,S2,S1," "S5,S4,S3,S2,S1," + "S5,S4,S3,S2,S1," "S5,S4,S3,S2,S1,", callbackData.szTrace1 ); + + + /* Sending broadcast messages, and checking who receives them */ + dwDataSize = 4; + /* 0 -> * */ + hr = IDirectPlayX_Send( pDP[0], idPlayer[0], DPID_ALLPLAYERS, 0, + lpData, dwDataSize ); + checkHR( DP_OK, hr ); + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "05,04,03,02,01,", callbackData.szTrace1 ); + + /* 0 -> g0 */ + hr = IDirectPlayX_Send( pDP[0], idPlayer[0], idGroup[0], 0, + lpData, dwDataSize ); + checkHR( DP_OK, hr ); + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "02,01,", callbackData.szTrace1 ); + /* 0 -> g1 */ + hr = IDirectPlayX_Send( pDP[0], idPlayer[0], idGroup[1], 0, + lpData, dwDataSize ); + checkHR( DPERR_INVALIDPARAMS, hr ); + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + /* 0 -> g2 */ + hr = IDirectPlayX_Send( pDP[0], idPlayer[0], idGroup[2], 0, + lpData, dwDataSize ); + checkHR( DPERR_INVALIDPARAMS, hr ); + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + + /* 3 -> * */ + hr = IDirectPlayX_Send( pDP[1], idPlayer[3], DPID_ALLPLAYERS, 0, + lpData, dwDataSize ); + checkHR( DP_OK, hr ); + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "30,", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "35,34,32,31,", callbackData.szTrace1 ); + /* 3 -> g0 */ + hr = IDirectPlayX_Send( pDP[1], idPlayer[3], idGroup[0], 0, + lpData, dwDataSize ); + checkHR( DPERR_INVALIDPARAMS, hr ); + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + /* 3 -> g1 */ + hr = IDirectPlayX_Send( pDP[1], idPlayer[3], idGroup[1], 0, + lpData, dwDataSize ); + checkHR( DP_OK, hr ); + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "34,", callbackData.szTrace1 ); + /* 3 -> g2 */ + hr = IDirectPlayX_Send( pDP[1], idPlayer[3], idGroup[2], 0, + lpData, dwDataSize ); + checkHR( DP_OK, hr ); + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "35,34,", callbackData.szTrace1 ); + + /* 5 -> * */ + hr = IDirectPlayX_Send( pDP[1], idPlayer[5], DPID_ALLPLAYERS, 0, + lpData, dwDataSize ); + checkHR( DP_OK, hr ); + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "50,", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "54,53,52,51,", callbackData.szTrace1 ); + /* 5 -> g0 */ + hr = IDirectPlayX_Send( pDP[1], idPlayer[5], idGroup[0], 0, + lpData, dwDataSize ); + checkHR( DPERR_INVALIDPARAMS, hr ); + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + /* 5 -> g1 */ + hr = IDirectPlayX_Send( pDP[1], idPlayer[5], idGroup[1], 0, + lpData, dwDataSize ); + checkHR( DP_OK, hr ); + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "54,53,", callbackData.szTrace1 ); + /* 5 -> g2 */ + hr = IDirectPlayX_Send( pDP[1], idPlayer[5], idGroup[2], 0, + lpData, dwDataSize ); + checkHR( DP_OK, hr ); + check_messages( pDP[0], idPlayer, 6, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + check_messages( pDP[1], idPlayer, 6, &callbackData ); + checkStr( "54,", callbackData.szTrace1 ); + + + HeapFree( GetProcessHeap(), 0, lpData ); + IDirectPlayX_Release( pDP[0] ); + IDirectPlayX_Release( pDP[1] ); + +} + +/* Send */ + +static void test_Send(void) +{ + + LPDIRECTPLAY4 pDP[2]; + DPSESSIONDESC2 dpsd; + DPID dpid[4], idFrom, idTo; + CallbackData callbackData; + HRESULT hr; + LPCSTR message = "message"; + DWORD messageSize = strlen(message) + 1; + DWORD dwDataSize = 1024; + LPDPMSG_GENERIC lpData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize ); + LPDPMSG_SECUREMESSAGE lpDataSecure; + UINT i; + + + for (i=0; i<2; i++) + { + CoCreateInstance( &CLSID_DirectPlay, NULL, CLSCTX_ALL, + &IID_IDirectPlay4A, (LPVOID*) &pDP[i] ); + } + ZeroMemory( &dpsd, sizeof(DPSESSIONDESC2) ); + + + /* Uninitialized service provider */ + hr = IDirectPlayX_Send( pDP[0], 0, 0, 0, + (LPVOID) message, messageSize ); + checkHR( DPERR_UNINITIALIZED, hr ); + + + init_TCPIP_provider( pDP[0], "127.0.0.1", 0 ); + init_TCPIP_provider( pDP[1], "127.0.0.1", 0 ); + + dpsd.dwSize = sizeof(DPSESSIONDESC2); + dpsd.guidApplication = appGuid; + dpsd.dwMaxPlayers = 10; + IDirectPlayX_Open( pDP[0], &dpsd, DPOPEN_CREATE ); + IDirectPlayX_EnumSessions( pDP[1], &dpsd, 0, EnumSessions_cb_join, + (LPVOID) pDP[1], 0 ); + IDirectPlayX_Open( pDP[0], &dpsd, DPOPEN_CREATE ); + + + /* Incorrect players */ + hr = IDirectPlayX_Send( pDP[0], 0, 1, 2, + (LPVOID) message, messageSize ); + todo_wine checkHR( DPERR_INVALIDPLAYER, hr ); + + if ( hr == DPERR_UNINITIALIZED ) + { + skip( "Send not implemented\n" ); + return; + } + + + IDirectPlayX_CreatePlayer( pDP[0], &dpid[0], NULL, NULL, NULL, 0, 0 ); + IDirectPlayX_CreatePlayer( pDP[0], &dpid[1], NULL, NULL, NULL, 0, 0 ); + IDirectPlayX_CreatePlayer( pDP[0], &dpid[2], NULL, NULL, NULL, 0, 0 ); + IDirectPlayX_CreatePlayer( pDP[1], &dpid[3], NULL, NULL, NULL, 0, 0 ); + + /* Purge player creation messages */ + check_messages( pDP[0], dpid, 4, &callbackData ); + checkStr( "S0," "S1,S0," "S2,S1,S0,", callbackData.szTrace1 ); + check_messages( pDP[1], dpid, 4, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + + + /* Message to self: no error, but no message is sent */ + hr = IDirectPlayX_Send( pDP[0], dpid[0], dpid[0], 0, + (LPVOID) message, messageSize ); + checkHR( DP_OK, hr ); + + /* Send a message from a remote player */ + hr = IDirectPlayX_Send( pDP[1], dpid[0], dpid[1], 0, + (LPVOID) message, messageSize ); + checkHR( DPERR_ACCESSDENIED, hr ); + hr = IDirectPlayX_Send( pDP[1], dpid[0], dpid[3], 0, + (LPVOID) message, messageSize ); + checkHR( DPERR_ACCESSDENIED, hr ); + + /* Null message */ + hr = IDirectPlayX_Send( pDP[0], dpid[0], dpid[1], 0, + NULL, messageSize ); + checkHR( DPERR_INVALIDPARAMS, hr ); + hr = IDirectPlayX_Send( pDP[0], dpid[0], dpid[1], 0, + (LPVOID) message, 0 ); + checkHR( DPERR_INVALIDPARAMS, hr ); + + + /* Checking no message was sent */ + check_messages( pDP[0], dpid, 4, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + check_messages( pDP[1], dpid, 4, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + + + /* Regular parameters */ + hr = IDirectPlayX_Send( pDP[0], dpid[0], dpid[1], + 0, + (LPVOID) message, messageSize ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_Receive( pDP[0], &dpid[0], &dpid[1], + DPRECEIVE_FROMPLAYER | DPRECEIVE_TOPLAYER, + (LPVOID) lpData, &dwDataSize ); + checkHR( DP_OK, hr ); + checkStr( message, (LPSTR) lpData ); + check( strlen(message)+1, dwDataSize ); + + check_messages( pDP[0], dpid, 4, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + check_messages( pDP[1], dpid, 4, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + + + /* Message to a remote player */ + hr = IDirectPlayX_Send( pDP[0], dpid[0], dpid[3], 0, + (LPVOID) message, messageSize ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_Receive( pDP[0], &dpid[0], &dpid[3], + DPRECEIVE_FROMPLAYER | DPRECEIVE_TOPLAYER, + (LPVOID) lpData, &dwDataSize ); + checkHR( DPERR_NOMESSAGES, hr ); + hr = IDirectPlayX_Receive( pDP[1], &dpid[0], &dpid[3], + DPRECEIVE_FROMPLAYER | DPRECEIVE_TOPLAYER, + (LPVOID) lpData, &dwDataSize ); + checkHR( DP_OK, hr ); + checkStr( message, (LPSTR) lpData ); + check( strlen(message)+1, dwDataSize ); + + check_messages( pDP[0], dpid, 4, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + check_messages( pDP[1], dpid, 4, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + + + /* Broadcast */ + + hr = IDirectPlayX_Send( pDP[0], dpid[0], DPID_ALLPLAYERS, 0, + (LPVOID) message, messageSize ); + checkHR( DP_OK, hr ); + + for (i=1; i<3; i++) + { + hr = IDirectPlayX_Receive( pDP[0], &dpid[0], &dpid[i], + DPRECEIVE_FROMPLAYER | DPRECEIVE_TOPLAYER, + (LPVOID) lpData, &dwDataSize ); + checkHR( DP_OK, hr ); + checkStr( message, (LPSTR) lpData ); + } + hr = IDirectPlayX_Receive( pDP[1], &dpid[0], &dpid[3], + DPRECEIVE_FROMPLAYER | DPRECEIVE_TOPLAYER, + (LPVOID) lpData, &dwDataSize ); + checkHR( DP_OK, hr ); + checkStr( message, (LPSTR) lpData ); + + check_messages( pDP[0], dpid, 4, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + check_messages( pDP[1], dpid, 4, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + + + hr = IDirectPlayX_Send( pDP[0], DPID_ALLPLAYERS, dpid[1], + 0, + (LPVOID) message, messageSize ); + checkHR( DPERR_INVALIDPLAYER, hr ); + hr = IDirectPlayX_Send( pDP[0], DPID_ALLPLAYERS, DPID_ALLPLAYERS, + 0, + (LPVOID) message, messageSize ); + checkHR( DPERR_INVALIDPLAYER, hr ); + + + /* Flags */ + hr = IDirectPlayX_Send( pDP[0], dpid[0], dpid[1], + DPSEND_GUARANTEED, + (LPVOID) message, messageSize ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_Receive( pDP[0], &dpid[0], &dpid[1], + DPRECEIVE_FROMPLAYER | DPRECEIVE_TOPLAYER, + lpData, &dwDataSize ); + checkHR( DP_OK, hr ); + checkStr( message, (LPSTR)lpData ); + + /* - Inorrect flags */ + hr = IDirectPlayX_Send( pDP[0], dpid[0], dpid[1], + DPSEND_ENCRYPTED, + (LPVOID) message, messageSize ); + checkHR( DPERR_INVALIDPARAMS, hr ); + hr = IDirectPlayX_Send( pDP[0], dpid[0], dpid[1], + DPSEND_SIGNED, + (LPVOID) message, messageSize ); + checkHR( DPERR_INVALIDPARAMS, hr ); + hr = IDirectPlayX_Send( pDP[0], dpid[0], dpid[1], + DPSEND_ENCRYPTED | DPSEND_SIGNED, + (LPVOID) message, messageSize ); + checkHR( DPERR_INVALIDPARAMS, hr ); + + /* - Correct flags, but session is not secure */ + hr = IDirectPlayX_Send( pDP[0], dpid[0], dpid[1], + DPSEND_ENCRYPTED | DPSEND_GUARANTEED, + (LPVOID) message, messageSize ); + checkHR( DPERR_INVALIDPARAMS, hr ); + hr = IDirectPlayX_Send( pDP[0], dpid[0], dpid[1], + DPSEND_SIGNED | DPSEND_GUARANTEED, + (LPVOID) message, messageSize ); + checkHR( DPERR_INVALIDPARAMS, hr ); + hr = IDirectPlayX_Send( pDP[0], dpid[0], dpid[1], + ( DPSEND_ENCRYPTED | + DPSEND_SIGNED | + DPSEND_GUARANTEED ), + (LPVOID) message, messageSize ); + checkHR( DPERR_INVALIDPARAMS, hr ); + + /* - Corerct flags, secure session incorrectly opened (without flags) */ + hr = IDirectPlayX_Close( pDP[0] ); + checkHR( DP_OK, hr ); + + dpsd.dwFlags = 0; + hr = IDirectPlayX_SecureOpen( pDP[0], &dpsd, DPOPEN_CREATE, NULL, NULL ); + checkHR( DP_OK, hr ); + for (i=0; i<2; i++) + IDirectPlayX_CreatePlayer( pDP[0], &dpid[i], NULL, NULL, NULL, 0, 0 ); + + hr = IDirectPlayX_Send( pDP[0], dpid[0], dpid[1], + DPSEND_ENCRYPTED | DPSEND_GUARANTEED, + (LPVOID) message, messageSize ); + checkHR( DPERR_INVALIDPARAMS, hr ); + hr = IDirectPlayX_Send( pDP[0], dpid[0], dpid[1], + DPSEND_SIGNED | DPSEND_GUARANTEED, + (LPVOID) message, messageSize ); + checkHR( DPERR_INVALIDPARAMS, hr ); + hr = IDirectPlayX_Send( pDP[0], dpid[0], dpid[1], + ( DPSEND_ENCRYPTED | + DPSEND_SIGNED | + DPSEND_GUARANTEED ), + (LPVOID) message, messageSize ); + checkHR( DPERR_INVALIDPARAMS, hr ); + + /* - Correct flags, secure session */ + hr = IDirectPlayX_Close( pDP[0] ); + checkHR( DP_OK, hr ); + + dpsd.dwFlags = DPSESSION_SECURESERVER; + hr = IDirectPlayX_SecureOpen( pDP[0], &dpsd, DPOPEN_CREATE, NULL, NULL ); + checkHR( DP_OK, hr ); + IDirectPlayX_CreatePlayer( pDP[0], &dpid[0], NULL, NULL, NULL, 0, 0 ); + IDirectPlayX_CreatePlayer( pDP[0], &dpid[1], NULL, NULL, NULL, 0, 0 ); + + /* Purge */ + check_messages( pDP[0], dpid, 6, &callbackData ); + checkStr( "S0,", callbackData.szTrace1 ); + + + hr = IDirectPlayX_Send( pDP[0], dpid[0], dpid[1], + DPSEND_ENCRYPTED | DPSEND_GUARANTEED, + (LPVOID) message, messageSize ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_Send( pDP[0], dpid[0], dpid[1], + DPSEND_SIGNED | DPSEND_GUARANTEED, + (LPVOID) message, messageSize ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_Send( pDP[0], dpid[0], dpid[1], + ( DPSEND_ENCRYPTED | + DPSEND_SIGNED | + DPSEND_GUARANTEED ), + (LPVOID) message, messageSize ); + checkHR( DP_OK, hr ); + + + for (i=0; i<3; i++) + { + dwDataSize = 1024; + hr = IDirectPlayX_Receive( pDP[0], &idFrom, &idTo, 0, + (LPVOID) lpData, &dwDataSize ); + + lpDataSecure = (LPDPMSG_SECUREMESSAGE) lpData; + + checkHR( DP_OK, hr ); + checkConv( DPSYS_SECUREMESSAGE, lpData->dwType, dpMsgType2str ); + check( DPID_SYSMSG, idFrom ); + check( dpid[1], idTo ); + check( dpid[0], lpDataSecure->dpIdFrom ); + checkStr( message, (LPSTR) lpDataSecure->lpData ); + check( strlen(message)+1, lpDataSecure->dwDataSize ); + + switch(i) + { + case 0: + checkFlags( DPSEND_ENCRYPTED, + lpDataSecure->dwFlags, + FLAGS_DPSEND ); + break; + case 1: + checkFlags( DPSEND_SIGNED, + lpDataSecure->dwFlags, + FLAGS_DPSEND ); + break; + case 2: + checkFlags( DPSEND_SIGNED | DPSEND_ENCRYPTED, + lpDataSecure->dwFlags, + FLAGS_DPSEND ); + break; + default: break; + } + } + check_messages( pDP[0], dpid, 4, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + + + /* - Even in a secure session, incorrect flags still not working */ + hr = IDirectPlayX_Send( pDP[0], dpid[0], dpid[1], + DPSEND_ENCRYPTED, + (LPVOID) message, messageSize ); + checkHR( DPERR_INVALIDPARAMS, hr ); + hr = IDirectPlayX_Send( pDP[0], dpid[0], dpid[1], + DPSEND_SIGNED, + (LPVOID) message, messageSize ); + checkHR( DPERR_INVALIDPARAMS, hr ); + hr = IDirectPlayX_Send( pDP[0], dpid[0], dpid[1], + DPSEND_ENCRYPTED | DPSEND_SIGNED, + (LPVOID) message, messageSize ); + checkHR( DPERR_INVALIDPARAMS, hr ); + + + HeapFree( GetProcessHeap(), 0, lpData ); + IDirectPlayX_Release( pDP[0] ); + IDirectPlayX_Release( pDP[1] ); + +} + +/* Receive */ + +static void test_Receive(void) +{ + + LPDIRECTPLAY4 pDP; + DPSESSIONDESC2 dpsd; + DPID dpid[4], idFrom, idTo; + HRESULT hr; + LPCSTR message = "message"; + DWORD messageSize = strlen(message) + 1; + DWORD dwDataSize = 1024; + LPDPMSG_GENERIC lpData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + dwDataSize ); + LPDPMSG_CREATEPLAYERORGROUP lpDataCreate; + LPDPMSG_DESTROYPLAYERORGROUP lpDataDestroy; + + DWORD dwCount; + UINT i; + + + CoCreateInstance( &CLSID_DirectPlay, NULL, CLSCTX_ALL, + &IID_IDirectPlay4A, (LPVOID*) &pDP ); + + ZeroMemory( &dpsd, sizeof(DPSESSIONDESC2) ); + dpsd.dwSize = sizeof(DPSESSIONDESC2); + dpsd.guidApplication = appGuid; + + init_TCPIP_provider( pDP, "127.0.0.1", 0 ); + + IDirectPlayX_Open( pDP, &dpsd, DPOPEN_CREATE ); + + + /* Invalid parameters */ + hr = IDirectPlayX_Receive( pDP, NULL, &idTo, 0, + lpData, &dwDataSize ); + todo_wine checkHR( DPERR_INVALIDPARAMS, hr ); + + if ( hr == DPERR_UNINITIALIZED ) + { + skip( "Receive not implemented\n" ); + return; + } + + hr = IDirectPlayX_Receive( pDP, &idFrom, NULL, 0, + lpData, &dwDataSize ); + checkHR( DPERR_INVALIDPARAMS, hr ); + hr = IDirectPlayX_Receive( pDP, &idFrom, &idTo, 0, + lpData, NULL ); + checkHR( DPERR_INVALIDPARAMS, hr ); + dwDataSize = -1; + hr = IDirectPlayX_Receive( pDP, &idFrom, &idTo, 0, + lpData, &dwDataSize ); + checkHR( DPERR_INVALIDPARAMS, hr ); + + /* No messages yet */ + hr = IDirectPlayX_Receive( pDP, &idFrom, &idTo, 0, + NULL, &dwDataSize ); + checkHR( DPERR_NOMESSAGES, hr ); + dwDataSize = 0; + hr = IDirectPlayX_Receive( pDP, &idFrom, &idTo, 0, + lpData, &dwDataSize ); + checkHR( DPERR_NOMESSAGES, hr ); + + + IDirectPlayX_CreatePlayer( pDP, &dpid[0], NULL, 0, NULL, 0, 0 ); + IDirectPlayX_CreatePlayer( pDP, &dpid[1], NULL, 0, NULL, 0, + DPPLAYER_SPECTATOR ); + IDirectPlayX_CreatePlayer( pDP, &dpid[2], NULL, 0, NULL, 0, 0 ); + IDirectPlayX_CreatePlayer( pDP, &dpid[3], NULL, 0, NULL, 0, 0 ); + + + /* 0, 1, 2, 3 */ + /* 3, 2, 1, 0 */ + for (i=0; i<4; i++) + { + IDirectPlayX_GetMessageCount( pDP, dpid[i], &dwCount ); + check( 3-i, dwCount ); + } + + + IDirectPlayX_DestroyPlayer( pDP, dpid[3] ); + IDirectPlayX_DestroyPlayer( pDP, dpid[1] ); + + + /* 0, 1, 2, 3 */ + /* 5, 5, 3, 3 */ + IDirectPlayX_GetMessageCount( pDP, dpid[0], &dwCount ); + check( 5, dwCount ); + IDirectPlayX_GetMessageCount( pDP, dpid[1], &dwCount ); + check( 5, dwCount ); + IDirectPlayX_GetMessageCount( pDP, dpid[2], &dwCount ); + check( 3, dwCount ); + IDirectPlayX_GetMessageCount( pDP, dpid[3], &dwCount ); + check( 3, dwCount ); + + + /* Buffer too small */ + hr = IDirectPlayX_Receive( pDP, &idFrom, &idFrom, 0, + NULL, &dwDataSize ); + checkHR( DPERR_BUFFERTOOSMALL, hr ); + check( 48, dwDataSize ); + dwDataSize = 0; + hr = IDirectPlayX_Receive( pDP, &idTo, &idFrom, 0, + lpData, &dwDataSize ); + checkHR( DPERR_BUFFERTOOSMALL, hr ); + check( 48, dwDataSize ); + + + /* Checking the order or reception */ + for (i=0; i<11; i++) + { + dwDataSize = 1024; + hr = IDirectPlayX_Receive( pDP, &idFrom, &idTo, 0, + lpData, &dwDataSize ); + + checkHR( DP_OK, hr ); + check( DPID_SYSMSG, idFrom ); + + if (i<6) /* Player creation */ + { + checkConv( DPSYS_CREATEPLAYERORGROUP, lpData->dwType, dpMsgType2str ); + check( 48, dwDataSize ); + lpDataCreate = (LPDPMSG_CREATEPLAYERORGROUP) lpData; + check( DPPLAYERTYPE_PLAYER, lpDataCreate->dwPlayerType ); + checkLP( NULL, lpDataCreate->lpData ); + check( 0, lpDataCreate->dwDataSize ); + checkLP( NULL, lpDataCreate->dpnName.lpszShortNameA ); + check( 0, lpDataCreate->dpIdParent ); + } + else /* Player destruction */ + { + checkConv( DPSYS_DESTROYPLAYERORGROUP, lpData->dwType, + dpMsgType2str ); + check( 52, dwDataSize ); + lpDataDestroy = (LPDPMSG_DESTROYPLAYERORGROUP) lpData; + check( DPPLAYERTYPE_PLAYER, lpDataDestroy->dwPlayerType ); + checkLP( NULL, lpDataDestroy->lpLocalData ); + check( 0, lpDataDestroy->dwLocalDataSize ); + checkLP( NULL, lpDataDestroy->lpRemoteData ); + check( 0, lpDataDestroy->dwRemoteDataSize ); + checkLP( NULL, lpDataDestroy->dpnName.lpszShortNameA ); + check( 0, lpDataDestroy->dpIdParent ); + } + + switch(i) + { + /* 1 -> 0 */ + case 0: + lpDataCreate = (LPDPMSG_CREATEPLAYERORGROUP) lpData; + check( dpid[0], idTo ); + check( dpid[1], lpDataCreate->dpId ); + check( 1, lpDataCreate->dwCurrentPlayers ); + checkFlags( DPPLAYER_LOCAL|DPPLAYER_SPECTATOR, lpDataCreate->dwFlags, + FLAGS_DPPLAYER|FLAGS_DPGROUP ); + break; + + /* 2 -> 1,0 */ + case 1: + check( dpid[1], idTo ); + lpDataCreate = (LPDPMSG_CREATEPLAYERORGROUP) lpData; + check( dpid[2], lpDataCreate->dpId ); + check( 2, lpDataCreate->dwCurrentPlayers ); + checkFlags( DPPLAYER_LOCAL, lpDataCreate->dwFlags, + FLAGS_DPPLAYER | FLAGS_DPGROUP ); + break; + case 2: + check( dpid[0], idTo ); + lpDataCreate = (LPDPMSG_CREATEPLAYERORGROUP) lpData; + check( dpid[2], lpDataCreate->dpId ); + check( 2, lpDataCreate->dwCurrentPlayers ); + checkFlags( DPPLAYER_LOCAL, lpDataCreate->dwFlags, + FLAGS_DPPLAYER | FLAGS_DPGROUP ); + break; + + /* 3 -> 2,1,0 */ + case 3: + check( dpid[2], idTo ); + lpDataCreate = (LPDPMSG_CREATEPLAYERORGROUP) lpData; + check( dpid[3], lpDataCreate->dpId ); + check( 3, lpDataCreate->dwCurrentPlayers ); + checkFlags( DPPLAYER_LOCAL, lpDataCreate->dwFlags, + FLAGS_DPPLAYER | FLAGS_DPGROUP ); + break; + case 4: + check( dpid[1], idTo ); + lpDataCreate = (LPDPMSG_CREATEPLAYERORGROUP) lpData; + check( dpid[3], lpDataCreate->dpId ); + check( 3, lpDataCreate->dwCurrentPlayers ); + checkFlags( DPPLAYER_LOCAL, lpDataCreate->dwFlags, + FLAGS_DPPLAYER | FLAGS_DPGROUP ); + break; + case 5: + check( dpid[0], idTo ); + lpDataCreate = (LPDPMSG_CREATEPLAYERORGROUP) lpData; + check( dpid[3], lpDataCreate->dpId ); + check( 3, lpDataCreate->dwCurrentPlayers ); + checkFlags( DPPLAYER_LOCAL, lpDataCreate->dwFlags, + FLAGS_DPPLAYER | FLAGS_DPGROUP ); + break; + + /* 3 -> 2,1,0 */ + case 6: + check( dpid[2], idTo ); + lpDataDestroy = (LPDPMSG_DESTROYPLAYERORGROUP) lpData; + check( dpid[3], lpDataDestroy->dpId ); + checkFlags( DPPLAYER_LOCAL, lpDataDestroy->dwFlags, + FLAGS_DPPLAYER | FLAGS_DPGROUP ); + break; + case 7: + check( dpid[1], idTo ); + lpDataDestroy = (LPDPMSG_DESTROYPLAYERORGROUP) lpData; + check( dpid[3], lpDataDestroy->dpId ); + checkFlags( DPPLAYER_LOCAL, lpDataDestroy->dwFlags, + FLAGS_DPPLAYER | FLAGS_DPGROUP ); + break; + case 8: + check( dpid[0], idTo ); + lpDataDestroy = (LPDPMSG_DESTROYPLAYERORGROUP) lpData; + check( dpid[3], lpDataDestroy->dpId ); + checkFlags( DPPLAYER_LOCAL, lpDataDestroy->dwFlags, + FLAGS_DPPLAYER | FLAGS_DPGROUP ); + break; + + /* 1 -> 2,0 */ + case 9: + check( dpid[2], idTo ); + lpDataDestroy = (LPDPMSG_DESTROYPLAYERORGROUP) lpData; + check( dpid[1], lpDataDestroy->dpId ); + checkFlags( DPPLAYER_LOCAL | + DPPLAYER_SPECTATOR, lpDataDestroy->dwFlags, + FLAGS_DPPLAYER | FLAGS_DPGROUP ); + break; + case 10: + check( dpid[0], idTo ); + lpDataDestroy = (LPDPMSG_DESTROYPLAYERORGROUP) lpData; + check( dpid[1], lpDataDestroy->dpId ); + checkFlags( DPPLAYER_LOCAL | + DPPLAYER_SPECTATOR, lpDataDestroy->dwFlags, + FLAGS_DPPLAYER | FLAGS_DPGROUP ); + break; + + default: + trace( "%s\n", dpMsgType2str(lpData->dwType) ); + break; + } + } + + hr = IDirectPlayX_Receive( pDP, &idFrom, &idTo, 0, lpData, &dwDataSize ); + checkHR( DPERR_NOMESSAGES, hr ); + + + /* New data message */ + hr = IDirectPlayX_Send( pDP, dpid[0], dpid[2], 0, + (LPVOID) message, messageSize ); + checkHR( DP_OK, hr ); + + + /* Ensuring DPRECEIVE_PEEK doesn't remove the messages from the queue */ + for (i=0; i<10; i++) + { + hr = IDirectPlayX_Receive( pDP, &idFrom, &idTo, DPRECEIVE_PEEK, + lpData, &dwDataSize ); + checkStr( message, (LPSTR) lpData ); + } + + /* Removing the message from the queue */ + hr = IDirectPlayX_Receive( pDP, &idFrom, &idTo, 0, lpData, &dwDataSize ); + checkHR( DP_OK, hr ); + check( idFrom, dpid[0] ); + check( idTo, dpid[2] ); + checkStr( message, (LPSTR) lpData ); + + hr = IDirectPlayX_Receive( pDP, &idFrom, &idTo, 0, lpData, &dwDataSize ); + checkHR( DPERR_NOMESSAGES, hr ); + + + HeapFree( GetProcessHeap(), 0, lpData ); + IDirectPlayX_Release( pDP ); + +} + +/* GetMessageCount */ + +static void test_GetMessageCount(void) +{ + + LPDIRECTPLAY4 pDP[2]; + DPSESSIONDESC2 dpsd; + DPID dpid[4]; + HRESULT hr; + UINT i; + DWORD dwCount; + + DWORD dwDataSize = 1024; + LPVOID lpData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize ); + CallbackData callbackData; + + + for (i=0; i<2; i++) + { + CoCreateInstance( &CLSID_DirectPlay, NULL, CLSCTX_ALL, + &IID_IDirectPlay4A, (LPVOID*) &pDP[i] ); + } + ZeroMemory( &dpsd, sizeof(DPSESSIONDESC2) ); + + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[0], 0, &dwCount ); + todo_wine checkHR( DPERR_UNINITIALIZED, hr ); + check( -1, dwCount ); + + if ( hr == DP_OK ) + { + skip( "GetMessageCount not implemented\n" ); + return; + } + + + init_TCPIP_provider( pDP[0], "127.0.0.1", 0 ); + init_TCPIP_provider( pDP[1], "127.0.0.1", 0 ); + + + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[0], 0, &dwCount ); + checkHR( DP_OK, hr ); + check( 0, dwCount ); + + + dpsd.dwSize = sizeof(DPSESSIONDESC2); + dpsd.guidApplication = appGuid; + dpsd.dwMaxPlayers = 10; + IDirectPlayX_Open( pDP[0], &dpsd, DPOPEN_CREATE ); + IDirectPlayX_EnumSessions( pDP[1], &dpsd, 0, EnumSessions_cb_join, + (LPVOID) pDP[1], 0 ); + + IDirectPlayX_CreatePlayer( pDP[0], &dpid[0], NULL, NULL, NULL, 0, 0 ); + IDirectPlayX_CreatePlayer( pDP[0], &dpid[1], NULL, NULL, NULL, 0, 0 ); + IDirectPlayX_CreatePlayer( pDP[1], &dpid[3], NULL, NULL, NULL, 0, 0 ); + IDirectPlayX_CreatePlayer( pDP[0], &dpid[2], NULL, NULL, NULL, 0, 0 ); + + + /* Incorrect parameters */ + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[0], dpid[0], NULL ); + checkHR( DPERR_INVALIDPARAMS, hr ); + check( -1, dwCount ); + + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[0], 0, NULL ); + checkHR( DPERR_INVALIDPARAMS, hr ); + check( -1, dwCount ); + + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[0], -1, &dwCount ); + checkHR( DPERR_INVALIDPLAYER, hr ); + check( -1, dwCount ); + + + /* Correct parameters */ + /* Player creation messages */ + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[0], 0, &dwCount ); + checkHR( DP_OK, hr ); + check( 5, dwCount ); + + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[1], 0, &dwCount ); + checkHR( DP_OK, hr ); + check( 1, dwCount ); + + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[0], dpid[0], &dwCount ); + checkHR( DP_OK, hr ); + check( 3, dwCount ); + + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[0], dpid[1], &dwCount ); + checkHR( DP_OK, hr ); + check( 2, dwCount ); + + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[0], dpid[3], &dwCount ); + checkHR( DP_OK, hr ); + /* Remote player: doesn't throw error but result is 0 and not 1 */ + check( 0, dwCount ); + + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[1], dpid[3], &dwCount ); + checkHR( DP_OK, hr ); + check( 1, dwCount ); + + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[0], dpid[1], &dwCount ); + checkHR( DP_OK, hr ); + check( 2, dwCount ); + + + /* Purge queues */ + check_messages( pDP[0], dpid, 6, &callbackData ); + checkStr( "S0,S1,S0,S1,S0,", callbackData.szTrace1 ); + check_messages( pDP[1], dpid, 6, &callbackData ); + checkStr( "S3,", callbackData.szTrace1 ); + + + /* Ensure queues is purged */ + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[0], 0, &dwCount ); + checkHR( DP_OK, hr ); + check( 0, dwCount ); + + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[1], 0, &dwCount ); + checkHR( DP_OK, hr ); + check( 0, dwCount ); + + + /* Send data messages */ + for (i=0; i<5; i++) + IDirectPlayX_Send( pDP[0], dpid[0], dpid[1], 0, lpData, dwDataSize ); + for (i=0; i<6; i++) + IDirectPlayX_Send( pDP[0], dpid[1], dpid[2], 0, lpData, dwDataSize ); + for (i=0; i<7; i++) + IDirectPlayX_Send( pDP[0], dpid[2], dpid[3], 0, lpData, dwDataSize ); + + + /* Check all messages are in the queues */ + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[0], 0, &dwCount ); + checkHR( DP_OK, hr ); + check( 11, dwCount ); + + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[1], 0, &dwCount ); + checkHR( DP_OK, hr ); + check( 7, dwCount ); + + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[0], dpid[0], &dwCount ); + checkHR( DP_OK, hr ); + check( 0, dwCount ); + + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[0], dpid[1], &dwCount ); + checkHR( DP_OK, hr ); + check( 5, dwCount ); + + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[0], dpid[2], &dwCount ); + checkHR( DP_OK, hr ); + check( 6, dwCount ); + + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[1], dpid[3], &dwCount ); + checkHR( DP_OK, hr ); + check( 7, dwCount ); + + + /* Purge queues again */ + check_messages( pDP[0], dpid, 6, &callbackData ); + checkStr( "01,01,01,01,01," + "12,12,12,12,12,12,", callbackData.szTrace1 ); + check_messages( pDP[1], dpid, 6, &callbackData ); + checkStr( "23,23,23,23,23,23,23,", callbackData.szTrace1 ); + + + /* Check queues are purged */ + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[0], 0, &dwCount ); + checkHR( DP_OK, hr ); + check( 0, dwCount ); + + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[1], 0, &dwCount ); + checkHR( DP_OK, hr ); + check( 0, dwCount ); + + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[0], dpid[0], &dwCount ); + checkHR( DP_OK, hr ); + check( 0, dwCount ); + + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[0], dpid[1], &dwCount ); + checkHR( DP_OK, hr ); + check( 0, dwCount ); + + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[0], dpid[2], &dwCount ); + checkHR( DP_OK, hr ); + check( 0, dwCount ); + + dwCount = -1; + hr = IDirectPlayX_GetMessageCount( pDP[1], dpid[3], &dwCount ); + checkHR( DP_OK, hr ); + check( 0, dwCount ); + + + HeapFree( GetProcessHeap(), 0, lpData ); + IDirectPlayX_Release( pDP[0] ); + IDirectPlayX_Release( pDP[1] ); + +} + +/* GetMessageQueue */ + +static void test_GetMessageQueue(void) +{ + + LPDIRECTPLAY4 pDP[2]; + DPSESSIONDESC2 dpsd; + DPID dpid[4]; + CallbackData callbackData; + HRESULT hr; + UINT i; + DWORD dwNumMsgs, dwNumBytes; + + DWORD dwDataSize = 1024; + LPVOID lpData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize ); + + + for (i=0; i<2; i++) + { + CoCreateInstance( &CLSID_DirectPlay, NULL, CLSCTX_ALL, + &IID_IDirectPlay4A, (LPVOID*) &pDP[i] ); + } + ZeroMemory( &dpsd, sizeof(DPSESSIONDESC2) ); + + + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[0], 0, 0, 0, + &dwNumMsgs, &dwNumBytes ); + todo_wine checkHR( DPERR_UNINITIALIZED, hr ); + check( -1, dwNumMsgs ); + check( -1, dwNumBytes ); + + if ( hr == DP_OK ) + { + skip( "GetMessageQueue not implemented\n" ); + return; + } + + + init_TCPIP_provider( pDP[0], "127.0.0.1", 0 ); + init_TCPIP_provider( pDP[1], "127.0.0.1", 0 ); + + + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[0], 0, 0, 0, + &dwNumMsgs, &dwNumBytes ); + checkHR( DP_OK, hr ); + check( 0, dwNumMsgs ); + check( 0, dwNumBytes ); + + + dpsd.dwSize = sizeof(DPSESSIONDESC2); + dpsd.guidApplication = appGuid; + dpsd.dwMaxPlayers = 10; + IDirectPlayX_Open( pDP[0], &dpsd, DPOPEN_CREATE ); + IDirectPlayX_EnumSessions( pDP[1], &dpsd, 0, EnumSessions_cb_join, + (LPVOID) pDP[1], 0 ); + + IDirectPlayX_CreatePlayer( pDP[0], &dpid[0], NULL, NULL, NULL, 0, 0 ); + IDirectPlayX_CreatePlayer( pDP[0], &dpid[1], NULL, NULL, NULL, 0, 0 ); + IDirectPlayX_CreatePlayer( pDP[1], &dpid[3], NULL, NULL, NULL, 0, 0 ); + IDirectPlayX_CreatePlayer( pDP[0], &dpid[2], NULL, NULL, NULL, 0, 0 ); + + + + /* Incorrect parameters */ + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[0], -1, dpid[1], + 0, + &dwNumMsgs, &dwNumBytes ); + checkHR( DPERR_INVALIDPLAYER, hr ); + check( -1, dwNumMsgs ); + check( -1, dwNumBytes ); + + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[0], dpid[0], -1, + 0, + &dwNumMsgs, &dwNumBytes ); + checkHR( DPERR_INVALIDPLAYER, hr ); + check( -1, dwNumMsgs ); + check( -1, dwNumBytes ); + + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[0], dpid[0], dpid[0], + -1, + &dwNumMsgs, &dwNumBytes ); + checkHR( DPERR_INVALIDFLAGS, hr ); + check( -1, dwNumMsgs ); + check( -1, dwNumBytes ); + + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[0], dpid[0], dpid[1], + ( DPMESSAGEQUEUE_SEND | + DPMESSAGEQUEUE_RECEIVE ), + &dwNumMsgs, &dwNumBytes ); + checkHR( DPERR_INVALIDFLAGS, hr ); + check( -1, dwNumMsgs ); + check( -1, dwNumBytes ); + + /* - Remote players */ + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[0], 0, dpid[3], + DPMESSAGEQUEUE_RECEIVE, + &dwNumMsgs, &dwNumBytes ); + checkHR( DPERR_INVALIDPLAYER, hr ); /* Player 3 is remote */ + check( -1, dwNumMsgs ); + check( -1, dwNumBytes ); + + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[0], dpid[3], 0, + DPMESSAGEQUEUE_SEND, + &dwNumMsgs, &dwNumBytes ); + checkHR( DPERR_INVALIDPLAYER, hr ); /* Player 3 is remote */ + check( -1, dwNumMsgs ); + check( -1, dwNumBytes ); + + /* - Remote players, this time in the right place */ + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[0], 0, dpid[3], + DPMESSAGEQUEUE_SEND, + &dwNumMsgs, &dwNumBytes ); + checkHR( DP_OK, hr ); + check( 0, dwNumMsgs ); + check( 0, dwNumBytes ); + + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[0], dpid[3], 0, + DPMESSAGEQUEUE_RECEIVE, + &dwNumMsgs, &dwNumBytes ); + checkHR( DP_OK, hr ); + check( 0, dwNumMsgs ); + check( 0, dwNumBytes ); + + + /* Correct parameters */ + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[0], 0, dpid[1], + DPMESSAGEQUEUE_RECEIVE, + &dwNumMsgs, &dwNumBytes ); + checkHR( DP_OK, hr ); + check( 2, dwNumMsgs ); + check( 96, dwNumBytes ); + + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[0], dpid[0], 0, + DPMESSAGEQUEUE_RECEIVE, + &dwNumMsgs, &dwNumBytes ); + checkHR( DP_OK, hr ); + check( 0, dwNumMsgs ); + check( 0, dwNumBytes ); + + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[0], 0, 0, + DPMESSAGEQUEUE_RECEIVE, + &dwNumMsgs, &dwNumBytes ); + checkHR( DP_OK, hr ); + check( 5, dwNumMsgs ); + check( 240, dwNumBytes ); + + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[0], dpid[0], dpid[1], + DPMESSAGEQUEUE_RECEIVE, + NULL, &dwNumBytes ); + checkHR( DP_OK, hr ); + check( -1, dwNumMsgs ); + check( 0, dwNumBytes ); + + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[0], dpid[0], dpid[1], + DPMESSAGEQUEUE_RECEIVE, + &dwNumMsgs, NULL ); + checkHR( DP_OK, hr ); + check( 0, dwNumMsgs ); + check( -1, dwNumBytes ); + + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[0], dpid[0], dpid[1], + DPMESSAGEQUEUE_RECEIVE, + NULL, NULL ); + checkHR( DP_OK, hr ); + check( -1, dwNumMsgs ); + check( -1, dwNumBytes ); + + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[0], dpid[0], dpid[1], + DPMESSAGEQUEUE_RECEIVE, + &dwNumMsgs, &dwNumBytes ); + checkHR( DP_OK, hr ); + check( 0, dwNumMsgs ); + check( 0, dwNumBytes ); + + + /* Purge messages */ + check_messages( pDP[0], dpid, 6, &callbackData ); + checkStr( "S0,S1,S0,S1,S0,", callbackData.szTrace1 ); + check_messages( pDP[1], dpid, 6, &callbackData ); + checkStr( "S3,", callbackData.szTrace1 ); + + /* Check queues are empty */ + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[0], 0, 0, + DPMESSAGEQUEUE_RECEIVE, + &dwNumMsgs, &dwNumBytes ); + checkHR( DP_OK, hr ); + check( 0, dwNumMsgs ); + check( 0, dwNumBytes ); + + + /* Sending 4 data messages from 0 to 1 */ + /* 3 from 0 to 3 */ + /* 2 from 1 to 3 */ + for (i=0; i<4; i++) + IDirectPlayX_Send( pDP[0], dpid[0], dpid[1], 0, lpData, dwDataSize ); + for (i=0; i<3; i++) + IDirectPlayX_Send( pDP[0], dpid[0], dpid[3], 0, lpData, dwDataSize ); + for (i=0; i<2; i++) + IDirectPlayX_Send( pDP[0], dpid[1], dpid[3], 0, lpData, dwDataSize ); + + + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[0], dpid[0], dpid[1], + DPMESSAGEQUEUE_RECEIVE, + &dwNumMsgs, &dwNumBytes ); + checkHR( DP_OK, hr ); + check( 4, dwNumMsgs ); + check( 4*dwDataSize, dwNumBytes ); + + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[1], dpid[0], dpid[3], + DPMESSAGEQUEUE_RECEIVE, + &dwNumMsgs, &dwNumBytes ); + checkHR( DP_OK, hr ); + check( 3, dwNumMsgs ); + check( 3*dwDataSize, dwNumBytes ); + + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[1], dpid[1], dpid[3], + DPMESSAGEQUEUE_RECEIVE, + &dwNumMsgs, &dwNumBytes ); + checkHR( DP_OK, hr ); + check( 2, dwNumMsgs ); + check( 2*dwDataSize, dwNumBytes ); + + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[0], dpid[0], 0, + DPMESSAGEQUEUE_RECEIVE, + &dwNumMsgs, &dwNumBytes ); + checkHR( DP_OK, hr ); + check( 4, dwNumMsgs ); + check( 4*dwDataSize, dwNumBytes ); + + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[1], dpid[0], 0, + DPMESSAGEQUEUE_RECEIVE, + &dwNumMsgs, &dwNumBytes ); + checkHR( DP_OK, hr ); + check( 3, dwNumMsgs ); + check( 3*dwDataSize, dwNumBytes ); + + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[1], 0, dpid[3], + DPMESSAGEQUEUE_RECEIVE, + &dwNumMsgs, &dwNumBytes ); + checkHR( DP_OK, hr ); + check( 5, dwNumMsgs ); + check( 5*dwDataSize, dwNumBytes ); + + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[0], 0, 0, + DPMESSAGEQUEUE_RECEIVE, + &dwNumMsgs, &dwNumBytes ); + checkHR( DP_OK, hr ); + check( 4, dwNumMsgs ); + check( 4*dwDataSize, dwNumBytes ); + + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[1], 0, 0, + DPMESSAGEQUEUE_RECEIVE, + &dwNumMsgs, &dwNumBytes ); + checkHR( DP_OK, hr ); + check( 5, dwNumMsgs ); + check( 5*dwDataSize, dwNumBytes ); + + + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[0], dpid[0], dpid[1], + DPMESSAGEQUEUE_SEND, + &dwNumMsgs, &dwNumBytes ); + checkHR( DP_OK, hr ); + check( 0, dwNumMsgs ); + check( 0, dwNumBytes ); + + dwNumMsgs = dwNumBytes = -1; + hr = IDirectPlayX_GetMessageQueue( pDP[0], dpid[0], dpid[1], + 0, + &dwNumMsgs, &dwNumBytes ); + checkHR( DP_OK, hr ); + check( 0, dwNumMsgs ); + check( 0, dwNumBytes ); + + + HeapFree( GetProcessHeap(), 0, lpData ); + IDirectPlayX_Release( pDP[0] ); + IDirectPlayX_Release( pDP[1] ); + +} + +/* Remote data replication */ + +static void test_remote_data_replication(void) +{ + + LPDIRECTPLAY4 pDP[2]; + DPSESSIONDESC2 dpsd; + DPID dpid[2], idFrom, idTo; + CallbackData callbackData; + HRESULT hr; + UINT i, j; + DWORD dwFlags, dwDataSize = 1024; + DWORD dwCount; + + LPDPMSG_SETPLAYERORGROUPDATA lpData = HeapAlloc( GetProcessHeap(), + HEAP_ZERO_MEMORY, + dwDataSize ); + + LPCSTR lpDataLocal[] = { "local_0", "local_1" }; + LPCSTR lpDataRemote[] = { "remote_0", "remote_1" }; + LPCSTR lpDataFake = "ugly_fake_data"; + LPSTR lpDataGet = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 32 ); + DWORD dwDataSizeLocal = strlen(lpDataLocal[0])+1, + dwDataSizeRemote = strlen(lpDataRemote[0])+1, + dwDataSizeFake = strlen(lpDataFake)+1, + dwDataSizeGet; + + + for (i=0; i<2; i++) + { + CoCreateInstance( &CLSID_DirectPlay, NULL, CLSCTX_ALL, + &IID_IDirectPlay4A, (LPVOID*) &pDP[i] ); + init_TCPIP_provider( pDP[i], "127.0.0.1", 0 ); + } + ZeroMemory( &dpsd, sizeof(DPSESSIONDESC2) ); + dpsd.dwSize = sizeof(DPSESSIONDESC2); + dpsd.guidApplication = appGuid; + + /* Host */ + hr = IDirectPlayX_Open( pDP[0], &dpsd, DPOPEN_CREATE ); + todo_wine checkHR( DP_OK, hr ); + + if ( hr == DPERR_UNINITIALIZED ) + { + skip( "dplay not implemented enough for this test yet\n" ); + return; + } + + hr = IDirectPlayX_CreatePlayer( pDP[0], &dpid[0], + NULL, NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + + /* Peer */ + hr = IDirectPlayX_EnumSessions( pDP[1], &dpsd, 0, EnumSessions_cb_join, + (LPVOID) pDP[1], 0 ); + checkHR( DP_OK, hr ); + + hr = IDirectPlayX_CreatePlayer( pDP[1], &dpid[1], + NULL, NULL, NULL, 0, 0 ); + checkHR( DP_OK, hr ); + + /* Check players */ + for (i=0; i<2; i++) + { + /* Local (0,0) (1,1) */ + IDirectPlayX_GetPlayerFlags( pDP[i], dpid[i], &dwFlags ); + checkFlags( DPPLAYER_LOCAL, dwFlags, FLAGS_DPPLAYER ); + /* Remote (0,1) (1,0) */ + IDirectPlayX_GetPlayerFlags( pDP[i], dpid[!i], &dwFlags ); + checkFlags( 0, dwFlags, FLAGS_DPPLAYER ); + } + + /* Set data for a local player */ + for (i=0; i<2; i++) + { + hr = IDirectPlayX_SetPlayerData( pDP[i], dpid[i], + (LPVOID) lpDataLocal[i], + dwDataSizeLocal, + DPSET_LOCAL ); + checkHR( DP_OK, hr ); + hr = IDirectPlayX_SetPlayerData( pDP[i], dpid[i], + (LPVOID) lpDataRemote[i], + dwDataSizeRemote, + DPSET_REMOTE ); + checkHR( DP_OK, hr ); + } + + /* Retrieve data locally (0->0, 1->1) */ + for (i=0; i<2; i++) + { + dwDataSizeGet = dwDataSizeFake; + strcpy( lpDataGet, lpDataFake ); + hr = IDirectPlayX_GetPlayerData( pDP[i], dpid[i], + lpDataGet, &dwDataSizeGet, + DPGET_LOCAL ); + checkHR( DP_OK, hr ); + check( dwDataSizeLocal, dwDataSizeGet ); + checkStr( lpDataLocal[i], lpDataGet ); + + dwDataSizeGet = dwDataSizeFake; + strcpy( lpDataGet, lpDataFake ); + hr = IDirectPlayX_GetPlayerData( pDP[i], dpid[i], + lpDataGet, &dwDataSizeGet, + DPGET_REMOTE ); + checkHR( DP_OK, hr ); + check( dwDataSizeRemote, dwDataSizeGet ); + checkStr( lpDataRemote[i], lpDataGet ); + } + + + /* Set data for a remote player */ + /* This should fail with DPERR_ACCESSDENIED, + but for some reason it doesn't */ + for (i=0; i<2; i++) + { + IDirectPlayX_SetPlayerData( pDP[i], dpid[!i], + (LPVOID) lpDataLocal[!i], + dwDataSizeLocal, + DPSET_LOCAL ); + checkHR( DP_OK, hr ); + IDirectPlayX_SetPlayerData( pDP[i], dpid[!i], + (LPVOID) lpDataRemote[!i], + dwDataSizeRemote, + DPSET_REMOTE ); + checkHR( DP_OK, hr ); + } + + /* Retrieve crossed data (0->1, 1->0) */ + for (i=0; i<2; i++) + { + dwDataSizeGet = dwDataSizeFake; + strcpy( lpDataGet, lpDataFake ); + hr = IDirectPlayX_GetPlayerData( pDP[i], dpid[!i], + lpDataGet, &dwDataSizeGet, + DPGET_LOCAL ); + checkHR( DP_OK, hr ); + check( dwDataSizeLocal, dwDataSizeGet ); + checkStr( lpDataLocal[!i], lpDataGet ); + + dwDataSizeGet = dwDataSizeFake; + strcpy( lpDataGet, lpDataFake ); + hr = IDirectPlayX_GetPlayerData( pDP[i], dpid[!i], + lpDataGet, &dwDataSizeGet, + DPGET_REMOTE ); + checkHR( DP_OK, hr ); + check( dwDataSizeRemote, dwDataSizeGet ); + checkStr( lpDataRemote[!i], lpDataGet ); + } + + + /* Purge "new player" messages from queue */ + hr = IDirectPlayX_Receive( pDP[0], &idFrom, &idTo, 0, + (LPVOID) lpData, &dwDataSize ); + checkHR( DP_OK, hr ); + checkConv( DPSYS_CREATEPLAYERORGROUP, lpData->dwType, dpMsgType2str ); + + /* Check number of messages in queue */ + for (i=0; i<2; i++) + { + IDirectPlayX_GetMessageCount( pDP[i], dpid[i], &dwCount ); + check( 2, dwCount ); + IDirectPlayX_GetMessageCount( pDP[i], dpid[!i], &dwCount ); + check( 0, dwCount ); + } + + /* Checking system messages */ + for (i=0; i<2; i++) + { + for (j=0; j<2; j++) + { + hr = IDirectPlayX_Receive( pDP[i], &idFrom, &idTo, 0, + (LPVOID) lpData, &dwDataSize ); + checkHR( DP_OK, hr ); + check( 29, dwDataSize ); + check( DPID_SYSMSG, idFrom ); + check( dpid[i], idTo ); + checkConv( DPSYS_SETPLAYERORGROUPDATA, lpData->dwType, + dpMsgType2str ); + check( DPPLAYERTYPE_PLAYER, lpData->dwPlayerType ); + check( dpid[j], lpData->dpId ); + checkStr( lpDataRemote[j], (LPSTR) lpData->lpData ); + check( dwDataSizeRemote, lpData->dwDataSize ); + dwDataSize = 1024; + } + hr = IDirectPlayX_Receive( pDP[i], &idFrom, &idTo, 0, + lpData, &dwDataSize ); + checkHR( DPERR_NOMESSAGES, hr ); + } + + + /* Changing remote data */ + hr = IDirectPlayX_SetPlayerData( pDP[0], dpid[0], + (LPVOID) lpDataRemote[0], dwDataSizeRemote, + DPSET_REMOTE ); + checkHR( DP_OK, hr ); + + /* Checking system messages (j=0) */ + for (i=0; i<2; i++) + { + hr = IDirectPlayX_Receive( pDP[i], &idFrom, &idTo, 0, + lpData, &dwDataSize ); + checkHR( DP_OK, hr ); + check( 29, dwDataSize ); + check( DPID_SYSMSG, idFrom ); + check( dpid[i], idTo ); + checkConv( DPSYS_SETPLAYERORGROUPDATA, lpData->dwType, dpMsgType2str ); + check( DPPLAYERTYPE_PLAYER, lpData->dwPlayerType ); + check( dpid[0], lpData->dpId ); + checkStr( lpDataRemote[0], (LPSTR) lpData->lpData ); + check( dwDataSizeRemote, lpData->dwDataSize ); + dwDataSize = 1024; + } + + /* Queue is empty */ + check_messages( pDP[0], dpid, 2, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + check_messages( pDP[1], dpid, 2, &callbackData ); + checkStr( "", callbackData.szTrace1 ); + + + HeapFree( GetProcessHeap(), 0, lpData ); + IDirectPlayX_Release( pDP[0] ); + IDirectPlayX_Release( pDP[1] ); + +} + + +START_TEST(dplayx) +{ + CoInitialize( NULL ); + + test_DirectPlayCreate(); + test_EnumConnections(); + test_InitializeConnection(); + + test_GetCaps(); + test_Open(); + test_EnumSessions(); + test_SessionDesc(); + + test_CreatePlayer(); + test_GetPlayerCaps(); + test_PlayerData(); + test_PlayerName(); + test_GetPlayerAccount(); + test_GetPlayerAddress(); + test_GetPlayerFlags(); + + test_CreateGroup(); + test_GroupOwner(); + + test_EnumPlayers(); + test_EnumGroups(); + test_EnumGroupsInGroup(); + + test_groups_p2p(); + test_groups_cs(); + + test_Send(); + test_Receive(); + test_GetMessageCount(); + test_GetMessageQueue(); + + test_remote_data_replication(); CoUninitialize(); } diff --git a/dlls/kernel32/comm.c b/dlls/kernel32/comm.c index 9eeed3de2bb..d83eacbaa6c 100644 --- a/dlls/kernel32/comm.c +++ b/dlls/kernel32/comm.c @@ -824,7 +824,7 @@ BOOL WINAPI SetCommState( HANDLE handle, LPDCB lpdcb) SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - switch (lpdcb->fDtrControl) + switch (lpdcb->fRtsControl) { case RTS_CONTROL_DISABLE: break; case RTS_CONTROL_ENABLE: shf.FlowReplace |= SERIAL_RTS_CONTROL; break; diff --git a/dlls/kernel32/profile.c b/dlls/kernel32/profile.c index ac983ffeedd..22d4cb5e284 100644 --- a/dlls/kernel32/profile.c +++ b/dlls/kernel32/profile.c @@ -702,6 +702,25 @@ static void PROFILE_ReleaseFile(void) ZeroMemory(&CurProfile->LastWriteTime, sizeof(CurProfile->LastWriteTime)); } +/*********************************************************************** + * + * Compares a file time with the current time. If the file time is + * at least 2.1 seconds in the past, return true. + * + * Intended as cache safety measure: The time resolution on FAT is + * two seconds, so files that are not at least two seconds old might + * keep their time even on modification, so don't cache them. + */ +static BOOL is_not_current(FILETIME * ft) +{ + FILETIME Now; + LONGLONG ftll, nowll; + GetSystemTimeAsFileTime(&Now); + ftll = ((LONGLONG)ft->dwHighDateTime << 32) + ft->dwLowDateTime; + nowll = ((LONGLONG)Now.dwHighDateTime << 32) + Now.dwLowDateTime; + TRACE("%08x;%08x\n",(unsigned)ftll+21000000,(unsigned)nowll); + return ftll + 21000000 < nowll; +} /*********************************************************************** * PROFILE_Open @@ -780,15 +799,17 @@ static BOOL PROFILE_Open( LPCWSTR filename, BOOL write_access ) if (hFile != INVALID_HANDLE_VALUE) { - if (TRACE_ON(profile)) + GetFileTime(hFile, NULL, NULL, &LastWriteTime); + if (!memcmp( &CurProfile->LastWriteTime, &LastWriteTime, sizeof(FILETIME) ) && + is_not_current(&LastWriteTime)) + TRACE("(%s): already opened (mru=%d)\n", + debugstr_w(buffer), i); + else { - GetFileTime(hFile, NULL, NULL, &LastWriteTime); - if (memcmp(&CurProfile->LastWriteTime, &LastWriteTime, sizeof(FILETIME))) - TRACE("(%s): already opened (mru=%d)\n", - debugstr_w(buffer), i); - else - TRACE("(%s): already opened, needs refreshing (mru=%d)\n", - debugstr_w(buffer), i); + TRACE("(%s): already opened, needs refreshing (mru=%d)\n", + debugstr_w(buffer), i); + CurProfile->section = PROFILE_Load(hFile, &CurProfile->encoding); + CurProfile->LastWriteTime = LastWriteTime; } CloseHandle(hFile); } diff --git a/dlls/kernel32/tests/profile.c b/dlls/kernel32/tests/profile.c index 4463f5043bc..9cccac233e3 100644 --- a/dlls/kernel32/tests/profile.c +++ b/dlls/kernel32/tests/profile.c @@ -362,9 +362,42 @@ static void test_profile_delete_on_close() ok( size == sizeof contents - 1, "Test file: partial write\n"); res = GetPrivateProfileInt(SECTION, KEY, 0, testfile); + ok( res == 123, "Got %d instead of 123\n", res); + + /* This also deletes the file */ + CloseHandle(h); +} + +static void test_profile_refresh(void) +{ + static CHAR testfile[] = ".\\winetest4.ini"; + HANDLE h; + DWORD size, res; + static const char contents1[] = "[" SECTION "]\n" KEY "=123\n"; + static const char contents2[] = "[" SECTION "]\n" KEY "=124\n"; + + h = CreateFile(testfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, + CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL); + ok( WriteFile( h, contents1, sizeof contents1 - 1, &size, NULL ), + "Cannot write test file: %x\n", GetLastError() ); + ok( size == sizeof contents1 - 1, "Test file: partial write\n"); + res = GetPrivateProfileInt(SECTION, KEY, 0, testfile); ok( res == 123, "Got %d instead of 123\n", res); + CloseHandle(h); + + /* Test proper invalidation of wine's profile file cache */ + + h = CreateFile(testfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, + CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL); + ok( WriteFile( h, contents2, sizeof contents2 - 1, &size, NULL ), + "Cannot write test file: %x\n", GetLastError() ); + ok( size == sizeof contents2 - 1, "Test file: partial write\n"); + + res = GetPrivateProfileInt(SECTION, KEY, 0, testfile); + ok( res == 124, "Got %d instead of 124\n", res); + /* This also deletes the file */ CloseHandle(h); } @@ -417,6 +450,10 @@ static void test_GetPrivateProfileString(void) create_test_file(filename, content, sizeof(content)); + /* Run this test series with caching. Wine won't cache profile + files younger than 2.1 seconds. */ + Sleep(2500); + /* lpAppName is NULL */ lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA(NULL, "name1", "default", @@ -664,5 +701,6 @@ START_TEST(profile) test_profile_sections_names(); test_profile_existing(); test_profile_delete_on_close(); + test_profile_refresh(); test_GetPrivateProfileString(); } diff --git a/dlls/mstask/tests/Makefile.in b/dlls/mstask/tests/Makefile.in index 9a261e75205..c1206d9a33d 100644 --- a/dlls/mstask/tests/Makefile.in +++ b/dlls/mstask/tests/Makefile.in @@ -6,6 +6,7 @@ TESTDLL = mstask.dll IMPORTS = ole32 kernel32 CTESTS = \ + task.c \ task_scheduler.c @MAKE_TEST_RULES@ diff --git a/dlls/mstask/tests/task.c b/dlls/mstask/tests/task.c new file mode 100644 index 00000000000..48f87f20fec --- /dev/null +++ b/dlls/mstask/tests/task.c @@ -0,0 +1,239 @@ +/* + * Test suite for Task interface + * + * Copyright (C) 2008 Google (Roy Shea) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS + +#include "corerror.h" +#include "mstask.h" +#include "wine/test.h" + +static ITaskScheduler *test_task_scheduler; +static ITask *test_task; +static const WCHAR empty[] = {0}; + +/* allocate some tmp string space */ +/* FIXME: this is not 100% thread-safe */ +static char *get_tmp_space(int size) +{ + static char *list[16]; + static long pos; + char *ret; + int idx; + + idx = ++pos % (sizeof(list)/sizeof(list[0])); + if ((ret = realloc(list[idx], size))) + list[idx] = ret; + return ret; +} + +static const char *dbgstr_w(LPCWSTR str) +{ + char *buf; + int len; + if(!str) + return "(null)"; + len = lstrlenW(str) + 1; + buf = get_tmp_space(len); + WideCharToMultiByte(CP_ACP, 0, str, -1, buf, len, NULL, NULL); + return buf; +} + +static BOOL setup_task(void) +{ + HRESULT hres; + const WCHAR task_name[] = {'T','e','s','t','i','n','g', 0}; + + hres = CoCreateInstance(&CLSID_CTaskScheduler, NULL, CLSCTX_INPROC_SERVER, + &IID_ITaskScheduler, (void **) &test_task_scheduler); + if(hres != S_OK) + return FALSE; + hres = ITaskScheduler_NewWorkItem(test_task_scheduler, task_name, &CLSID_CTask, + &IID_ITask, (IUnknown**)&test_task); + if(hres != S_OK) + { + ITaskScheduler_Release(test_task_scheduler); + return FALSE; + } + return TRUE; +} + +static void cleanup_task(void) +{ + ITask_Release(test_task); + ITaskScheduler_Release(test_task_scheduler); +} + +static LPCWSTR path_resolve_name(LPCWSTR base_name) +{ + static WCHAR buffer[MAX_PATH]; + int len; + + len = SearchPathW(NULL, base_name, NULL, 0, NULL, NULL); + if (len == 0) + return base_name; + else if (len < MAX_PATH) + { + SearchPathW(NULL, base_name, NULL, MAX_PATH, buffer, NULL); + return buffer; + } + return NULL; +} + +static void test_SetApplicationName_GetApplicationName(void) +{ + BOOL setup; + HRESULT hres; + LPWSTR stored_name; + LPCWSTR full_name; + const WCHAR non_application_name[] = {'N','o','S','u','c','h', + 'A','p','p','l','i','c','a','t','i','o','n', 0}; + const WCHAR notepad_exe[] = { + 'n','o','t','e','p','a','d','.','e','x','e', 0}; + const WCHAR notepad[] = {'n','o','t','e','p','a','d', 0}; + + setup = setup_task(); + ok(setup, "Failed to setup test_task\n"); + if (!setup) + { + skip("Failed to create task. Skipping tests.\n"); + return; + } + + /* Attempt getting before setting application name */ + hres = ITask_GetApplicationName(test_task, &stored_name); + todo_wine ok(hres == S_OK, "GetApplicationName failed: %08x\n", hres); + if (hres == S_OK) + { + todo_wine ok(!lstrcmpW(stored_name, empty), + "Got %s, expected empty string\n", dbgstr_w(stored_name)); + CoTaskMemFree(stored_name); + } + + /* Set application name to a non-existent application and then get + * the application name that is actually stored */ + hres = ITask_SetApplicationName(test_task, non_application_name); + todo_wine ok(hres == S_OK, "Failed setting name %s: %08x\n", + dbgstr_w(non_application_name), hres); + hres = ITask_GetApplicationName(test_task, &stored_name); + todo_wine ok(hres == S_OK, "GetApplicationName failed: %08x\n", hres); + if (hres == S_OK) + { + full_name = path_resolve_name(non_application_name); + todo_wine ok(!lstrcmpW(stored_name, full_name), "Got %s, expected %s\n", + dbgstr_w(stored_name), dbgstr_w(full_name)); + CoTaskMemFree(stored_name); + } + + /* Set a valid application name with program type extension and then + * get the stored name */ + hres = ITask_SetApplicationName(test_task, notepad_exe); + todo_wine ok(hres == S_OK, "Failed setting name %s: %08x\n", + dbgstr_w(notepad_exe), hres); + hres = ITask_GetApplicationName(test_task, &stored_name); + todo_wine ok(hres == S_OK, "GetApplicationName failed: %08x\n", hres); + if (hres == S_OK) + { + full_name = path_resolve_name(notepad_exe); + todo_wine ok(!lstrcmpW(stored_name, full_name), "Got %s, expected %s\n", + dbgstr_w(stored_name), dbgstr_w(full_name)); + CoTaskMemFree(stored_name); + } + + /* Set a valid application name without program type extension and + * then get the stored name */ + hres = ITask_SetApplicationName(test_task, notepad); + todo_wine ok(hres == S_OK, "Failed setting name %s: %08x\n", dbgstr_w(notepad), hres); + hres = ITask_GetApplicationName(test_task, &stored_name); + todo_wine ok(hres == S_OK, "GetApplicationName failed: %08x\n", hres); + if (hres == S_OK) + { + full_name = path_resolve_name(notepad); + todo_wine ok(!lstrcmpW(stored_name, full_name), "Got %s, expected %s\n", + dbgstr_w(stored_name), dbgstr_w(full_name)); + CoTaskMemFree(stored_name); + } + + /* After having a valid application name set, set application name + * to a non-existant application and then get the name that is + * actually stored */ + hres = ITask_SetApplicationName(test_task, non_application_name); + todo_wine ok(hres == S_OK, "Failed setting name %s: %08x\n", + dbgstr_w(non_application_name), hres); + hres = ITask_GetApplicationName(test_task, &stored_name); + todo_wine ok(hres == S_OK, "GetApplicationName failed: %08x\n", hres); + if (hres == S_OK) + { + full_name = path_resolve_name(non_application_name); + todo_wine ok(!lstrcmpW(stored_name, full_name), "Got %s, expected %s\n", + dbgstr_w(stored_name), dbgstr_w(full_name)); + CoTaskMemFree(stored_name); + } + + /* Clear application name */ + hres = ITask_SetApplicationName(test_task, empty); + todo_wine ok(hres == S_OK, "Failed setting name %s: %08x\n", dbgstr_w(empty), hres); + hres = ITask_GetApplicationName(test_task, &stored_name); + todo_wine ok(hres == S_OK, "GetApplicationName failed: %08x\n", hres); + if (hres == S_OK) + { + todo_wine ok(!lstrcmpW(stored_name, empty), + "Got %s, expected empty string\n", dbgstr_w(stored_name)); + CoTaskMemFree(stored_name); + } + + cleanup_task(); + return; +} + +static void test_CreateTrigger(void) +{ + BOOL setup; + HRESULT hres; + WORD trigger_index; + ITaskTrigger *test_trigger; + + setup = setup_task(); + ok(setup, "Failed to setup test_task\n"); + if (!setup) + { + skip("Failed to create task. Skipping tests.\n"); + return; + } + + hres = ITask_CreateTrigger(test_task, &trigger_index, &test_trigger); + todo_wine ok(hres == S_OK, "Failed to create trigger: 0x%08x\n", hres); + if (hres != S_OK) + { + cleanup_task(); + return; + } + + ITaskTrigger_Release(test_trigger); + cleanup_task(); + return; +} + +START_TEST(task) +{ + CoInitialize(NULL); + test_SetApplicationName_GetApplicationName(); + test_CreateTrigger(); + CoUninitialize(); +} diff --git a/dlls/msvcirt/msvcirt.c b/dlls/msvcirt/msvcirt.c index 686ca7cd9e2..6178aca0508 100644 --- a/dlls/msvcirt/msvcirt.c +++ b/dlls/msvcirt/msvcirt.c @@ -16,6 +16,9 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "config.h" +#include "wine/port.h" + #include #include "windef.h" @@ -24,6 +27,61 @@ WINE_DEFAULT_DEBUG_CHANNEL(msvcirt); +typedef struct { + LPVOID VTable; +} class_ostream; + +#ifdef __i386__ /* thiscall functions are i386-specific */ + +#define THISCALL(func) __thiscall_ ## func +#define THISCALL_NAME(func) __ASM_NAME("__thiscall_" #func) +#define DEFINE_THISCALL_WRAPPER(func) \ + extern void THISCALL(func)(); \ + __ASM_GLOBAL_FUNC(__thiscall_ ## func, \ + "popl %eax\n\t" \ + "pushl %ecx\n\t" \ + "pushl %eax\n\t" \ + "jmp " __ASM_NAME(#func) ) +#else /* __i386__ */ + +#define THISCALL(func) func +#define THISCALL_NAME(func) __ASM_NAME(#func) +#define DEFINE_THISCALL_WRAPPER(func) /* nothing */ + +#endif /* __i386__ */ + +/****************************************************************** + * ??6ostream@@QAEAAV0@H@Z (MSVCRTI.@) + * class ostream & __thiscall ostream::operator<<(int) + */ +DEFINE_THISCALL_WRAPPER(MSVCIRT_operator_sl_int) +void * __stdcall MSVCIRT_operator_sl_int(class_ostream * _this, int integer) +{ + FIXME("(%p)->(%d) stub\n", _this, integer); + return _this; +} + +/****************************************************************** + * ??6ostream@@QAEAAV0@PBD@Z (MSVCRTI.@) + * class ostream & __thiscall ostream::operator<<(char const *) + */ +DEFINE_THISCALL_WRAPPER(MSVCIRT_operator_sl_pchar) +void * __stdcall MSVCIRT_operator_sl_pchar(class_ostream * _this, const char * string) +{ + FIXME("(%p)->(%s) stub\n", _this, string); + return _this; +} + +/****************************************************************** + * ?endl@@YAAAVostream@@AAV1@@Z (MSVCRTI.@) + * class ostream & __cdecl endl(class ostream &) + */ +void * CDECL MSVCIRT_endl(class_ostream * _this) +{ + FIXME("(%p)->() stub\n", _this); + return _this; +} + BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved ) { switch (reason) diff --git a/dlls/msvcirt/msvcirt.spec b/dlls/msvcirt/msvcirt.spec index 0588b558b56..a91cec790d7 100644 --- a/dlls/msvcirt/msvcirt.spec +++ b/dlls/msvcirt/msvcirt.spec @@ -134,7 +134,7 @@ @ stub ??6ostream@@QAEAAV0@E@Z # class ostream & __thiscall ostream::operator<<(unsigned char) @ stub ??6ostream@@QAEAAV0@F@Z # class ostream & __thiscall ostream::operator<<(short) @ stub ??6ostream@@QAEAAV0@G@Z # class ostream & __thiscall ostream::operator<<(unsigned short) -@ stub ??6ostream@@QAEAAV0@H@Z # class ostream & __thiscall ostream::operator<<(int) +@ cdecl -i386 -norelay ??6ostream@@QAEAAV0@H@Z(ptr long) __thiscall_MSVCIRT_operator_sl_int # class ostream & __thiscall ostream::operator<<(int) @ stub ??6ostream@@QAEAAV0@I@Z # class ostream & __thiscall ostream::operator<<(unsigned int) @ stub ??6ostream@@QAEAAV0@J@Z # class ostream & __thiscall ostream::operator<<(long) @ stub ??6ostream@@QAEAAV0@K@Z # class ostream & __thiscall ostream::operator<<(unsigned long) @@ -145,7 +145,7 @@ @ stub ??6ostream@@QAEAAV0@P6AAAVios@@AAV1@@Z@Z # class ostream & __thiscall ostream::operator<<(class ios & (__cdecl*)(class ios &)) @ stub ??6ostream@@QAEAAV0@PAVstreambuf@@@Z # class ostream & __thiscall ostream::operator<<(class streambuf *) @ stub ??6ostream@@QAEAAV0@PBC@Z # class ostream & __thiscall ostream::operator<<(signed char const *) -@ stub ??6ostream@@QAEAAV0@PBD@Z # class ostream & __thiscall ostream::operator<<(char const *) +@ cdecl -i386 -norelay ??6ostream@@QAEAAV0@PBD@Z(ptr ptr) __thiscall_MSVCIRT_operator_sl_pchar # class ostream & __thiscall ostream::operator<<(char const *) @ stub ??6ostream@@QAEAAV0@PBE@Z # class ostream & __thiscall ostream::operator<<(unsigned char const *) @ stub ??6ostream@@QAEAAV0@PBX@Z # class ostream & __thiscall ostream::operator<<(void const *) @ stub ??7ios@@QBEHXZ # int __thiscall ios::operator!(void)const @@ -268,7 +268,7 @@ @ stub ?eback@streambuf@@IBEPADXZ # char * __thiscall streambuf::eback(void)const @ stub ?ebuf@streambuf@@IBEPADXZ # char * __thiscall streambuf::ebuf(void)const @ stub ?egptr@streambuf@@IBEPADXZ # char * __thiscall streambuf::egptr(void)const -@ stub ?endl@@YAAAVostream@@AAV1@@Z # class ostream & __cdecl endl(class ostream &) +@ cdecl ?endl@@YAAAVostream@@AAV1@@Z(ptr) MSVCIRT_endl # class ostream & __cdecl endl(class ostream &) @ stub ?ends@@YAAAVostream@@AAV1@@Z # class ostream & __cdecl ends(class ostream &) @ stub ?eof@ios@@QBEHXZ # int __thiscall ios::eof(void)const @ stub ?epptr@streambuf@@IBEPADXZ # char * __thiscall streambuf::epptr(void)const diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index 972d600d6c5..d7f5b938efd 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -1565,6 +1565,16 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io, RtlSecondsSince1970ToTime( st.st_mtime, &info->LastWriteTime); RtlSecondsSince1970ToTime( st.st_ctime, &info->ChangeTime); RtlSecondsSince1970ToTime( st.st_atime, &info->LastAccessTime); +#ifdef HAVE_STRUCT_STAT_ST_MTIM + info->CreationTime.QuadPart += st.st_mtim.tv_nsec / 100; + info->LastWriteTime.QuadPart += st.st_mtim.tv_nsec / 100; +#endif +#ifdef HAVE_STRUCT_STAT_ST_CTIM + info->ChangeTime.QuadPart += st.st_ctim.tv_nsec / 100; +#endif +#ifdef HAVE_STRUCT_STAT_ST_ATIM + info->LastAccessTime.QuadPart += st.st_atim.tv_nsec / 100; +#endif } } break; @@ -1653,6 +1663,16 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io, RtlSecondsSince1970ToTime( st.st_mtime, &info->BasicInformation.LastWriteTime); RtlSecondsSince1970ToTime( st.st_ctime, &info->BasicInformation.ChangeTime); RtlSecondsSince1970ToTime( st.st_atime, &info->BasicInformation.LastAccessTime); +#ifdef HAVE_STRUCT_STAT_ST_MTIM + info->BasicInformation.CreationTime.QuadPart += st.st_mtim.tv_nsec / 100; + info->BasicInformation.LastWriteTime.QuadPart += st.st_mtim.tv_nsec / 100; +#endif +#ifdef HAVE_STRUCT_STAT_ST_CTIM + info->BasicInformation.ChangeTime.QuadPart += st.st_ctim.tv_nsec / 100; +#endif +#ifdef HAVE_STRUCT_STAT_ST_ATIM + info->BasicInformation.LastAccessTime.QuadPart += st.st_atim.tv_nsec / 100; +#endif info->InternalInformation.IndexNumber.QuadPart = st.st_ino; info->EaInformation.EaSize = 0; info->AccessInformation.AccessFlags = 0; /* FIXME */ diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c index 18baeeee168..9c0dafe3ff4 100644 --- a/dlls/ntdll/threadpool.c +++ b/dlls/ntdll/threadpool.c @@ -258,6 +258,7 @@ static DWORD CALLBACK iocp_poller(LPVOID Arg) callback( err, transferred, overlapped ); } } + return 0; } /*********************************************************************** diff --git a/dlls/ole32/tests/marshal.c b/dlls/ole32/tests/marshal.c index fba8b14dac1..0443b63291a 100644 --- a/dlls/ole32/tests/marshal.c +++ b/dlls/ole32/tests/marshal.c @@ -2337,20 +2337,23 @@ static void test_handler_marshaling(void) ok_ole_success(hr, "CoUnmarshalInterface"); IStream_Release(pStream); - ok_more_than_one_lock(); + if(hr == S_OK) + { + ok_more_than_one_lock(); - hr = IUnknown_QueryInterface(pProxy, &IID_IWineTest, (void **)&pObject); - ok(hr == E_NOINTERFACE, "IUnknown_QueryInterface with unknown IID should have returned E_NOINTERFACE instead of 0x%08x\n", hr); + hr = IUnknown_QueryInterface(pProxy, &IID_IWineTest, (void **)&pObject); + ok(hr == E_NOINTERFACE, "IUnknown_QueryInterface with unknown IID should have returned E_NOINTERFACE instead of 0x%08x\n", hr); - /* it's a handler as it supports IOleObject */ - hr = IUnknown_QueryInterface(pProxy, &IID_IOleObject, (void **)&pObject); - todo_wine - ok_ole_success(hr, "IUnknown_QueryInterface(&IID_IOleObject)"); - if (SUCCEEDED(hr)) IUnknown_Release(pObject); + /* it's a handler as it supports IOleObject */ + hr = IUnknown_QueryInterface(pProxy, &IID_IOleObject, (void **)&pObject); + todo_wine + ok_ole_success(hr, "IUnknown_QueryInterface(&IID_IOleObject)"); + if (SUCCEEDED(hr)) IUnknown_Release(pObject); - IUnknown_Release(pProxy); + IUnknown_Release(pProxy); - ok_no_locks(); + ok_no_locks(); + } end_host_object(tid, thread); diff --git a/dlls/secur32/secur32.c b/dlls/secur32/secur32.c index 8b3c2bbd0cd..d552e13e857 100644 --- a/dlls/secur32/secur32.c +++ b/dlls/secur32/secur32.c @@ -104,8 +104,8 @@ static SecurityFunctionTableA securityFunctionTableA = { VerifySignature, FreeContextBuffer, QuerySecurityPackageInfoA, - NULL, /* Reserved3 */ - NULL, /* Reserved4 */ + EncryptMessage, /* Reserved3 */ + DecryptMessage, /* Reserved4 */ ExportSecurityContext, ImportSecurityContextA, AddCredentialsA, @@ -135,8 +135,8 @@ static SecurityFunctionTableW securityFunctionTableW = { VerifySignature, FreeContextBuffer, QuerySecurityPackageInfoW, - NULL, /* Reserved3 */ - NULL, /* Reserved4 */ + EncryptMessage, /* Reserved3 */ + DecryptMessage, /* Reserved4 */ ExportSecurityContext, ImportSecurityContextW, AddCredentialsW, diff --git a/dlls/secur32/tests/secur32.c b/dlls/secur32/tests/secur32.c index 43704a9952c..955d7bfdf31 100644 --- a/dlls/secur32/tests/secur32.c +++ b/dlls/secur32/tests/secur32.c @@ -99,10 +99,8 @@ static void test_InitSecurityInterface(void) ok(sftA != NULL, "pInitSecurityInterfaceA failed\n"); ok(sftA->dwVersion == SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION, "wrong dwVersion %ld in security function table\n", sftA->dwVersion); ok(!sftA->Reserved2, "Reserved2 should be NULL instead of %p in security function table\n", sftA->Reserved2); - todo_wine - ok(sftA->Reserved3 != NULL, "Reserved3 should not be NULL in security function table\n"); - todo_wine - ok(sftA->Reserved4 != NULL, "Reserved4 should not be NULL in security function table\n"); + ok(sftA->Reserved3 == sftA->EncryptMessage, "Reserved3 should be equal to EncryptMessage in the security function table\n"); + ok(sftA->Reserved4 == sftA->DecryptMessage, "Reserved4 should be equal to DecryptMessage in the security function table\n"); if (!pInitSecurityInterfaceW) { @@ -114,10 +112,8 @@ static void test_InitSecurityInterface(void) ok(sftW != NULL, "pInitSecurityInterfaceW failed\n"); ok(sftW->dwVersion == SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION, "wrong dwVersion %ld in security function table\n", sftW->dwVersion); ok(!sftW->Reserved2, "Reserved2 should be NULL instead of %p in security function table\n", sftW->Reserved2); - todo_wine - ok(sftW->Reserved3 != NULL, "Reserved3 should note be NULL in security function table\n"); - todo_wine - ok(sftW->Reserved4 != NULL, "Reserved4 should not be NULL in security function table\n"); + ok(sftW->Reserved3 == sftW->EncryptMessage, "Reserved3 should be equal to EncryptMessage in the security function table\n"); + ok(sftW->Reserved4 == sftW->DecryptMessage, "Reserved4 should be equal to DecryptMessage in the security function table\n"); } START_TEST(secur32) diff --git a/dlls/user32/menu.c b/dlls/user32/menu.c index b4c19553330..058cf0fee6f 100644 --- a/dlls/user32/menu.c +++ b/dlls/user32/menu.c @@ -1767,7 +1767,7 @@ UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd, * * Display a popup menu. */ -static BOOL MENU_ShowPopup( HWND hwndOwner, HMENU hmenu, UINT id, +static BOOL MENU_ShowPopup( HWND hwndOwner, HMENU hmenu, UINT id, UINT flags, INT x, INT y, INT xanchor, INT yanchor ) { POPUPMENU *menu; @@ -1803,6 +1803,13 @@ static BOOL MENU_ShowPopup( HWND hwndOwner, HMENU hmenu, UINT id, monitor = MonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST ); info.cbSize = sizeof(info); GetMonitorInfoW( monitor, &info ); + + if( flags & TPM_RIGHTALIGN ) x -= width; + if( flags & TPM_CENTERALIGN ) x -= width / 2; + + if( flags & TPM_BOTTOMALIGN ) y -= height; + if( flags & TPM_VCENTERALIGN ) y -= height / 2; + if( x + width > info.rcWork.right) { if( xanchor && x >= width - xanchor ) @@ -2390,7 +2397,7 @@ static HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu, } } - MENU_ShowPopup( hwndOwner, item->hSubMenu, menu->FocusedItem, + MENU_ShowPopup( hwndOwner, item->hSubMenu, menu->FocusedItem, 0, rect.left, rect.top, rect.right, rect.bottom ); if (selectFirst) MENU_MoveSelection( hwndOwner, item->hSubMenu, ITEM_NEXT ); @@ -3410,7 +3417,7 @@ BOOL WINAPI TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y, if (!(wFlags & TPM_NONOTIFY)) SendMessageW( hWnd, WM_INITMENUPOPUP, (WPARAM)hMenu, 0); - if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 )) + if (MENU_ShowPopup( hWnd, hMenu, 0, wFlags, x, y, 0, 0 )) ret = MENU_TrackMenu( hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd, lpRect ); MENU_ExitTracking(hWnd); diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 7227eb7f924..8d60d21255a 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1166,6 +1166,44 @@ static void test_key_map(void) } } +static void test_ToUnicode(void) +{ + WCHAR wStr[2]; + BYTE state[256]; + const BYTE SC_RETURN = 0x1c, SC_TAB = 0x0f; + const BYTE HIGHEST_BIT = 0x80; + int i, ret; + for(i=0; i<256; i++) + state[i]=0; + + SetLastError(0xdeadbeef); + ret = ToUnicode(VK_RETURN, SC_RETURN, state, wStr, 2, 0); + if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + skip("ToUnicode is not implemented\n"); + return; + } + + ok(ret == 1, "ToUnicode for Return key didn't return 1 (was %i)\n", ret); + if(ret == 1) + ok(wStr[0]=='\r', "ToUnicode for CTRL + Return was %i (expected 13)\n", wStr[0]); + state[VK_CONTROL] |= HIGHEST_BIT; + state[VK_LCONTROL] |= HIGHEST_BIT; + + ret = ToUnicode(VK_TAB, SC_TAB, state, wStr, 2, 0); + todo_wine ok(ret == 0, "ToUnicode for CTRL + Tab didn't return 0 (was %i)\n", ret); + + ret = ToUnicode(VK_RETURN, SC_RETURN, state, wStr, 2, 0); + ok(ret == 1, "ToUnicode for CTRL + Return didn't return 1 (was %i)", ret); + if(ret == 1) + ok(wStr[0]=='\n', "ToUnicode for CTRL + Return was %i (expected 10)\n", wStr[0]); + + state[VK_SHIFT] |= HIGHEST_BIT; + state[VK_LSHIFT] |= HIGHEST_BIT; + ret = ToUnicode(VK_RETURN, SC_RETURN, state, wStr, 2, 0); + todo_wine ok(ret == 0, "ToUnicode for CTRL + SHIFT + Return didn't return 0 (was %i)\n", ret); +} + START_TEST(input) { init_function_pointers(); @@ -1179,6 +1217,7 @@ START_TEST(input) test_keynames(); test_mouse_ll_hook(); test_key_map(); + test_ToUnicode(); if(pGetMouseMovePointsEx) test_GetMouseMovePointsEx(); diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 9ac29b86f6d..1964e88ec26 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -4786,8 +4786,11 @@ static void test_hwnd_message(void) found = FindWindowExA( 0, 0, 0, "message window" ); ok( found == hwnd, "didn't find message window %p/%p\n", found, hwnd ); + SetLastError(0xdeadbeef); found = FindWindowExA( GetDesktopWindow(), 0, 0, "message window" ); ok( found == 0, "found message window %p/%p\n", found, hwnd ); + todo_wine + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); if (parent) { found = FindWindowExA( parent, 0, 0, "message window" ); diff --git a/dlls/winealsa.drv/waveout.c b/dlls/winealsa.drv/waveout.c index 62e7f4f9c8c..6dfb0882211 100644 --- a/dlls/winealsa.drv/waveout.c +++ b/dlls/winealsa.drv/waveout.c @@ -764,7 +764,7 @@ static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags) EXIT_ON_ERROR( snd_pcm_sw_params_set_silence_size(pcm, sw_params, 0), MMSYSERR_ERROR, "unable to set silence size"); EXIT_ON_ERROR( snd_pcm_sw_params_set_avail_min(pcm, sw_params, period_size), MMSYSERR_ERROR, "unable to set avail min"); EXIT_ON_ERROR( snd_pcm_sw_params_set_silence_threshold(pcm, sw_params, 0), MMSYSERR_ERROR, "unable to set silence threshold"); - EXIT_ON_ERROR( snd_pcm_sw_params_set_stop_threshold(pcm, sw_params, boundary), MMSYSERR_ERROR, "unable to set xrun mode"); + EXIT_ON_ERROR( snd_pcm_sw_params_set_stop_threshold(pcm, sw_params, boundary), MMSYSERR_ERROR, "unable to set stop threshold"); EXIT_ON_ERROR( snd_pcm_sw_params(pcm, sw_params), MMSYSERR_ERROR, "unable to set sw params for playback"); #undef EXIT_ON_ERROR diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c index dbb7f3fb659..40f33e19faa 100644 --- a/dlls/wined3d/arb_program_shader.c +++ b/dlls/wined3d/arb_program_shader.c @@ -2180,6 +2180,23 @@ static void shader_arb_get_caps(WINED3DDEVTYPE devtype, WineD3D_GL_Info *gl_info } } +static BOOL shader_arb_conv_supported(WINED3DFORMAT fmt) { + TRACE("Checking shader format support for format %s:", debug_d3dformat(fmt)); + switch(fmt) { + case WINED3DFMT_V8U8: + case WINED3DFMT_V16U16: + case WINED3DFMT_X8L8V8U8: + case WINED3DFMT_L6V5U5: + case WINED3DFMT_Q8W8V8U8: + case WINED3DFMT_ATI2N: + TRACE("[OK]\n"); + return TRUE; + default: + TRACE("[FAILED\n"); + return FALSE; + } +} + const shader_backend_t arb_program_shader_backend = { shader_arb_select, shader_arb_select_depth_blt, @@ -2194,6 +2211,7 @@ const shader_backend_t arb_program_shader_backend = { shader_arb_generate_pshader, shader_arb_generate_vshader, shader_arb_get_caps, + shader_arb_conv_supported, }; /* ARB_fragment_program fixed function pipeline replacement definitions */ @@ -2351,7 +2369,7 @@ static void set_bumpmat_arbfp(DWORD state, IWineD3DStateBlockImpl *stateblock, W static const char *get_argreg(SHADER_BUFFER *buffer, DWORD argnum, unsigned int stage, DWORD arg) { const char *ret; - if(arg > WINED3DTOP_LERP) return "unused"; /* This is the marker for unused registers */ + if(arg == ARG_UNUSED) return "unused"; /* This is the marker for unused registers */ switch(arg & WINED3DTA_SELECTMASK) { case WINED3DTA_DIFFUSE: @@ -2961,5 +2979,299 @@ const struct fragment_pipeline arbfp_fragment_pipeline = { arbfp_get_caps, arbfp_alloc, arbfp_free, + shader_arb_conv_supported, arbfp_fragmentstate_template }; + +#define GLINFO_LOCATION device->adapter->gl_info + +struct arbfp_blit_priv { + GLenum yuy2_rect_shader, yuy2_2d_shader; + GLenum uyvy_rect_shader, uyvy_2d_shader; +}; + +static HRESULT arbfp_blit_alloc(IWineD3DDevice *iface) { + IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) iface; + device->blit_priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct arbfp_blit_priv)); + if(!device->blit_priv) { + ERR("Out of memory\n"); + return E_OUTOFMEMORY; + } + return WINED3D_OK; +} +static void arbfp_blit_free(IWineD3DDevice *iface) { + IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) iface; + struct arbfp_blit_priv *priv = (struct arbfp_blit_priv *) device->blit_priv; + + ENTER_GL(); + GL_EXTCALL(glDeleteProgramsARB(1, &priv->yuy2_rect_shader)); + GL_EXTCALL(glDeleteProgramsARB(1, &priv->yuy2_2d_shader)); + GL_EXTCALL(glDeleteProgramsARB(1, &priv->uyvy_rect_shader)); + GL_EXTCALL(glDeleteProgramsARB(1, &priv->uyvy_2d_shader)); + checkGLcall("Delete yuv programs\n"); + LEAVE_GL(); +} + +GLenum gen_yuv_shader(IWineD3DDeviceImpl *device, WINED3DFORMAT fmt, GLenum textype) { + GLenum shader; + SHADER_BUFFER buffer; + const char *tex, *texinstr; + char chroma, luminance; + struct arbfp_blit_priv *priv = (struct arbfp_blit_priv *) device->blit_priv; + + /* Shader header */ + buffer.bsize = 0; + buffer.lineNo = 0; + buffer.newline = TRUE; + buffer.buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, SHADER_PGMSIZE); + + switch(textype) { + case GL_TEXTURE_2D: tex = "2D"; texinstr = "TXP"; break; + case GL_TEXTURE_RECTANGLE_ARB: tex = "RECT"; texinstr = "TEX"; break; + default: + /* This is more tricky than just replacing the texture type - we have to navigate + * properly in the texture to find the correct chroma values + */ + FIXME("Implement yuv correction for non-2d, non-rect textures\n"); + return 0; + } + + if(fmt == WINED3DFMT_UYVY) { + chroma = 'r'; + luminance = 'a'; + } else { + chroma = 'a'; + luminance = 'r'; + } + + GL_EXTCALL(glGenProgramsARB(1, &shader)); + checkGLcall("GL_EXTCALL(glGenProgramsARB(1, &shader))"); + GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader)); + checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader)"); + if(!shader) return 0; + + /* The YUY2 and UYVY formats contain two pixels packed into a 32 bit macropixel, + * giving effectively 16 bit per pixel. The color consists of a luminance(Y) and + * two chroma(U and V) values. Each macropixel has two luminance values, one for + * each single pixel it contains, and one U and one V value shared between both + * pixels. + * + * The data is loaded into an A8L8 texture. With YUY2, the luminance component + * contains the luminance and alpha the chroma. With UYVY it is vice versa. Thus + * take the format into account when generating the read swizzles + * + * Reading the Y value is streightforward - just sample the texture. The hardware + * takes care of filtering in the horizontal and vertical direction. + * + * Reading the U and V values is harder. We have to avoid filtering horizontally, + * because that would mix the U and V values of one pixel or two adjacent pixels. + * Thus floor the texture coordinate and add 0.5 to get an unfiltered read, + * regardless of the filtering setting. Vertical filtering works automatically + * though - the U and V values of two rows are mixed nicely. + * + * Appart of avoiding filtering issues, the code has to know which value it just + * read, and where it can find the other one. To determine this, it checks if + * it sampled an even or odd pixel, and shifts the 2nd read accordingly. + * + * Handling horizontal filtering of U and V values requires reading a 2nd pair + * of pixels, extracting U and V and mixing them. This is not implemented yet. + * + * An alternative implementation idea is to load the texture as A8R8G8B8 texture, + * with width / 2. This way one read gives all 3 values, finding U and V is easy + * in an unfiltered situation. Finding the luminance on the other hand requires + * finding out if it is an odd or even pixel. The real drawback of this approach + * is filtering. This would have to be emulated completely in the shader, reading + * up two 2 packed pixels in up to 2 rows and interpolating both horizontally and + * vertically. Beyond that it would require adjustments to the texture handling + * code to deal with the width scaling + */ + shader_addline(&buffer, "!!ARBfp1.0\n"); + shader_addline(&buffer, "TEMP luminance;\n"); + shader_addline(&buffer, "TEMP temp;\n"); + shader_addline(&buffer, "TEMP chroma;\n"); + shader_addline(&buffer, "TEMP texcrd;\n"); + shader_addline(&buffer, "TEMP texcrd2;\n"); + shader_addline(&buffer, "PARAM coef = {1.0, 0.5, 2.0, 0.0};\n"); + shader_addline(&buffer, "PARAM yuv_coef = {1.403, 0.344, 0.714, 1.770};\n"); + shader_addline(&buffer, "PARAM size = program.local[0];\n"); + + /* First we have to read the chroma values. This means we need at least two pixels(no filtering), + * or 4 pixels(with filtering). To get the unmodified chromas, we have to rid ourselves of the + * filtering when we sample the texture. + * + * These are the rules for reading the chroma: + * + * Even pixel: Cr + * Even pixel: U + * Odd pixel: V + * + * So we have to get the sampling x position in non-normalized coordinates in integers + */ + if(textype != GL_TEXTURE_RECTANGLE_ARB) { + shader_addline(&buffer, "MUL texcrd.rg, fragment.texcoord[0], size.x;\n"); + shader_addline(&buffer, "MOV texcrd.a, size.x;\n"); + } else { + shader_addline(&buffer, "MOV texcrd, fragment.texcoord[0];\n"); + } + /* We must not allow filtering between pixel x and x+1, this would mix U and V + * Vertical filtering is ok. However, bear in mind that the pixel center is at + * 0.5, so add 0.5. + */ + shader_addline(&buffer, "FLR texcrd.x, texcrd.x;\n"); + shader_addline(&buffer, "ADD texcrd.x, texcrd.x, coef.y;\n"); + + /* Divide the x coordinate by 0.5 and get the fraction. This gives 0.25 and 0.75 for the + * even and odd pixels respectively + */ + shader_addline(&buffer, "MUL texcrd2, texcrd, coef.y;\n"); + shader_addline(&buffer, "FRC texcrd2, texcrd2;\n"); + + /* Sample Pixel 1 */ + shader_addline(&buffer, "%s luminance, texcrd, texture[0], %s;\n", texinstr, tex); + + /* Put the value into either of the chroma values */ + shader_addline(&buffer, "SGE temp.x, texcrd2.x, coef.y;\n"); + shader_addline(&buffer, "MUL chroma.r, luminance.%c, temp.x;\n", chroma); + shader_addline(&buffer, "SLT temp.x, texcrd2.x, coef.y;\n"); + shader_addline(&buffer, "MUL chroma.g, luminance.%c, temp.x;\n", chroma); + + /* Sample pixel 2. If we read an even pixel(SLT above returned 1), sample + * the pixel right to the current one. Otherwise, sample the left pixel. + * Bias and scale the SLT result to -1;1 and add it to the texcrd.x. + */ + shader_addline(&buffer, "MAD temp.x, temp.x, coef.z, -coef.x;\n"); + shader_addline(&buffer, "ADD texcrd.x, texcrd, temp.x;\n"); + shader_addline(&buffer, "%s luminance, texcrd, texture[0], %s;\n", texinstr, tex); + + /* Put the value into the other chroma */ + shader_addline(&buffer, "SGE temp.x, texcrd2.x, coef.y;\n"); + shader_addline(&buffer, "MAD chroma.g, luminance.%c, temp.x, chroma.g;\n", chroma); + shader_addline(&buffer, "SLT temp.x, texcrd2.x, coef.y;\n"); + shader_addline(&buffer, "MAD chroma.r, luminance.%c, temp.x, chroma.r;\n", chroma); + + /* TODO: If filtering is enabled, sample a 2nd pair of pixels left or right of + * the current one and lerp the two U and V values + */ + + /* This gives the correctly filtered luminance value */ + shader_addline(&buffer, "TEX luminance, fragment.texcoord[0], texture[0], %s;\n", tex); + + /* Calculate the final result. Formula is taken from + * http://www.fourcc.org/fccyvrgb.php. Note that the chroma + * ranges from -0.5 to 0.5 + */ + shader_addline(&buffer, "SUB chroma.rg, chroma, coef.y;\n"); + + shader_addline(&buffer, "MAD result.color.r, chroma.r, yuv_coef.x, luminance.%c;\n", luminance); + shader_addline(&buffer, "MAD temp.r, -chroma.g, yuv_coef.y, luminance.%c;\n", luminance); + shader_addline(&buffer, "MAD result.color.g, -chroma.r, yuv_coef.z, temp.r;\n"); + shader_addline(&buffer, "MAD result.color.b, chroma.g, yuv_coef.w, luminance.%c;\n", luminance); + shader_addline(&buffer, "END\n"); + + GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(buffer.buffer), buffer.buffer)); + + if (glGetError() == GL_INVALID_OPERATION) { + GLint pos; + glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos); + FIXME("Fragment program error at position %d: %s\n", pos, + debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB))); + } + + if(fmt == WINED3DFMT_YUY2) { + if(textype == GL_TEXTURE_RECTANGLE_ARB) { + priv->yuy2_rect_shader = shader; + } else { + priv->yuy2_2d_shader = shader; + } + } else { + if(textype == GL_TEXTURE_RECTANGLE_ARB) { + priv->uyvy_rect_shader = shader; + } else { + priv->uyvy_2d_shader = shader; + } + } + return shader; +} + +static HRESULT arbfp_blit_set(IWineD3DDevice *iface, WINED3DFORMAT fmt, GLenum textype, UINT width, UINT height) { + GLenum shader; + IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) iface; + float size[4] = {width, height, 1, 1}; + struct arbfp_blit_priv *priv = (struct arbfp_blit_priv *) device->blit_priv; + const GlPixelFormatDesc *glDesc; + + getFormatDescEntry(fmt, &GLINFO_LOCATION, &glDesc); + + if(glDesc->conversion_group != WINED3DFMT_YUY2 && glDesc->conversion_group != WINED3DFMT_UYVY) { + /* Don't bother setting up a shader for unconverted formats */ + glEnable(textype); + checkGLcall("glEnable(textype)"); + return WINED3D_OK; + } + + if(glDesc->conversion_group == WINED3DFMT_YUY2) { + if(textype == GL_TEXTURE_RECTANGLE_ARB) { + shader = priv->yuy2_rect_shader; + } else { + shader = priv->yuy2_2d_shader; + } + } else { + if(textype == GL_TEXTURE_RECTANGLE_ARB) { + shader = priv->uyvy_rect_shader; + } else { + shader = priv->uyvy_2d_shader; + } + } + + if(!shader) { + shader = gen_yuv_shader(device, glDesc->conversion_group, textype); + } + + glEnable(GL_FRAGMENT_PROGRAM_ARB); + checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB)"); + GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader)); + checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader)"); + GL_EXTCALL(glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 0, size)); + checkGLcall("glProgramLocalParameter4fvARB"); + + return WINED3D_OK; +} + +static void arbfp_blit_unset(IWineD3DDevice *iface) { + IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) iface; + glDisable(GL_FRAGMENT_PROGRAM_ARB); + checkGLcall("glDisable(GL_FRAGMENT_PROGRAM_ARB)"); + glDisable(GL_TEXTURE_2D); + checkGLcall("glDisable(GL_TEXTURE_2D)"); + if(GL_SUPPORT(ARB_TEXTURE_CUBE_MAP)) { + glDisable(GL_TEXTURE_CUBE_MAP_ARB); + checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)"); + } + if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE)) { + glDisable(GL_TEXTURE_RECTANGLE_ARB); + checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)"); + } +} + +static BOOL arbfp_blit_conv_supported(WINED3DFORMAT fmt) { + TRACE("Checking blit format support for format %s:", debug_d3dformat(fmt)); + switch(fmt) { + case WINED3DFMT_YUY2: + case WINED3DFMT_UYVY: + TRACE("[OK]\n"); + return TRUE; + default: + TRACE("[FAILED]\n"); + return FALSE; + } +} + +const struct blit_shader arbfp_blit = { + arbfp_blit_alloc, + arbfp_blit_free, + arbfp_blit_set, + arbfp_blit_unset, + arbfp_blit_conv_supported +}; + +#undef GLINFO_LOCATION diff --git a/dlls/wined3d/ati_fragment_shader.c b/dlls/wined3d/ati_fragment_shader.c index 54b05b144c1..8e3ed184d9d 100644 --- a/dlls/wined3d/ati_fragment_shader.c +++ b/dlls/wined3d/ati_fragment_shader.c @@ -153,7 +153,7 @@ static GLuint register_for_arg(DWORD arg, WineD3D_GL_Info *gl_info, unsigned int GLenum ret; if(mod) *mod = GL_NONE; - if(arg == 0xFFFFFFFF) return -1; /* This is the marker for unused registers */ + if(arg == ARG_UNUSED) return -1; /* This is the marker for unused registers */ switch(arg & WINED3DTA_SELECTMASK) { case WINED3DTA_DIFFUSE: @@ -1063,10 +1063,24 @@ static void atifs_free(IWineD3DDevice *iface) { } #undef GLINFO_LOCATION +static BOOL atifs_conv_supported(WINED3DFORMAT fmt) { + TRACE("Checking shader format support for format %s:", debug_d3dformat(fmt)); + switch(fmt) { + case WINED3DFMT_V8U8: + case WINED3DFMT_V16U16: + TRACE("[OK]\n"); + return TRUE; + default: + TRACE("[FAILED\n"); + return FALSE; + } +} + const struct fragment_pipeline atifs_fragment_pipeline = { atifs_enable, atifs_get_caps, atifs_alloc, atifs_free, + atifs_conv_supported, atifs_fragmentstate_template }; diff --git a/dlls/wined3d/baseshader.c b/dlls/wined3d/baseshader.c index 7b52510c587..82187fc1a11 100644 --- a/dlls/wined3d/baseshader.c +++ b/dlls/wined3d/baseshader.c @@ -1113,8 +1113,23 @@ static void shader_none_get_caps(WINED3DDEVTYPE devtype, WineD3D_GL_Info *gl_inf pCaps->PixelShaderVersion = 0; pCaps->PixelShader1xMaxValue = 0.0; } - #undef GLINFO_LOCATION +static BOOL shader_none_conv_supported(WINED3DFORMAT fmt) { + TRACE("Checking shader format support for format %s", debug_d3dformat(fmt)); + switch(fmt) { + /* Faked to make some apps happy. */ + case WINED3DFMT_V8U8: + case WINED3DFMT_V16U16: + case WINED3DFMT_L6V5U5: + case WINED3DFMT_X8L8V8U8: + case WINED3DFMT_Q8W8V8U8: + TRACE("[OK]\n"); + return TRUE; + default: + TRACE("[FAILED]\n"); + return FALSE; + } +} const shader_backend_t none_shader_backend = { shader_none_select, @@ -1130,6 +1145,7 @@ const shader_backend_t none_shader_backend = { shader_none_generate_pshader, shader_none_generate_vshader, shader_none_get_caps, + shader_none_conv_supported }; /* ******************************************* diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c index 4440848fe88..68ec2a79d58 100644 --- a/dlls/wined3d/context.c +++ b/dlls/wined3d/context.c @@ -29,6 +29,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d); #define GLINFO_LOCATION This->adapter->gl_info +/* The last used device. + * + * If the application creates multiple devices and switches between them, ActivateContext has to + * change the opengl context. This flag allows to keep track which device is active + */ +static IWineD3DDeviceImpl *last_device; + /***************************************************************************** * Context_MarkStateDirty * @@ -562,6 +569,8 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar */ if(oldDrawable && oldCtx) { pwglMakeCurrent(oldDrawable, oldCtx); + } else { + last_device = This; } This->frag_pipe->enable_extension((IWineD3DDevice *) This, TRUE); @@ -627,6 +636,8 @@ void DestroyContext(IWineD3DDeviceImpl *This, WineD3DContext *context) { TRACE("Destroying ctx %p\n", context); if(pwglGetCurrentContext() == context->glCtx){ pwglMakeCurrent(NULL, NULL); + } else { + last_device = NULL; } if(context->isPBuffer) { @@ -1125,7 +1136,7 @@ void ActivateContext(IWineD3DDeviceImpl *This, IWineD3DSurface *target, ContextU } /* Activate the opengl context */ - if(context != This->activeContext) { + if(last_device != This || context != This->activeContext) { BOOL ret; /* Prevent an unneeded context switch as those are expensive */ @@ -1152,6 +1163,7 @@ void ActivateContext(IWineD3DDeviceImpl *This, IWineD3DSurface *target, ContextU sizeof(*This->activeContext->pshader_const_dirty) * GL_LIMITS(pshader_constantsF)); } This->activeContext = context; + last_device = This; } /* We only need ENTER_GL for the gl calls made below and for the helper functions which make GL calls */ diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 43837b28d3b..e1e01e2af17 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -2170,6 +2170,11 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPR TRACE("Fragment pipeline private data couldn't be allocated\n"); goto err_out; } + hr = This->blitter->alloc_private(iface); + if(FAILED(hr)) { + TRACE("Blitter private data couldn't be allocated\n"); + goto err_out; + } /* Set up some starting GL setup */ @@ -2254,6 +2259,7 @@ err_out: IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock); This->stateBlock = NULL; } + This->blitter->free_private(iface); This->frag_pipe->free_private(iface); This->shader_backend->shader_free_private(iface); return hr; @@ -2371,6 +2377,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_D } /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */ + This->blitter->free_private(iface); This->frag_pipe->free_private(iface); This->shader_backend->shader_free_private(iface); @@ -7220,6 +7227,7 @@ void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_ This->depth_blt_rb_w = 0; This->depth_blt_rb_h = 0; } + This->blitter->free_private(iface); This->frag_pipe->free_private(iface); This->shader_backend->shader_free_private(iface); @@ -7263,15 +7271,26 @@ HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain * hr = This->shader_backend->shader_alloc_private(iface); if(FAILED(hr)) { ERR("Failed to recreate shader private data\n"); - return hr; + goto err_out; } hr = This->frag_pipe->alloc_private(iface); if(FAILED(hr)) { TRACE("Fragment pipeline private data couldn't be allocated\n"); - return hr; + goto err_out; + } + hr = This->blitter->alloc_private(iface); + if(FAILED(hr)) { + TRACE("Blitter private data couldn't be allocated\n"); + goto err_out; } return WINED3D_OK; + +err_out: + This->blitter->free_private(iface); + This->frag_pipe->free_private(iface); + This->shader_backend->shader_free_private(iface); + return hr; } static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) { diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c index ebf7b408e06..bd7f68bc23b 100644 --- a/dlls/wined3d/directx.c +++ b/dlls/wined3d/directx.c @@ -149,6 +149,9 @@ static int numAdapters = 0; static struct WineD3DAdapter Adapters[1]; static HRESULT WINAPI IWineD3DImpl_CheckDeviceFormat(IWineD3D *iface, UINT Adapter, WINED3DDEVTYPE DeviceType, WINED3DFORMAT AdapterFormat, DWORD Usage, WINED3DRESOURCETYPE RType, WINED3DFORMAT CheckFormat); +static const struct fragment_pipeline *select_fragment_implementation(UINT Adapter, WINED3DDEVTYPE DeviceType); +static const shader_backend_t *select_shader_backend(UINT Adapter, WINED3DDEVTYPE DeviceType); +static const struct blit_shader *select_blit_implementation(UINT Adapter, WINED3DDEVTYPE DeviceType); /* lookup tables */ int minLookup[MAX_LOOKUPS]; @@ -1960,46 +1963,40 @@ static HRESULT WINAPI IWineD3DImpl_CheckDeviceType(IWineD3D *iface, UINT Adapter #define GLINFO_LOCATION Adapters[Adapter].gl_info /* Check if we support bumpmapping for a format */ -static BOOL CheckBumpMapCapability(UINT Adapter, WINED3DFORMAT CheckFormat) +static BOOL CheckBumpMapCapability(UINT Adapter, WINED3DDEVTYPE DeviceType, WINED3DFORMAT CheckFormat) { - /* TODO: Check this in the fixed function pipeline backend */ - if(GL_SUPPORT(NV_REGISTER_COMBINERS) && GL_SUPPORT(NV_TEXTURE_SHADER2)) { - switch (CheckFormat) { - case WINED3DFMT_V8U8: - TRACE_(d3d_caps)("[OK]\n"); - return TRUE; - /* TODO: Other bump map formats */ - default: - TRACE_(d3d_caps)("[FAILED]\n"); - return FALSE; - } - } - if(GL_SUPPORT(ATI_ENVMAP_BUMPMAP) || GL_SUPPORT(ATI_FRAGMENT_SHADER)) { - switch (CheckFormat) { - case WINED3DFMT_V8U8: + const struct fragment_pipeline *fp; + const GlPixelFormatDesc *glDesc; + + switch(CheckFormat) { + case WINED3DFMT_V8U8: + case WINED3DFMT_V16U16: + case WINED3DFMT_L6V5U5: + case WINED3DFMT_X8L8V8U8: + case WINED3DFMT_Q8W8V8U8: + getFormatDescEntry(CheckFormat, &GLINFO_LOCATION, &glDesc); + if(glDesc->conversion_group == WINED3DFMT_UNKNOWN) { + /* We have a GL extension giving native support */ TRACE_(d3d_caps)("[OK]\n"); return TRUE; - default: - TRACE_(d3d_caps)("[FAILED]\n"); - return FALSE; - } - } - if(GL_SUPPORT(ARB_FRAGMENT_PROGRAM)) { - switch (CheckFormat) { - case WINED3DFMT_V8U8: - case WINED3DFMT_V16U16: - case WINED3DFMT_L6V5U5: - case WINED3DFMT_X8L8V8U8: - case WINED3DFMT_Q8W8V8U8: + } + + /* No native support: Ask the fixed function pipeline implementation if it + * can deal with the conversion + */ + fp = select_fragment_implementation(Adapter, DeviceType); + if(fp->conv_supported(CheckFormat)) { TRACE_(d3d_caps)("[OK]\n"); return TRUE; - default: + } else { TRACE_(d3d_caps)("[FAILED]\n"); return FALSE; - } + } + + default: + TRACE_(d3d_caps)("[FAILED]\n"); + return FALSE; } - TRACE_(d3d_caps)("[FAILED]\n"); - return FALSE; } /* Check if the given DisplayFormat + DepthStencilFormat combination is valid for the Adapter */ @@ -2186,8 +2183,12 @@ static BOOL CheckWrapAndMipCapability(UINT Adapter, WINED3DFORMAT CheckFormat) { } /* Check if a texture format is supported on the given adapter */ -static BOOL CheckTextureCapability(UINT Adapter, WINED3DFORMAT CheckFormat) +static BOOL CheckTextureCapability(UINT Adapter, WINED3DDEVTYPE DeviceType, WINED3DFORMAT CheckFormat) { + const shader_backend_t *shader_backend; + const struct fragment_pipeline *fp; + const GlPixelFormatDesc *glDesc; + switch (CheckFormat) { /***** @@ -2247,53 +2248,33 @@ static BOOL CheckTextureCapability(UINT Adapter, WINED3DFORMAT CheckFormat) /***** * Not supported everywhere(depends on GL_ATI_envmap_bumpmap or - * GL_NV_texture_shader), but advertized to make apps happy. - * Enable some because games often fail when they are not available - * and are still playable even without bump mapping + * GL_NV_texture_shader). Emulated by shaders */ case WINED3DFMT_V8U8: - if(GL_SUPPORT(NV_TEXTURE_SHADER) || GL_SUPPORT(ATI_ENVMAP_BUMPMAP) || - GL_SUPPORT(ATI_FRAGMENT_SHADER)) { - return TRUE; - } - if(GL_SUPPORT(ARB_FRAGMENT_SHADER) || GL_SUPPORT(ARB_FRAGMENT_PROGRAM)) { - /* Shader emulated */ - return TRUE; - } - TRACE_(d3d_caps)("[FAILED] - No converted formats on volumes\n"); - return FALSE; - case WINED3DFMT_X8L8V8U8: case WINED3DFMT_L6V5U5: - if(GL_SUPPORT(ARB_FRAGMENT_SHADER) || GL_SUPPORT(ARB_FRAGMENT_PROGRAM)) { - /* Shader emulated */ - return TRUE; - } - WARN_(d3d_caps)("[FAILED]\n"); - return FALSE; - case WINED3DFMT_Q8W8V8U8: case WINED3DFMT_V16U16: - if(GL_SUPPORT(NV_TEXTURE_SHADER)) { - WARN_(d3d_caps)("[Not supported, but pretended to do]\n"); + case WINED3DFMT_W11V11U10: + case WINED3DFMT_A2W10V10U10: + getFormatDescEntry(CheckFormat, &GLINFO_LOCATION, &glDesc); + if(glDesc->conversion_group == WINED3DFMT_UNKNOWN) { + /* We have a GL extension giving native support */ + TRACE_(d3d_caps)("[OK]\n"); return TRUE; } - if(GL_SUPPORT(ARB_FRAGMENT_SHADER) || GL_SUPPORT(ARB_FRAGMENT_PROGRAM)) { - /* Shader emulated */ + + /* No native support: Ask the fixed function pipeline implementation if it + * can deal with the conversion + */ + shader_backend = select_shader_backend(Adapter, DeviceType); + if(shader_backend->shader_conv_supported(CheckFormat)) { + TRACE_(d3d_caps)("[OK]\n"); return TRUE; + } else { + TRACE_(d3d_caps)("[FAILED]\n"); + return FALSE; } - TRACE_(d3d_caps)("[FAILED] - No converted formats on volumes\n"); - return FALSE; - - /* Those are not advertized by the nvidia windows driver, and not - * supported natively by GL_NV_texture_shader or GL_ATI_envmap_bumpmap. - * WINED3DFMT_A2W10V10U10 could be loaded into shaders using the unsigned - * ARGB format if needed - */ - case WINED3DFMT_W11V11U10: - case WINED3DFMT_A2W10V10U10: - WARN_(d3d_caps)("[FAILED]\n"); - return FALSE; case WINED3DFMT_DXT1: case WINED3DFMT_DXT2: @@ -2325,10 +2306,14 @@ static BOOL CheckTextureCapability(UINT Adapter, WINED3DFORMAT CheckFormat) TRACE_(d3d_caps)("[FAILED]\n"); /* Enable when implemented */ return FALSE; - /* YUV formats, not supported for now */ + /* YUV formats */ case WINED3DFMT_UYVY: case WINED3DFMT_YUY2: - TRACE_(d3d_caps)("[FAILED]\n"); /* Enable when implemented */ + if(GL_SUPPORT(APPLE_YCBCR_422)) { + TRACE_(d3d_caps)("[OK]\n"); + return TRUE; + } + TRACE_(d3d_caps)("[FAILED]\n"); return FALSE; /* Not supported */ @@ -2390,6 +2375,14 @@ static BOOL CheckTextureCapability(UINT Adapter, WINED3DFORMAT CheckFormat) /* Vendor specific formats */ case WINED3DFMT_ATI2N: if(GL_SUPPORT(ATI_TEXTURE_COMPRESSION_3DC) || GL_SUPPORT(EXT_TEXTURE_COMPRESSION_RGTC)) { + shader_backend = select_shader_backend(Adapter, DeviceType); + fp = select_fragment_implementation(Adapter, DeviceType); + if(shader_backend->shader_conv_supported(CheckFormat) && + fp->conv_supported(CheckFormat)) { + TRACE_(d3d_caps)("[OK]\n"); + return TRUE; + } + TRACE_(d3d_caps)("[OK]\n"); return TRUE; } @@ -2406,6 +2399,26 @@ static BOOL CheckTextureCapability(UINT Adapter, WINED3DFORMAT CheckFormat) return FALSE; } +static BOOL CheckSurfaceCapability(UINT Adapter, WINED3DFORMAT AdapterFormat, WINED3DDEVTYPE DeviceType, WINED3DFORMAT CheckFormat) { + const struct blit_shader *blitter; + + /* All format that are supported for textures are supported for surfaces as well */ + if(CheckTextureCapability(Adapter, DeviceType, CheckFormat)) return TRUE; + /* All depth stencil formats are supported on surfaces */ + if(CheckDepthStencilCapability(Adapter, AdapterFormat, CheckFormat)) return TRUE; + + /* If opengl can't process the format natively, the blitter may be able to convert it */ + blitter = select_blit_implementation(Adapter, DeviceType); + if(blitter->conv_supported(CheckFormat)) { + TRACE_(d3d_caps)("[OK]\n"); + return TRUE; + } + + /* Reject other formats */ + TRACE_(d3d_caps)("[FAILED]\n"); + return FALSE; +} + static BOOL CheckVertexTextureCapability(UINT Adapter, WINED3DFORMAT CheckFormat) { if (!GL_LIMITS(vertex_samplers)) { @@ -2459,7 +2472,7 @@ static HRESULT WINAPI IWineD3DImpl_CheckDeviceFormat(IWineD3D *iface, UINT Adapt */ if(GL_SUPPORT(ARB_TEXTURE_CUBE_MAP)) { /* Check if the texture format is around */ - if(CheckTextureCapability(Adapter, CheckFormat)) { + if(CheckTextureCapability(Adapter, DeviceType, CheckFormat)) { if(Usage & WINED3DUSAGE_AUTOGENMIPMAP) { /* Check for automatic mipmap generation support */ if(GL_SUPPORT(SGIS_GENERATE_MIPMAP)) { @@ -2561,33 +2574,39 @@ static HRESULT WINAPI IWineD3DImpl_CheckDeviceFormat(IWineD3D *iface, UINT Adapt * - D3DUSAGE_RENDERTARGET */ - if(Usage & WINED3DUSAGE_DEPTHSTENCIL) { - if(CheckDepthStencilCapability(Adapter, AdapterFormat, CheckFormat)) { - UsageCaps |= WINED3DUSAGE_DEPTHSTENCIL; - } else { - TRACE_(d3d_caps)("[FAILED] - No depthstencil support\n"); - return WINED3DERR_NOTAVAILABLE; + if(CheckSurfaceCapability(Adapter, AdapterFormat, DeviceType, CheckFormat)) { + if(Usage & WINED3DUSAGE_DEPTHSTENCIL) { + if(CheckDepthStencilCapability(Adapter, AdapterFormat, CheckFormat)) { + UsageCaps |= WINED3DUSAGE_DEPTHSTENCIL; + } else { + TRACE_(d3d_caps)("[FAILED] - No depthstencil support\n"); + return WINED3DERR_NOTAVAILABLE; + } } - } - if(Usage & WINED3DUSAGE_RENDERTARGET) { - if(CheckRenderTargetCapability(AdapterFormat, CheckFormat)) { - UsageCaps |= WINED3DUSAGE_RENDERTARGET; - } else { - TRACE_(d3d_caps)("[FAILED] - No rendertarget support\n"); - return WINED3DERR_NOTAVAILABLE; + if(Usage & WINED3DUSAGE_RENDERTARGET) { + if(CheckRenderTargetCapability(AdapterFormat, CheckFormat)) { + UsageCaps |= WINED3DUSAGE_RENDERTARGET; + } else { + TRACE_(d3d_caps)("[FAILED] - No rendertarget support\n"); + return WINED3DERR_NOTAVAILABLE; + } } - } - /* Check QUERY_POSTPIXELSHADER_BLENDING support */ - if(Usage & WINED3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING) { - if(CheckPostPixelShaderBlendingCapability(Adapter, CheckFormat)) { - UsageCaps |= WINED3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING; - } else { - TRACE_(d3d_caps)("[FAILED] - No query post pixelshader blending support\n"); - return WINED3DERR_NOTAVAILABLE; + /* Check QUERY_POSTPIXELSHADER_BLENDING support */ + if(Usage & WINED3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING) { + if(CheckPostPixelShaderBlendingCapability(Adapter, CheckFormat)) { + UsageCaps |= WINED3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING; + } else { + TRACE_(d3d_caps)("[FAILED] - No query post pixelshader blending support\n"); + return WINED3DERR_NOTAVAILABLE; + } } + } else { + TRACE_(d3d_caps)("[FAILED] - Not supported for plain surfaces\n"); + return WINED3DERR_NOTAVAILABLE; } + } else if(RType == WINED3DRTYPE_TEXTURE) { /* Texture allows: * - D3DUSAGE_AUTOGENMIPMAP @@ -2602,7 +2621,7 @@ static HRESULT WINAPI IWineD3DImpl_CheckDeviceFormat(IWineD3D *iface, UINT Adapt */ /* Check if the texture format is around */ - if(CheckTextureCapability(Adapter, CheckFormat)) { + if(CheckTextureCapability(Adapter, DeviceType, CheckFormat)) { if(Usage & WINED3DUSAGE_AUTOGENMIPMAP) { /* Check for automatic mipmap generation support */ if(GL_SUPPORT(SGIS_GENERATE_MIPMAP)) { @@ -2642,7 +2661,7 @@ static HRESULT WINAPI IWineD3DImpl_CheckDeviceFormat(IWineD3D *iface, UINT Adapt /* Check QUERY_LEGACYBUMPMAP support */ if(Usage & WINED3DUSAGE_QUERY_LEGACYBUMPMAP) { - if(CheckBumpMapCapability(Adapter, CheckFormat)) { + if(CheckBumpMapCapability(Adapter, DeviceType, CheckFormat)) { UsageCaps |= WINED3DUSAGE_QUERY_LEGACYBUMPMAP; } else { TRACE_(d3d_caps)("[FAILED] - No legacy bumpmap support\n"); @@ -2725,7 +2744,7 @@ static HRESULT WINAPI IWineD3DImpl_CheckDeviceFormat(IWineD3D *iface, UINT Adapt /* Check volume texture and volume usage caps */ if(GL_SUPPORT(EXT_TEXTURE3D)) { - if(CheckTextureCapability(Adapter, CheckFormat) == FALSE) { + if(CheckTextureCapability(Adapter, DeviceType, CheckFormat) == FALSE) { TRACE_(d3d_caps)("[FAILED] - Format not supported\n"); return WINED3DERR_NOTAVAILABLE; } @@ -2929,6 +2948,18 @@ static const struct fragment_pipeline *select_fragment_implementation(UINT Adapt } } +static const struct blit_shader *select_blit_implementation(UINT Adapter, WINED3DDEVTYPE DeviceType) { + int vs_selected_mode; + int ps_selected_mode; + + select_shader_mode(&GLINFO_LOCATION, DeviceType, &ps_selected_mode, &vs_selected_mode); + if((ps_selected_mode == SHADER_ARB || ps_selected_mode == SHADER_GLSL) && GL_SUPPORT(ARB_FRAGMENT_PROGRAM)) { + return &arbfp_blit; + } else { + return &ffp_blit; + } +} + /* Note: d3d8 passes in a pointer to a D3DCAPS8 structure, which is a true subset of a D3DCAPS9 structure. However, it has to come via a void * as the d3d8 interface cannot import the d3d9 header */ @@ -3564,6 +3595,7 @@ static HRESULT WINAPI IWineD3DImpl_CreateDevice(IWineD3D *iface, UINT Adapter, object->frag_pipe = frag_pipeline; compile_state_table(object->StateTable, object->multistate_funcs, &GLINFO_LOCATION, ffp_vertexstate_template, frag_pipeline, misc_state_template); + object->blitter = select_blit_implementation(Adapter, DeviceType); /* Prefer the vtable with functions optimized for single dirtifyable objects if the shader * model can deal with that. It is essentially the same, just with adjusted diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index 925a07ca57f..63d95fd9b30 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -3731,6 +3731,23 @@ static void shader_glsl_get_caps(WINED3DDEVTYPE devtype, WineD3D_GL_Info *gl_inf TRACE_(d3d_caps)("Hardware pixel shader version %d.%d enabled (GLSL)\n", (pCaps->PixelShaderVersion >> 8) & 0xff, pCaps->PixelShaderVersion & 0xff); } +static BOOL shader_glsl_conv_supported(WINED3DFORMAT fmt) { + TRACE("Checking shader format support for format %s:", debug_d3dformat(fmt)); + switch(fmt) { + case WINED3DFMT_V8U8: + case WINED3DFMT_V16U16: + case WINED3DFMT_X8L8V8U8: + case WINED3DFMT_L6V5U5: + case WINED3DFMT_Q8W8V8U8: + case WINED3DFMT_ATI2N: + TRACE("[OK]\n"); + return TRUE; + default: + TRACE("[FAILED\n"); + return FALSE; + } +} + const shader_backend_t glsl_shader_backend = { shader_glsl_select, shader_glsl_select_depth_blt, @@ -3745,4 +3762,5 @@ const shader_backend_t glsl_shader_backend = { shader_glsl_generate_pshader, shader_glsl_generate_vshader, shader_glsl_get_caps, + shader_glsl_conv_supported, }; diff --git a/dlls/wined3d/nvidia_texture_shader.c b/dlls/wined3d/nvidia_texture_shader.c index e2176785553..aea99607454 100644 --- a/dlls/wined3d/nvidia_texture_shader.c +++ b/dlls/wined3d/nvidia_texture_shader.c @@ -673,6 +673,11 @@ static void nvrc_fragment_free(IWineD3DDevice *iface) {} * register combiners extension(Pre-GF3). */ +static BOOL nvts_conv_supported(WINED3DFORMAT fmt) { + TRACE("Checking shader format support for format %s: [FAILED]", debug_d3dformat(fmt)); + return FALSE; +} + const struct StateEntryTemplate nvrc_fragmentstate_template[] = { { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP), { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP), nvrc_colorop }, 0 }, { STATE_TEXTURESTAGE(0, WINED3DTSS_COLORARG1), { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP), nvrc_colorop }, 0 }, @@ -805,6 +810,7 @@ const struct fragment_pipeline nvts_fragment_pipeline = { nvrc_fragment_get_caps, nvrc_fragment_alloc, nvrc_fragment_free, + nvts_conv_supported, nvrc_fragmentstate_template }; @@ -813,5 +819,6 @@ const struct fragment_pipeline nvrc_fragment_pipeline = { nvrc_fragment_get_caps, nvrc_fragment_alloc, nvrc_fragment_free, + nvts_conv_supported, nvrc_fragmentstate_template }; diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c index dd81378ff5f..84be28bedf7 100644 --- a/dlls/wined3d/state.c +++ b/dlls/wined3d/state.c @@ -5620,12 +5620,17 @@ static void ffp_fragment_get_caps(WINED3DDEVTYPE devtype, WineD3D_GL_Info *gl_in static HRESULT ffp_fragment_alloc(IWineD3DDevice *iface) { return WINED3D_OK; } static void ffp_fragment_free(IWineD3DDevice *iface) {} +static BOOL ffp_conv_supported(WINED3DFORMAT fmt) { + TRACE("Checking shader format support for format %s: [FAILED]", debug_d3dformat(fmt)); + return FALSE; +} const struct fragment_pipeline ffp_fragment_pipeline = { ffp_enable, ffp_fragment_get_caps, ffp_fragment_alloc, ffp_fragment_free, + ffp_conv_supported, ffp_fragmentstate_template }; diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index 3c56d4c944f..9a50e84fe46 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -8,7 +8,7 @@ * Copyright 2004 Christian Costa * Copyright 2005 Oliver Stieber * Copyright 2006-2008 Stefan Dösinger for CodeWeavers - * Copyright 2007 Henri Verbeet + * Copyright 2007-2008 Henri Verbeet * Copyright 2006-2008 Roderick Colenbrander * * This library is free software; you can redistribute it and/or @@ -514,24 +514,9 @@ void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) { IWineD3DSurface_ModifyLocation(iface, SFLAG_INTEXTURE, FALSE); } } - ENTER_GL(); - glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */ - if (!This->glDescription.level) { - if (!This->glDescription.textureName) { - glGenTextures(1, &This->glDescription.textureName); - checkGLcall("glGenTextures"); - TRACE("Surface %p given name %d\n", This, This->glDescription.textureName); - } - glBindTexture(This->glDescription.target, This->glDescription.textureName); - checkGLcall("glBindTexture"); - LEAVE_GL(); - IWineD3DSurface_LoadTexture(iface, FALSE); - /* This is where we should be reducing the amount of GLMemoryUsed */ - } else if (This->glDescription.textureName) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */ - /* assume this is a coding error not a real error for now */ - FIXME("Mipmap surface has a glTexture bound to it!\n"); - LEAVE_GL(); - } + + IWineD3DSurface_LoadTexture(iface, FALSE); + if (This->resource.pool == WINED3DPOOL_DEFAULT) { /* Tell opengl to try and keep this texture in video ram (well mostly) */ GLclampf tmp; @@ -2361,8 +2346,26 @@ static void WINAPI IWineD3DSurfaceImpl_BindTexture(IWineD3DSurface *iface) { if(!device->isInDraw) { ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); } + ENTER_GL(); + + glEnable(This->glDescription.target); + + if (!This->glDescription.level) { + if (!This->glDescription.textureName) { + glGenTextures(1, &This->glDescription.textureName); + checkGLcall("glGenTextures"); + TRACE("Surface %p given name %d\n", This, This->glDescription.textureName); + } + /* This is where we should be reducing the amount of GLMemoryUsed */ + } else if (This->glDescription.textureName) { + /* Mipmap surfaces should have a base texture container */ + ERR("Mipmap surface has a glTexture bound to it!\n"); + } + glBindTexture(This->glDescription.target, This->glDescription.textureName); + checkGLcall("glBindTexture"); + LEAVE_GL(); } return; @@ -3433,7 +3436,6 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT * /* Activate the destination context, set it up for blitting */ - myDevice->activeContext->last_was_blit = FALSE; ActivateContext(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT); if(!dstSwapchain) { @@ -3465,8 +3467,8 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT * glDrawBuffer(buffer); checkGLcall("glDrawBuffer"); - glEnable(Src->glDescription.target); - checkGLcall("glEnable(Src->glDescription.target)"); + myDevice->blitter->set_shader((IWineD3DDevice *) myDevice, Src->resource.format, + Src->glDescription.target, Src->pow2Width, Src->pow2Height); /* Bind the texture */ glBindTexture(Src->glDescription.target, Src->glDescription.textureName); @@ -3535,8 +3537,7 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT * glBindTexture(Src->glDescription.target, 0); checkGLcall("glBindTexture(Src->glDescription.target, 0)"); /* Leave the opengl state valid for blitting */ - glDisable(Src->glDescription.target); - checkGLcall("glDisable(Src->glDescription.target)"); + myDevice->blitter->unset_shader((IWineD3DDevice *) myDevice); /* The draw buffer should only need to be restored if we were drawing to the front buffer, and there is a back buffer. * otherwise the context manager should choose between GL_BACK / offscreenDrawBuffer @@ -4621,3 +4622,41 @@ const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl = IWineD3DSurfaceImpl_GetImplType, IWineD3DSurfaceImpl_DrawOverlay }; +#undef GLINFO_LOCATION + +#define GLINFO_LOCATION device->adapter->gl_info +static HRESULT ffp_blit_alloc(IWineD3DDevice *iface) { return WINED3D_OK; } +static void ffp_blit_free(IWineD3DDevice *iface) { } + +static HRESULT ffp_blit_set(IWineD3DDevice *iface, WINED3DFORMAT fmt, GLenum textype, UINT width, UINT height) { + glEnable(textype); + checkGLcall("glEnable(textype)"); + return WINED3D_OK; +} + +static void ffp_blit_unset(IWineD3DDevice *iface) { + IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) iface; + glDisable(GL_TEXTURE_2D); + checkGLcall("glDisable(GL_TEXTURE_2D)"); + if(GL_SUPPORT(ARB_TEXTURE_CUBE_MAP)) { + glDisable(GL_TEXTURE_CUBE_MAP_ARB); + checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)"); + } + if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE)) { + glDisable(GL_TEXTURE_RECTANGLE_ARB); + checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)"); + } +} + +static BOOL ffp_blit_conv_supported(WINED3DFORMAT fmt) { + TRACE("Checking blit format support for format %s: [FAILED]\n", debug_d3dformat(fmt)); + return FALSE; +} + +const struct blit_shader ffp_blit = { + ffp_blit_alloc, + ffp_blit_free, + ffp_blit_set, + ffp_blit_unset, + ffp_blit_conv_supported +}; diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index 98f7eef9452..e56b4b98d7d 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -42,8 +42,8 @@ static const StaticPixelFormatDesc formats[] = { /*{WINED3DFORMAT ,alphamask ,redmask ,greenmask ,bluemask ,bpp ,depth ,stencil, isFourcc*/ {WINED3DFMT_UNKNOWN ,0x0 ,0x0 ,0x0 ,0x0 ,1 ,0 ,0 ,FALSE }, /* FourCC formats, kept here to have WINED3DFMT_R8G8B8(=20) at position 20 */ - {WINED3DFMT_UYVY ,0x0 ,0x0 ,0x0 ,0x0 ,1/*?*/ ,0 ,0 ,TRUE }, - {WINED3DFMT_YUY2 ,0x0 ,0x0 ,0x0 ,0x0 ,1/*?*/ ,0 ,0 ,TRUE }, + {WINED3DFMT_UYVY ,0x0 ,0x0 ,0x0 ,0x0 ,2 ,0 ,0 ,TRUE }, + {WINED3DFMT_YUY2 ,0x0 ,0x0 ,0x0 ,0x0 ,2 ,0 ,0 ,TRUE }, {WINED3DFMT_YV12 ,0x0 ,0x0 ,0x0 ,0x0 ,1/*?*/ ,0 ,0 ,TRUE }, {WINED3DFMT_DXT1 ,0x0 ,0x0 ,0x0 ,0x0 ,1 ,0 ,0 ,TRUE }, {WINED3DFMT_DXT2 ,0x0 ,0x0 ,0x0 ,0x0 ,1 ,0 ,0 ,TRUE }, @@ -134,10 +134,16 @@ static const GlPixelFormatDescTemplate gl_formats_template[] = { {WINED3DFMT_UNKNOWN ,0 ,0 , 0, 0 ,0 ,0 }, /* FourCC formats */ - {WINED3DFMT_UYVY ,0 ,0 , 0, 0 ,0 - ,0 }, - {WINED3DFMT_YUY2 ,0 ,0 , 0, 0 ,0 - ,0 }, + /* GL_APPLE_ycbcr_422 claims that its '2YUV' format, which is supported via the UNSIGNED_SHORT_8_8_REV_APPLE type + * is equivalent to 'UYVY' format on Windows, and the 'YUVS' via UNSIGNED_SHORT_8_8_APPLE equates to 'YUY2'. The + * d3d9 test however shows that the opposite is true. Since the extension is from 2002, it predates the x86 based + * Macs, so probably the endianess differs. This could be tested as soon as we have a Windows and MacOS on a big + * endian machine + */ + {WINED3DFMT_UYVY ,GL_RGB ,GL_RGB , 0, GL_YCBCR_422_APPLE ,UNSIGNED_SHORT_8_8_APPLE + ,WINED3DFMT_FLAG_FILTERING }, + {WINED3DFMT_YUY2 ,GL_RGB ,GL_RGB , 0, GL_YCBCR_422_APPLE ,UNSIGNED_SHORT_8_8_REV_APPLE + ,WINED3DFMT_FLAG_FILTERING }, {WINED3DFMT_DXT1 ,GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ,GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT , 0, GL_RGBA ,GL_UNSIGNED_BYTE ,WINED3DFMT_FLAG_FILTERING }, {WINED3DFMT_DXT2 ,GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ,GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT , 0, GL_RGBA ,GL_UNSIGNED_BYTE @@ -407,6 +413,21 @@ BOOL initPixelFormats(WineD3D_GL_Info *gl_info) gl_info->gl_formats[dst].conversion_group= WINED3DFMT_ATI2N; } + if(!GL_SUPPORT(APPLE_YCBCR_422)) { + dst = getFmtIdx(WINED3DFMT_YUY2); + gl_info->gl_formats[dst].glInternal = GL_LUMINANCE_ALPHA; + gl_info->gl_formats[dst].glGammaInternal = GL_LUMINANCE_ALPHA; /* not srgb */ + gl_info->gl_formats[dst].glFormat = GL_LUMINANCE_ALPHA; + gl_info->gl_formats[dst].glType = GL_UNSIGNED_BYTE; + gl_info->gl_formats[dst].conversion_group = WINED3DFMT_YUY2; + + dst = getFmtIdx(WINED3DFMT_UYVY); + gl_info->gl_formats[dst].glInternal = GL_LUMINANCE_ALPHA; + gl_info->gl_formats[dst].glGammaInternal = GL_LUMINANCE_ALPHA; /* not srgb */ + gl_info->gl_formats[dst].glFormat = GL_LUMINANCE_ALPHA; + gl_info->gl_formats[dst].glType = GL_UNSIGNED_BYTE; + gl_info->gl_formats[dst].conversion_group = WINED3DFMT_UYVY; + } return TRUE; } @@ -1796,9 +1817,8 @@ void gen_ffp_op(IWineD3DStateBlockImpl *stateblock, struct ffp_settings *setting if(stateblock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) { settings->op[i].cop = WINED3DTOP_DISABLE; settings->op[i].aop = WINED3DTOP_DISABLE; - /* 0x3F: set all 6 bits of the args to 1 */ - settings->op[i].carg0 = settings->op[i].carg1 = settings->op[i].carg2 = 0x3F; - settings->op[i].aarg0 = settings->op[i].aarg1 = settings->op[i].aarg2 = 0x3F; + settings->op[i].carg0 = settings->op[i].carg1 = settings->op[i].carg2 = ARG_UNUSED; + settings->op[i].aarg0 = settings->op[i].aarg1 = settings->op[i].aarg2 = ARG_UNUSED; settings->op[i].color_correction = WINED3DFMT_UNKNOWN; settings->op[i].dst = resultreg; settings->op[i].tex_type = tex_1d; diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 6f1479032b3..e2b1215960a 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -247,6 +247,7 @@ typedef struct { void (*shader_generate_pshader)(IWineD3DPixelShader *iface, SHADER_BUFFER *buffer); void (*shader_generate_vshader)(IWineD3DVertexShader *iface, SHADER_BUFFER *buffer); void (*shader_get_caps)(WINED3DDEVTYPE devtype, WineD3D_GL_Info *gl_info, struct shader_caps *caps); + BOOL (*shader_conv_supported)(WINED3DFORMAT conv); } shader_backend_t; extern const shader_backend_t atifs_shader_backend; @@ -556,6 +557,7 @@ struct fragment_pipeline { void (*get_caps)(WINED3DDEVTYPE devtype, WineD3D_GL_Info *gl_info, struct fragment_caps *caps); HRESULT (*alloc_private)(IWineD3DDevice *iface); void (*free_private)(IWineD3DDevice *iface); + BOOL (*conv_supported)(WINED3DFORMAT conv); const struct StateEntryTemplate *states; }; @@ -575,6 +577,18 @@ void compile_state_table(struct StateEntry *StateTable, const struct fragment_pipeline *fragment, const struct StateEntryTemplate *misc); +/* Shaders for color conversions in blits */ +struct blit_shader { + HRESULT (*alloc_private)(IWineD3DDevice *iface); + void (*free_private)(IWineD3DDevice *iface); + HRESULT (*set_shader)(IWineD3DDevice *iface, WINED3DFORMAT fmt, GLenum textype, UINT width, UINT height); + void (*unset_shader)(IWineD3DDevice *iface); + BOOL (*conv_supported)(WINED3DFORMAT conv); +}; + +extern const struct blit_shader ffp_blit; +extern const struct blit_shader arbfp_blit; + /* The new context manager that should deal with onscreen and offscreen rendering */ struct WineD3DContext { /* State dirtification @@ -746,6 +760,7 @@ enum dst_arg struct texture_stage_op { unsigned cop : 5, aop : 5; +#define ARG_UNUSED 0x3f unsigned carg1 : 6, carg2 : 6, carg0 : 6; unsigned tex_type : 3; unsigned dst : 1; /* Total of 32 bits */ @@ -829,10 +844,12 @@ struct IWineD3DDeviceImpl const shader_backend_t *shader_backend; void *shader_priv; void *fragment_priv; + void *blit_priv; struct StateEntry StateTable[STATE_HIGHEST + 1]; /* Array of functions for states which are handled by more than one pipeline part */ APPLYSTATEFUNC *multistate_funcs[STATE_HIGHEST + 1]; const struct fragment_pipeline *frag_pipe; + const struct blit_shader *blitter; /* To store */ BOOL view_ident; /* true iff view matrix is identity */ diff --git a/dlls/winedos/vga.c b/dlls/winedos/vga.c index fd52689209d..9afbc4cc067 100644 --- a/dlls/winedos/vga.c +++ b/dlls/winedos/vga.c @@ -295,6 +295,7 @@ static void CALLBACK set_timer_rate( ULONG_PTR arg ) static DWORD CALLBACK VGA_TimerThread( void *dummy ) { for (;;) SleepEx( INFINITE, TRUE ); + return 0; } static void VGA_DeinstallTimer(void) diff --git a/dlls/winedos/vxd.c b/dlls/winedos/vxd.c index 0b3602a6332..a719c30e108 100644 --- a/dlls/winedos/vxd.c +++ b/dlls/winedos/vxd.c @@ -407,6 +407,8 @@ static DWORD CALLBACK timer_thread( void *arg ) *system_time = GetTickCount(); Sleep( 55 ); } + + return 0; } diff --git a/dlls/wineoss.drv/audio.c b/dlls/wineoss.drv/audio.c index 2e22d14af6a..460c1f5372c 100644 --- a/dlls/wineoss.drv/audio.c +++ b/dlls/wineoss.drv/audio.c @@ -1923,6 +1923,8 @@ static DWORD CALLBACK wodPlayer(LPVOID pmt) dwNextFeedTime = dwNextNotifyTime = INFINITE; } } + + return 0; } /************************************************************************** diff --git a/dlls/winhttp/Makefile.in b/dlls/winhttp/Makefile.in index c65adbd5ee7..02cd48cf955 100644 --- a/dlls/winhttp/Makefile.in +++ b/dlls/winhttp/Makefile.in @@ -9,6 +9,7 @@ IMPORTS = wininet kernel32 C_SRCS = \ handle.c \ main.c \ + request.c \ session.c @MAKE_DLL_RULES@ diff --git a/dlls/winhttp/main.c b/dlls/winhttp/main.c index c503e230136..b660dba56e2 100644 --- a/dlls/winhttp/main.c +++ b/dlls/winhttp/main.c @@ -164,30 +164,6 @@ BOOL WINAPI WinHttpWriteData (HINTERNET hRequest, LPCVOID lpBuffer, return FALSE; } -/*********************************************************************** - * WinHttpQueryHeaders (winhttp.@) - */ -BOOL WINAPI WinHttpQueryHeaders (HINTERNET hRequest, DWORD dwInfoLevel, LPCWSTR pwszName, - LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex) -{ - FIXME("(%d): stub\n", dwInfoLevel); - - SetLastError(ERROR_NOT_SUPPORTED); - return FALSE; -} - -/*********************************************************************** - * WinHttpAddRequestHeaders (winhttp.@) - */ -BOOL WINAPI WinHttpAddRequestHeaders (HINTERNET hRequest, LPCWSTR pwszHeaders, - DWORD dwHeadersLength, DWORD dwModifiers) -{ - FIXME("(%s, %d, %d): stub\n", debugstr_w(pwszHeaders), dwHeadersLength, dwModifiers); - - SetLastError(ERROR_NOT_SUPPORTED); - return FALSE; -} - BOOL WINAPI InternetCrackUrlW( LPCWSTR, DWORD, DWORD, LPURL_COMPONENTSW ); BOOL WINAPI InternetCreateUrlW( LPURL_COMPONENTS, DWORD, LPWSTR, LPDWORD ); diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c new file mode 100644 index 00000000000..ab3dc810103 --- /dev/null +++ b/dlls/winhttp/request.c @@ -0,0 +1,515 @@ +/* + * Copyright 2008 Hans Leidekker for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wine/port.h" +#include "wine/debug.h" + +#include + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "winhttp.h" + +#include "winhttp_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winhttp); + +static void free_header( header_t *header ) +{ + heap_free( header->field ); + heap_free( header->value ); + heap_free( header ); +} + +static BOOL valid_token_char( WCHAR c ) +{ + if (c < 32 || c == 127) return FALSE; + switch (c) + { + case '(': case ')': + case '<': case '>': + case '@': case ',': + case ';': case ':': + case '\\': case '\"': + case '/': case '[': + case ']': case '?': + case '=': case '{': + case '}': case ' ': + case '\t': + return FALSE; + default: + return TRUE; + } +} + +static header_t *parse_header( LPCWSTR string ) +{ + const WCHAR *p, *q; + header_t *header; + int len; + + p = string; + if (!(q = strchrW( p, ':' ))) + { + WARN("no ':' in line %s\n", debugstr_w(string)); + return NULL; + } + if (q == string) + { + WARN("empty field name in line %s\n", debugstr_w(string)); + return NULL; + } + while (*p != ':') + { + if (!valid_token_char( *p )) + { + WARN("invalid character in field name %s\n", debugstr_w(string)); + return NULL; + } + p++; + } + len = q - string; + if (!(header = heap_alloc_zero( sizeof(header_t) ))) return NULL; + if (!(header->field = heap_alloc( (len + 1) * sizeof(WCHAR) ))) + { + heap_free( header ); + return NULL; + } + memcpy( header->field, string, len * sizeof(WCHAR) ); + header->field[len] = 0; + + q++; /* skip past colon */ + while (*q == ' ') q++; + if (!*q) + { + WARN("no value in line %s\n", debugstr_w(string)); + return header; + } + len = strlenW( q ); + if (!(header->value = heap_alloc( (len + 1) * sizeof(WCHAR) ))) + { + free_header( header ); + return NULL; + } + memcpy( header->value, q, len * sizeof(WCHAR) ); + header->value[len] = 0; + + return header; +} + +static int get_header_index( request_t *request, LPCWSTR field, int requested_index, BOOL request_only ) +{ + int index; + + TRACE("%s\n", debugstr_w(field)); + + for (index = 0; index < request->num_headers; index++) + { + if (strcmpiW( request->headers[index].field, field )) continue; + if (request_only && !request->headers[index].is_request) continue; + if (!request_only && request->headers[index].is_request) continue; + + if (!requested_index) break; + requested_index--; + } + if (index >= request->num_headers) index = -1; + TRACE("returning %d\n", index); + return index; +} + +static BOOL insert_header( request_t *request, header_t *header ) +{ + DWORD count; + header_t *hdrs; + + TRACE("inserting %s: %s\n", debugstr_w(header->field), debugstr_w(header->value)); + + count = request->num_headers + 1; + if (count > 1) + hdrs = heap_realloc_zero( request->headers, sizeof(header_t) * count ); + else + hdrs = heap_alloc_zero( sizeof(header_t) * count ); + + if (hdrs) + { + request->headers = hdrs; + request->headers[count - 1].field = strdupW( header->field ); + request->headers[count - 1].value = strdupW( header->value ); + request->headers[count - 1].is_request = header->is_request; + request->num_headers++; + return TRUE; + } + return FALSE; +} + +static BOOL delete_header( request_t *request, DWORD index ) +{ + if (!request->num_headers) return FALSE; + if (index >= request->num_headers) return FALSE; + request->num_headers--; + + heap_free( request->headers[index].field ); + heap_free( request->headers[index].value ); + + memmove( &request->headers[index], &request->headers[index + 1], (request->num_headers - index) * sizeof(header_t) ); + memset( &request->headers[request->num_headers], 0, sizeof(header_t) ); + return TRUE; +} + +static BOOL process_header( request_t *request, LPCWSTR field, LPCWSTR value, DWORD flags, BOOL request_only ) +{ + int index; + header_t *header; + + TRACE("%s: %s 0x%08x\n", debugstr_w(field), debugstr_w(value), flags); + + /* replace wins out over add */ + if (flags & WINHTTP_ADDREQ_FLAG_REPLACE) flags &= ~WINHTTP_ADDREQ_FLAG_ADD; + + if (flags & WINHTTP_ADDREQ_FLAG_ADD) index = -1; + else + index = get_header_index( request, field, 0, request_only ); + + if (index >= 0) + { + if (flags & WINHTTP_ADDREQ_FLAG_ADD_IF_NEW) return FALSE; + header = &request->headers[index]; + } + else if (value) + { + header_t hdr; + + hdr.field = (LPWSTR)field; + hdr.value = (LPWSTR)value; + hdr.is_request = request_only; + + return insert_header( request, &hdr ); + } + /* no value to delete */ + else return TRUE; + + if (flags & WINHTTP_ADDREQ_FLAG_REPLACE) + { + delete_header( request, index ); + if (value) + { + header_t hdr; + + hdr.field = (LPWSTR)field; + hdr.value = (LPWSTR)value; + hdr.is_request = request_only; + + return insert_header( request, &hdr ); + } + return TRUE; + } + else if (flags & (WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA | WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON)) + { + WCHAR sep, *tmp; + int len, orig_len, value_len; + + orig_len = strlenW( header->value ); + value_len = strlenW( value ); + + if (flags & WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA) sep = ','; + else sep = ';'; + + len = orig_len + value_len + 2; + if ((tmp = heap_realloc( header->value, (len + 1) * sizeof(WCHAR) ))) + { + header->value = tmp; + + header->value[orig_len] = sep; + orig_len++; + header->value[orig_len] = ' '; + orig_len++; + + memcpy( &header->value[orig_len], value, value_len * sizeof(WCHAR) ); + header->value[len] = 0; + return TRUE; + } + } + return TRUE; +} + +static BOOL add_request_headers( request_t *request, LPCWSTR headers, DWORD len, DWORD flags ) +{ + BOOL ret = FALSE; + WCHAR *buffer, *p, *q; + header_t *header; + + if (len == ~0UL) len = strlenW( headers ); + if (!(buffer = heap_alloc( (len + 1) * sizeof(WCHAR) ))) return FALSE; + strcpyW( buffer, headers ); + + p = buffer; + do + { + q = p; + while (*q) + { + if (q[0] == '\r' && q[1] == '\n') break; + q++; + } + if (!*p) break; + if (*q == '\r') + { + *q = 0; + q += 2; /* jump over \r\n */ + } + if ((header = parse_header( p ))) + { + ret = process_header( request, header->field, header->value, flags, TRUE ); + free_header( header ); + } + p = q; + } while (ret); + + heap_free( buffer ); + return ret; +} + +/*********************************************************************** + * WinHttpAddRequestHeaders (winhttp.@) + */ +BOOL WINAPI WinHttpAddRequestHeaders( HINTERNET hrequest, LPCWSTR headers, DWORD len, DWORD flags ) +{ + BOOL ret; + request_t *request; + + TRACE("%p, %s, 0x%x, 0x%08x\n", hrequest, debugstr_w(headers), len, flags); + + if (!headers) + { + set_last_error( ERROR_INVALID_PARAMETER ); + return FALSE; + } + if (!(request = (request_t *)grab_object( hrequest ))) + { + set_last_error( ERROR_INVALID_HANDLE ); + return FALSE; + } + if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST) + { + release_object( &request->hdr ); + set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE ); + return FALSE; + } + + ret = add_request_headers( request, headers, len, flags ); + + release_object( &request->hdr ); + return ret; +} + +static WCHAR *build_request_string( request_t *request, LPCWSTR verb, LPCWSTR path, LPCWSTR version ) +{ + static const WCHAR space[] = {' ',0}; + static const WCHAR crlf[] = {'\r','\n',0}; + static const WCHAR colon[] = {':',' ',0}; + static const WCHAR twocrlf[] = {'\r','\n','\r','\n',0}; + + WCHAR *ret; + const WCHAR **headers, **p; + unsigned int len, i = 0, j; + + /* allocate space for an array of all the string pointers to be added */ + len = request->num_headers * 4 + 7; + if (!(headers = heap_alloc( len * sizeof(LPCWSTR) ))) return NULL; + + headers[i++] = verb; + headers[i++] = space; + headers[i++] = path; + headers[i++] = space; + headers[i++] = version; + + for (j = 0; j < request->num_headers; j++) + { + if (request->headers[j].is_request) + { + headers[i++] = crlf; + headers[i++] = request->headers[j].field; + headers[i++] = colon; + headers[i++] = request->headers[j].value; + + TRACE("adding header %s (%s)\n", debugstr_w(request->headers[j].field), + debugstr_w(request->headers[j].value)); + } + } + headers[i++] = twocrlf; + headers[i] = NULL; + + len = 0; + for (p = headers; *p; p++) len += strlenW( *p ); + len++; + + if (!(ret = heap_alloc( len * sizeof(WCHAR) ))) + { + heap_free( headers ); + return NULL; + } + *ret = 0; + for (p = headers; *p; p++) strcatW( ret, *p ); + + heap_free( headers ); + return ret; +} + +#define QUERY_MODIFIER_MASK (WINHTTP_QUERY_FLAG_REQUEST_HEADERS | WINHTTP_QUERY_FLAG_SYSTEMTIME | WINHTTP_QUERY_FLAG_NUMBER) + +static BOOL query_headers( request_t *request, DWORD level, LPCWSTR name, LPVOID buffer, LPDWORD buflen, LPDWORD index ) +{ + header_t *header = NULL; + BOOL request_only, ret = FALSE; + int requested_index, header_index = -1; + DWORD attribute; + + request_only = level & WINHTTP_QUERY_FLAG_REQUEST_HEADERS; + requested_index = index ? *index : 0; + + attribute = level & ~QUERY_MODIFIER_MASK; + switch (attribute) + { + case WINHTTP_QUERY_CUSTOM: + { + header_index = get_header_index( request, name, requested_index, request_only ); + break; + } + case WINHTTP_QUERY_RAW_HEADERS_CRLF: + { + WCHAR *headers; + DWORD len; + + if (request_only) + headers = build_request_string( request, request->verb, request->path, request->version ); + else + headers = request->raw_headers; + + len = strlenW( headers ) * sizeof(WCHAR); + if (len + sizeof(WCHAR) > *buflen) + { + len += sizeof(WCHAR); + set_last_error( ERROR_INSUFFICIENT_BUFFER ); + } + else if (buffer) + { + memcpy( buffer, headers, len + sizeof(WCHAR) ); + TRACE("returning data: %s\n", debugstr_wn(buffer, len / sizeof(WCHAR))); + ret = TRUE; + } + *buflen = len; + if (request_only) heap_free( headers ); + return ret; + } + default: + { + FIXME("attribute %u not implemented\n", attribute); + return FALSE; + } + } + + if (header_index >= 0) + { + header = &request->headers[header_index]; + } + if (!header || (request_only && !header->is_request)) + { + set_last_error( ERROR_WINHTTP_HEADER_NOT_FOUND ); + return FALSE; + } + if (index) *index += 1; + if (level & WINHTTP_QUERY_FLAG_NUMBER) + { + int *number = buffer; + if (sizeof(int) > *buflen) + { + set_last_error( ERROR_INSUFFICIENT_BUFFER ); + } + else if (number) + { + *number = atoiW( header->value ); + TRACE("returning number: %d\n", *number); + ret = TRUE; + } + *buflen = sizeof(int); + } + else if (level & WINHTTP_QUERY_FLAG_SYSTEMTIME) + { + SYSTEMTIME *st = buffer; + if (sizeof(SYSTEMTIME) > *buflen) + { + set_last_error( ERROR_INSUFFICIENT_BUFFER ); + } + else if (st && (ret = WinHttpTimeToSystemTime( header->value, st ))) + { + TRACE("returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n", + st->wYear, st->wMonth, st->wDay, st->wDayOfWeek, + st->wHour, st->wMinute, st->wSecond, st->wMilliseconds); + } + *buflen = sizeof(SYSTEMTIME); + } + else if (header->value) + { + WCHAR *string = buffer; + DWORD len = (strlenW( header->value ) + 1) * sizeof(WCHAR); + if (len > *buflen) + { + set_last_error( ERROR_INSUFFICIENT_BUFFER ); + *buflen = len; + return FALSE; + } + else if (string) + { + strcpyW( string, header->value ); + TRACE("returning string: %s\n", debugstr_w(string)); + ret = TRUE; + } + *buflen = len - sizeof(WCHAR); + } + return ret; +} + +/*********************************************************************** + * WinHttpQueryHeaders (winhttp.@) + */ +BOOL WINAPI WinHttpQueryHeaders( HINTERNET hrequest, DWORD level, LPCWSTR name, LPVOID buffer, LPDWORD buflen, LPDWORD index ) +{ + BOOL ret; + request_t *request; + + TRACE("%p, 0x%08x, %s, %p, %p, %p\n", hrequest, level, debugstr_w(name), buffer, buflen, index); + + if (!(request = (request_t *)grab_object( hrequest ))) + { + set_last_error( ERROR_INVALID_HANDLE ); + return FALSE; + } + if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST) + { + release_object( &request->hdr ); + set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE ); + return FALSE; + } + + ret = query_headers( request, level, name, buffer, buflen, index ); + + release_object( &request->hdr ); + return ret; +} diff --git a/dlls/winhttp/session.c b/dlls/winhttp/session.c index eb2c71fa9f4..d2bb3407e0f 100644 --- a/dlls/winhttp/session.c +++ b/dlls/winhttp/session.c @@ -31,7 +31,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(winhttp); -static void set_last_error( DWORD error ) +void set_last_error( DWORD error ) { /* FIXME */ SetLastError( error ); @@ -39,7 +39,9 @@ static void set_last_error( DWORD error ) void send_callback( object_header_t *hdr, DWORD status, LPVOID info, DWORD buflen ) { - FIXME("%p, %u, %p, %u\n", hdr, status, info, buflen); + TRACE("%p, %u, %p, %u\n", hdr, status, info, buflen); + + if (hdr->notify_mask & status) hdr->callback( hdr->handle, hdr->context, status, info, buflen ); } /*********************************************************************** @@ -228,6 +230,10 @@ static const object_vtbl_t request_vtbl = HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, LPCWSTR verb, LPCWSTR object, LPCWSTR version, LPCWSTR referrer, LPCWSTR *types, DWORD flags ) { + static const WCHAR get[] = {'G','E','T',0}; + static const WCHAR slash[] = {'/',0}; + static const WCHAR http1_1[] = {'H','T','T','P','/','1','.','1',0}; + request_t *request; connect_t *connect; HINTERNET hrequest = NULL; @@ -262,9 +268,13 @@ HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, LPCWSTR verb, LPCWSTR o request->connect = connect; list_add_head( &connect->hdr.children, &request->hdr.entry ); - if (verb && !(request->verb = strdupW( verb ))) goto end; - if (object && !(request->path = strdupW( object ))) goto end; - if (version && !(request->version = strdupW( version ))) goto end; + if (!verb) verb = get; + if (!object) object = slash; + if (!version) version = http1_1; + + if (!(request->verb = strdupW( verb ))) goto end; + if (!(request->path = strdupW( object ))) goto end; + if (!(request->version = strdupW( version ))) goto end; if (!(hrequest = alloc_handle( &request->hdr ))) goto end; request->hdr.handle = hrequest; @@ -392,6 +402,15 @@ WINHTTP_STATUS_CALLBACK WINAPI WinHttpSetStatusCallback( HINTERNET handle, WINHT return ret; } +/*********************************************************************** + * WinHttpSetTimeouts (winhttp.@) + */ +BOOL WINAPI WinHttpSetTimeouts( HINTERNET handle, int resolve, int connect, int send, int receive ) +{ + FIXME("%p, %d, %d, %d, %d\n", handle, resolve, connect, send, receive); + return TRUE; +} + static const WCHAR wkday[7][4] = {{'S','u','n', 0}, {'M','o','n', 0}, {'T','u','e', 0}, {'W','e','d', 0}, {'T','h','u', 0}, {'F','r','i', 0}, {'S','a','t', 0}}; diff --git a/dlls/winhttp/tests/winhttp.c b/dlls/winhttp/tests/winhttp.c index 395d66f3b14..527794dddf8 100644 --- a/dlls/winhttp/tests/winhttp.c +++ b/dlls/winhttp/tests/winhttp.c @@ -17,6 +17,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ + #include #include #include @@ -203,6 +204,9 @@ static void test_WinHttpAddHeaders(void) static const WCHAR test_flag_coalesce_semicolon[] = {'t','e','s','t','2',',',' ','t','e','s','t','4',',',' ','t','e','s','t','5',';',' ','t','e','s','t','6',0}; + static const WCHAR field[] = {'f','i','e','l','d',0}; + static const WCHAR value[] = {'v','a','l','u','e',' ',0}; + static const WCHAR test_headers[][14] = { {'W','a','r','n','i','n','g',':','t','e','s','t','1',0}, @@ -211,7 +215,14 @@ static void test_WinHttpAddHeaders(void) {'W','a','r','n','i','n','g',':','t','e','s','t','4',0}, {'W','a','r','n','i','n','g',':','t','e','s','t','5',0}, {'W','a','r','n','i','n','g',':','t','e','s','t','6',0}, - {'W','a','r','n','i','n','g',':','t','e','s','t','7',0} + {'W','a','r','n','i','n','g',':','t','e','s','t','7',0}, + {0}, + {':',0}, + {'a',':',0}, + {':','b',0}, + {'c','d',0}, + {' ','e',' ',':','f',0}, + {'f','i','e','l','d',':',' ','v','a','l','u','e',' ',0} }; static const WCHAR test_indices[][6] = { @@ -243,21 +254,17 @@ static void test_WinHttpAddHeaders(void) test_header_name, buffer, &len, &index); ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded, found 'Warning' header."); ret = WinHttpAddRequestHeaders(request, test_headers[0], -1L, WINHTTP_ADDREQ_FLAG_ADD); - todo_wine ok(ret == TRUE, "WinHttpAddRequestHeader failed to add new header, got %d with error %u.\n", ret, GetLastError()); + ok(ret == TRUE, "WinHttpAddRequestHeader failed to add new header, got %d with error %u.\n", ret, GetLastError()); index = 0; len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, test_header_name, buffer, &len, &index); - todo_wine - { - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); - ok(index == 1, "WinHttpQueryHeaders failed: header index not incremented\n"); - ok(memcmp(buffer, test_indices[0], sizeof(test_indices[0])) == 0, - "WinHttpQueryHeaders failed: incorrect string returned\n"); - ok(len == 5*sizeof(WCHAR), - "WinHttpQueryHeaders failed: invalid length returned, expected 5, got %d\n", len); - } + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 1, "WinHttpQueryHeaders failed: header index not incremented\n"); + ok(memcmp(buffer, test_indices[0], sizeof(test_indices[0])) == 0, "WinHttpQueryHeaders failed: incorrect string returned\n"); + ok(len == 5*sizeof(WCHAR), "WinHttpQueryHeaders failed: invalid length returned, expected 5, got %d\n", len); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, test_header_name, buffer, &len, &index); ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded, second index should not exist.\n"); @@ -271,7 +278,7 @@ static void test_WinHttpAddHeaders(void) ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded with a buffer thats too small.\n"); ok(memcmp(buffer, check_buffer, sizeof(buffer)) == 0, "WinHttpQueryHeaders failed, modified the buffer when it should not have.\n"); - todo_wine ok(len == 6*sizeof(WCHAR), "WinHttpQueryHeaders returned invalid length, expected 12, got %d\n", len); + ok(len == 6*sizeof(WCHAR), "WinHttpQueryHeaders returned invalid length, expected 12, got %d\n", len); /* Try with a NULL buffer */ index = 0; @@ -291,12 +298,9 @@ static void test_WinHttpAddHeaders(void) ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS_CRLF | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, test_header_name, NULL, &len, &index); ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded.\n"); - todo_wine - { - ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "WinHttpQueryHeaders set incorrect error: expected ERROR_INSUFFICENT_BUFFER, go %u\n", GetLastError()); - ok(len > 40, "WinHttpQueryHeaders returned invalid length: expected greater than 40, got %d\n", len); - } + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "WinHttpQueryHeaders set incorrect error: expected ERROR_INSUFFICENT_BUFFER, go %u\n", GetLastError()); + ok(len > 40, "WinHttpQueryHeaders returned invalid length: expected greater than 40, got %d\n", len); ok(index == 0, "WinHttpQueryHeaders incorrectly incremented header index.\n"); index = 0; @@ -305,13 +309,9 @@ static void test_WinHttpAddHeaders(void) ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS_CRLF | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, test_header_name, NULL, &len, &index); ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded.\n"); - todo_wine - { - ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "WinHttpQueryHeaders set incorrect error: expected ERROR_INSUFFICIENT_BUFFER, got %u\n", - GetLastError()); - ok(len > 40, "WinHttpQueryHeaders returned invalid length: expected greater than 40, got %d\n", len); - } + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "WinHttpQueryHeaders set incorrect error: expected ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); + ok(len > 40, "WinHttpQueryHeaders returned invalid length: expected greater than 40, got %d\n", len); ok(index == 0, "WinHttpQueryHeaders failed: index was incremented.\n"); /* valid query */ @@ -321,70 +321,52 @@ static void test_WinHttpAddHeaders(void) memset(buffer, 0xff, sizeof(buffer)); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS_CRLF | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, test_header_name, buffer, &len, &index); - todo_wine - { - ok(ret == TRUE, "WinHttpQueryHeaders failed: got %d\n", ret); - ok(len + sizeof(WCHAR) <= oldlen, "WinHttpQueryHeaders resulting length longer than advertized.\n"); - ok((len < sizeof(buffer) - sizeof(WCHAR)) && buffer[len / sizeof(WCHAR)] == 0, - "WinHttpQueryHeaders did not append NULL terminator\n"); - ok(len == lstrlenW(buffer) * sizeof(WCHAR), "WinHttpQueryHeaders returned incorrect length.\n"); - ok(memcmp(buffer, test_header_begin, sizeof(test_header_begin)) == 0, - "WinHttpQueryHeaders returned invalid beginning of header string.\n"); - ok(memcmp(buffer + lstrlenW(buffer) - 4, test_header_end, sizeof(test_header_end)) == 0, - "WinHttpQueryHeaders returned invalid end of header string.\n"); - } + ok(ret == TRUE, "WinHttpQueryHeaders failed: got %d\n", ret); + ok(len + sizeof(WCHAR) <= oldlen, "WinHttpQueryHeaders resulting length longer than advertized.\n"); + ok((len < sizeof(buffer) - sizeof(WCHAR)) && buffer[len / sizeof(WCHAR)] == 0, "WinHttpQueryHeaders did not append NULL terminator\n"); + ok(len == lstrlenW(buffer) * sizeof(WCHAR), "WinHttpQueryHeaders returned incorrect length.\n"); + ok(memcmp(buffer, test_header_begin, sizeof(test_header_begin)) == 0, + "WinHttpQueryHeaders returned invalid beginning of header string.\n"); + ok(memcmp(buffer + lstrlenW(buffer) - 4, test_header_end, sizeof(test_header_end)) == 0, + "WinHttpQueryHeaders returned invalid end of header string.\n"); ok(index == 0, "WinHttpQueryHeaders incremented header index.\n"); /* tests for more indices */ ret = WinHttpAddRequestHeaders(request, test_headers[1], -1L, WINHTTP_ADDREQ_FLAG_ADD); - todo_wine ok(ret == TRUE, "WinHttpAddRequestHeaders failed to add duplicate header: %d\n", ret); + ok(ret == TRUE, "WinHttpAddRequestHeaders failed to add duplicate header: %d\n", ret); index = 0; len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, test_header_name, buffer, &len, &index); - todo_wine - { - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); - ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, test_indices[0], sizeof(test_indices[0])) == 0, - "WinHttpQueryHeaders returned incorrect string.\n"); - } + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_indices[0], sizeof(test_indices[0])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, test_header_name, buffer, &len, &index); - todo_wine - { - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); - ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, test_indices[1], sizeof(test_indices[1])) == 0, - "WinHttpQueryHeaders returned incorrect string.\n"); - } + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_indices[1], sizeof(test_indices[1])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); ret = WinHttpAddRequestHeaders(request, test_headers[2], -1L, WINHTTP_ADDREQ_FLAG_REPLACE); - todo_wine ok(ret == TRUE, "WinHttpAddRequestHeaders failed to add duplicate header.\n"); + ok(ret == TRUE, "WinHttpAddRequestHeaders failed to add duplicate header.\n"); index = 0; len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, test_header_name, buffer, &len, &index); - todo_wine - { - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); - ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, test_indices[1], sizeof(test_indices[1])) == 0, - "WinHttpQueryHeaders returned incorrect string.\n"); - } + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_indices[1], sizeof(test_indices[1])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, test_header_name, buffer, &len, &index); - todo_wine - { - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); - ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, test_indices[2], sizeof(test_indices[2])) == 0, - "WinHttpQueryHeaders returned incorrect string.\n"); - } + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_indices[2], sizeof(test_indices[2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); /* add if new flag */ ret = WinHttpAddRequestHeaders(request, test_headers[3], -1L, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW); @@ -394,23 +376,17 @@ static void test_WinHttpAddHeaders(void) len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, test_header_name, buffer, &len, &index); - todo_wine - { - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); - ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, test_indices[1], sizeof(test_indices[1])) == 0, - "WinHttpQueryHeaders returned incorrect string.\n"); - } + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_indices[1], sizeof(test_indices[1])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, test_header_name, buffer, &len, &index); - todo_wine - { - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); - ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, test_indices[2], sizeof(test_indices[2])) == 0, - "WinHttpQueryHeaders returned incorrect string.\n"); - } + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_indices[2], sizeof(test_indices[2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, test_header_name, buffer, &len, &index); @@ -418,29 +394,23 @@ static void test_WinHttpAddHeaders(void) /* coalesce flag */ ret = WinHttpAddRequestHeaders(request, test_headers[3], -1L, WINHTTP_ADDREQ_FLAG_COALESCE); - todo_wine ok(ret == TRUE, "WinHttpAddRequestHeaders failed with flag WINHTTP_ADDREQ_FLAG_COALESCE.\n"); + ok(ret == TRUE, "WinHttpAddRequestHeaders failed with flag WINHTTP_ADDREQ_FLAG_COALESCE.\n"); index = 0; len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, test_header_name, buffer, &len, &index); - todo_wine - { - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); - ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, test_flag_coalesce, sizeof(test_flag_coalesce)) == 0, - "WinHttpQueryHeaders returned incorrect string.\n"); - } + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_flag_coalesce, sizeof(test_flag_coalesce)) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, test_header_name, buffer, &len, &index); - todo_wine - { - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); - ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, test_indices[2], sizeof(test_indices[2])) == 0, - "WinHttpQueryHeaders returned incorrect string.\n"); - } + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_indices[2], sizeof(test_indices[2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, test_header_name, buffer, &len, &index); @@ -448,29 +418,24 @@ static void test_WinHttpAddHeaders(void) /* coalesce with comma flag */ ret = WinHttpAddRequestHeaders(request, test_headers[4], -1L, WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA); - todo_wine ok(ret == TRUE, "WinHttpAddRequestHeaders failed with flag WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA.\n"); + ok(ret == TRUE, "WinHttpAddRequestHeaders failed with flag WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA.\n"); index = 0; len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, test_header_name, buffer, &len, &index); - todo_wine - { - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); - ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, test_flag_coalesce_comma, sizeof(test_flag_coalesce_comma)) == 0, - "WinHttpQueryHeaders returned incorrect string.\n"); - } + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_flag_coalesce_comma, sizeof(test_flag_coalesce_comma)) == 0, + "WinHttpQueryHeaders returned incorrect string.\n"); + len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, test_header_name, buffer, &len, &index); - todo_wine - { - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); - ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, test_indices[2], sizeof(test_indices[2])) == 0, - "WinHttpQueryHeaders returned incorrect string.\n"); - } + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_indices[2], sizeof(test_indices[2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, test_header_name, buffer, &len, &index); @@ -479,29 +444,24 @@ static void test_WinHttpAddHeaders(void) /* coalesce with semicolon flag */ ret = WinHttpAddRequestHeaders(request, test_headers[5], -1L, WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON); - todo_wine ok(ret == TRUE, "WinHttpAddRequestHeaders failed with flag WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON.\n"); + ok(ret == TRUE, "WinHttpAddRequestHeaders failed with flag WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON.\n"); index = 0; len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, test_header_name, buffer, &len, &index); - todo_wine - { - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); - ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, test_flag_coalesce_semicolon, sizeof(test_flag_coalesce_semicolon)) == 0, + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_flag_coalesce_semicolon, sizeof(test_flag_coalesce_semicolon)) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); - } + len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, test_header_name, buffer, &len, &index); - todo_wine - { - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); - ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, test_indices[2], sizeof(test_indices[2])) == 0, - "WinHttpQueryHeaders returned incorrect string.\n"); - } + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_indices[2], sizeof(test_indices[2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, test_header_name, buffer, &len, &index); @@ -509,35 +469,54 @@ static void test_WinHttpAddHeaders(void) /* add and replace flags */ ret = WinHttpAddRequestHeaders(request, test_headers[3], -1L, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE); - todo_wine ok(ret == TRUE, - "WinHttpAddRequestHeaders failed with flag WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE.\n"); + ok(ret == TRUE, "WinHttpAddRequestHeaders failed with flag WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE.\n"); index = 0; len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, test_header_name, buffer, &len, &index); - todo_wine - { - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); - ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, test_indices[2], sizeof(test_indices[2])) == 0, - "WinHttpQueryHeaders returned incorrect string.\n"); - } + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_indices[2], sizeof(test_indices[2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, test_header_name, buffer, &len, &index); - todo_wine - { - ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); - ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); - ok(memcmp(buffer, test_indices[3], sizeof(test_indices[2])) == 0, - "WinHttpQueryHeaders returned incorrect string.\n"); - } + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_indices[3], sizeof(test_indices[2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + len = sizeof(buffer); ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, test_header_name, buffer, &len, &index); ok(ret == FALSE, "WinHttpQueryHeaders succeeded unexpectedly, found third header.\n"); + ret = WinHttpAddRequestHeaders(request, test_headers[8], ~0UL, WINHTTP_ADDREQ_FLAG_ADD); + ok(!ret, "WinHttpAddRequestHeaders failed\n"); + + ret = WinHttpAddRequestHeaders(request, test_headers[9], ~0UL, WINHTTP_ADDREQ_FLAG_ADD); + ok(ret, "WinHttpAddRequestHeaders failed\n"); + + ret = WinHttpAddRequestHeaders(request, test_headers[10], ~0UL, WINHTTP_ADDREQ_FLAG_ADD); + ok(!ret, "WinHttpAddRequestHeaders failed\n"); + + ret = WinHttpAddRequestHeaders(request, test_headers[11], ~0UL, WINHTTP_ADDREQ_FLAG_ADD); + ok(!ret, "WinHttpAddRequestHeaders failed\n"); + + ret = WinHttpAddRequestHeaders(request, test_headers[12], ~0UL, WINHTTP_ADDREQ_FLAG_ADD); + ok(!ret, "WinHttpAddRequestHeaders failed\n"); + + ret = WinHttpAddRequestHeaders(request, test_headers[13], ~0UL, WINHTTP_ADDREQ_FLAG_ADD); + ok(ret, "WinHttpAddRequestHeaders failed\n"); + + index = 0; + buffer[0] = 0; + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + field, buffer, &len, &index); + ok(ret, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(!memcmp(buffer, value, sizeof(value)), "unexpected result\n"); + ret = WinHttpCloseHandle(request); ok(ret == TRUE, "WinHttpCloseHandle failed on closing request, got %d.\n", ret); done: diff --git a/dlls/winhttp/winhttp.spec b/dlls/winhttp/winhttp.spec index 08e4d93a304..eadc07eba08 100644 --- a/dlls/winhttp/winhttp.spec +++ b/dlls/winhttp/winhttp.spec @@ -25,7 +25,7 @@ @ stdcall WinHttpSetDefaultProxyConfiguration(ptr long long wstr ptr ptr) @ stdcall WinHttpSetOption(ptr long ptr long) @ stdcall WinHttpSetStatusCallback(ptr ptr long ptr) -@ stub WinHttpSetTimeouts +@ stdcall WinHttpSetTimeouts(ptr long long long long) @ stdcall WinHttpTimeFromSystemTime(ptr ptr) @ stdcall WinHttpTimeToSystemTime(wstr ptr) @ stdcall WinHttpWriteData(ptr ptr long ptr) diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h index c13a63a036b..549d9cd2a04 100644 --- a/dlls/winhttp/winhttp_private.h +++ b/dlls/winhttp/winhttp_private.h @@ -90,8 +90,7 @@ typedef struct { LPWSTR field; LPWSTR value; - WORD flags; - WORD count; + BOOL is_request; /* part of request headers? */ } header_t; typedef struct @@ -116,6 +115,7 @@ void release_object( object_header_t * ); HINTERNET alloc_handle( object_header_t * ); BOOL free_handle( HINTERNET ); +void set_last_error( DWORD ); void send_callback( object_header_t *, DWORD, LPVOID, DWORD ); static inline void *heap_alloc( SIZE_T size ) @@ -128,6 +128,11 @@ static inline void *heap_alloc_zero( SIZE_T size ) return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ); } +static inline void *heap_realloc( LPVOID mem, SIZE_T size ) +{ + return HeapReAlloc( GetProcessHeap(), 0, mem, size ); +} + static inline void *heap_realloc_zero( LPVOID mem, SIZE_T size ) { return HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, mem, size ); diff --git a/include/Makefile.in b/include/Makefile.in index 882d89da625..115028b6e11 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -121,6 +121,7 @@ SRCDIR_INCLUDES = \ d3dhal.h \ d3drm.h \ d3drmdef.h \ + d3drmobj.h \ d3dtypes.h \ d3dvec.inl \ d3dx8.h \ diff --git a/include/config.h.in b/include/config.h.in index 1245197b54b..6ce0751831b 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -741,9 +741,18 @@ /* Define to 1 if `f_blocks' is member of `struct statvfs'. */ #undef HAVE_STRUCT_STATVFS_F_BLOCKS +/* Define to 1 if `st_atim' is member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_ATIM + /* Define to 1 if `st_blocks' is member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_BLOCKS +/* Define to 1 if `st_ctim' is member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_CTIM + +/* Define to 1 if `st_mtim' is member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_MTIM + /* Define to 1 if you have the header file. */ #undef HAVE_SYSCALL_H diff --git a/include/d3drmobj.h b/include/d3drmobj.h new file mode 100644 index 00000000000..ca32ec92d0d --- /dev/null +++ b/include/d3drmobj.h @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2008 Vijay Kiran Kamuju + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __D3DRMOBJ_H__ +#define __D3DRMOBJ_H__ + +#include +#define VIRTUAL +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************** + * Predeclare the interfaces + */ + +DEFINE_GUID(IID_IDirect3DRMObject, 0xeb16cb00, 0xd271, 0x11ce, 0xac, 0x48, 0x00, 0x00, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRMVisual, 0xeb16cb04, 0xd271, 0x11ce, 0xac, 0x48, 0x00, 0x00, 0xc0, 0x38, 0x25, 0xa1); + +typedef struct IDirect3DRMObject *LPDIRECT3DRMOBJECT, **LPLPDIRECT3DRMOBJECT; +typedef struct IDirect3DRMVisual *LPDIRECT3DRMVISUAL, **LPLPDIRECT3DRMVISUAL; + +/* ******************************************************************** + Types and structures + ******************************************************************** */ + +typedef void (__cdecl *D3DRMOBJECTCALLBACK)(LPDIRECT3DRMOBJECT obj, LPVOID arg); + +typedef struct _D3DRMPICKDESC +{ + ULONG ulFaceIdx; + LONG lGroupIdx; + D3DVECTOR vPosition; +} D3DRMPICKDESC, *LPD3DRMPICKDESC; + +typedef struct _D3DRMPICKDESC2 +{ + ULONG ulFaceIdx; + LONG lGroupIdx; + D3DVECTOR vPosition; + D3DVALUE tu; + D3DVALUE tv; + D3DVECTOR dvNormal; + D3DCOLOR dcColor; +} D3DRMPICKDESC2, *LPD3DRMPICKDESC2; + +/***************************************************************************** + * IDirect3DRMObject interface + */ +#define INTERFACE IDirect3DRMObject +DECLARE_INTERFACE_(IDirect3DRMObject,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirect3DRMObject methods ***/ + STDMETHOD(Clone)(THIS_ LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObj) PURE; + STDMETHOD(AddDestroyCallback)(THIS_ D3DRMOBJECTCALLBACK, LPVOID argument) PURE; + STDMETHOD(DeleteDestroyCallback)(THIS_ D3DRMOBJECTCALLBACK, LPVOID argument) PURE; + STDMETHOD(SetAppData)(THIS_ DWORD data) PURE; + STDMETHOD_(DWORD, GetAppData)(THIS) PURE; + STDMETHOD(SetName)(THIS_ LPCSTR) PURE; + STDMETHOD(GetName)(THIS_ LPDWORD lpdwSize, LPSTR lpName) PURE; + STDMETHOD(GetClassName)(THIS_ LPDWORD lpdwSize, LPSTR lpName) PURE; +}; +#undef INTERFACE + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirect3DRMObject_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirect3DRMObject_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirect3DRMObject_Release(p) (p)->lpVtbl->Release(p) +/*** IDirect3DRMObject methods ***/ +#define IDirect3DRMObject_Clone(p,a,b,c) (p)->lpVtbl->Clone(p,a,b,c) +#define IDirect3DRMObject_AddDestroyCallback(p,a,b) (p)->lpVtbl->AddDestroyCallback(p,a,b) +#define IDirect3DRMObject_DeleteDestroyCallback(p,a,b) (p)->lpVtbl->DeleteDestroyCallback(p,a,b) +#define IDirect3DRMObject_SetAppData(p,a) (p)->lpVtbl->SetAppData(p,a) +#define IDirect3DRMObject_GetAppData(p) (p)->lpVtbl->GetAppData(p) +#define IDirect3DRMObject_SetName(p,a) (p)->lpVtbl->SetName(p,a) +#define IDirect3DRMObject_GetName(p,a,b) (p)->lpVtbl->GetName(p,a,b) +#define IDirect3DRMObject_GetClassName(p,a,b) (p)->lpVtbl->GetClassName(p,a,b) +#else +/*** IUnknown methods ***/ +#define IDirect3DRMObject_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirect3DRMObject_AddRef(p) (p)->AddRef() +#define IDirect3DRMObject_Release(p) (p)->Release() +/*** IDirect3DRMObject methods ***/ +#define IDirect3DRMObject_Clone(p,a,b,c) (p)->Clone(a,b,c) +#define IDirect3DRMObject_AddDestroyCallback(p,a,b) (p)->AddDestroyCallback(a,b) +#define IDirect3DRMObject_DeleteDestroyCallback(p,a,b) (p)->DeleteDestroyCallback(a,b) +#define IDirect3DRMObject_SetAppData(p,a) (p)->SetAppData(a) +#define IDirect3DRMObject_GetAppData(p) (p)->GetAppData() +#define IDirect3DRMObject_SetName(p,a) (p)->SetName(a) +#define IDirect3DRMObject_GetName(p,a,b) (p)->GetName(a,b) +#define IDirect3DRMObject_GetClassName(p,a,b) (p)->GetClassName(a,b) +#endif + +/***************************************************************************** + * IDirect3DRMVisual interface + */ +#define INTERFACE IDirect3DRMVisual +DECLARE_INTERFACE_(IDirect3DRMVisual,IDirect3DRMObject) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirect3DRMObject methods ***/ + STDMETHOD(Clone)(THIS_ LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObj) PURE; + STDMETHOD(AddDestroyCallback)(THIS_ D3DRMOBJECTCALLBACK, LPVOID argument) PURE; + STDMETHOD(DeleteDestroyCallback)(THIS_ D3DRMOBJECTCALLBACK, LPVOID argument) PURE; + STDMETHOD(SetAppData)(THIS_ DWORD data) PURE; + STDMETHOD_(DWORD, GetAppData)(THIS) PURE; + STDMETHOD(SetName)(THIS_ LPCSTR) PURE; + STDMETHOD(GetName)(THIS_ LPDWORD lpdwSize, LPSTR lpName) PURE; + STDMETHOD(GetClassName)(THIS_ LPDWORD lpdwSize, LPSTR lpName) PURE; +}; +#undef INTERFACE + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDirect3DRMVisual_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirect3DRMVisual_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirect3DRMVisual_Release(p) (p)->lpVtbl->Release(p) +/*** IDirect3DRMObject methods ***/ +#define IDirect3DRMVisual_Clone(p,a,b,c) (p)->lpVtbl->Clone(p,a,b,c) +#define IDirect3DRMVisual_AddDestroyCallback(p,a,b) (p)->lpVtbl->AddDestroyCallback(p,a,b) +#define IDirect3DRMVisual_DeleteDestroyCallback(p,a,b) (p)->lpVtbl->DeleteDestroyCallback(p,a,b) +#define IDirect3DRMVisual_SetAppData(p,a) (p)->lpVtbl->SetAppData(p,a) +#define IDirect3DRMVisual_GetAppData(p) (p)->lpVtbl->GetAppData(p) +#define IDirect3DRMVisual_SetName(p,a) (p)->lpVtbl->SetName(p,a) +#define IDirect3DRMVisual_GetName(p,a,b) (p)->lpVtbl->GetName(p,a,b) +#define IDirect3DRMVisual_GetClassName(p,a,b) (p)->lpVtbl->GetClassName(p,a,b) +#else +/*** IUnknown methods ***/ +#define IDirect3DRMVisual_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirect3DRMVisual_AddRef(p) (p)->AddRef() +#define IDirect3DRMVisual_Release(p) (p)->Release() +/*** IDirect3DRMObject methods ***/ +#define IDirect3DRMVisual_Clone(p,a,b,c) (p)->Clone(a,b,c) +#define IDirect3DRMVisual_AddDestroyCallback(p,a,b) (p)->AddDestroyCallback(a,b) +#define IDirect3DRMVisual_DeleteDestroyCallback(p,a,b) (p)->DeleteDestroyCallback(a,b) +#define IDirect3DRMVisual_SetAppData(p,a) (p)->SetAppData(a) +#define IDirect3DRMVisual_GetAppData(p) (p)->GetAppData() +#define IDirect3DRMVisual_SetName(p,a) (p)->SetName(a) +#define IDirect3DRMVisual_GetName(p,a,b) (p)->GetName(a,b) +#define IDirect3DRMVisual_GetClassName(p,a,b) (p)->GetClassName(a,b) +#endif + +#ifdef __cplusplus +}; +#endif + +#endif /* __D3DRMOBJ_H__ */ diff --git a/include/d3dx8mesh.h b/include/d3dx8mesh.h index d063f6d67af..0d399ea529e 100644 --- a/include/d3dx8mesh.h +++ b/include/d3dx8mesh.h @@ -28,6 +28,7 @@ extern "C" { HRESULT WINAPI D3DXCreateBuffer(DWORD,LPD3DXBUFFER*); UINT WINAPI D3DXGetFVFVertexSize(DWORD); +BOOL WINAPI D3DXBoxBoundProbe(CONST D3DXVECTOR3 *, CONST D3DXVECTOR3 *, CONST D3DXVECTOR3 *, CONST D3DXVECTOR3 *); BOOL WINAPI D3DXSphereBoundProbe(CONST D3DXVECTOR3 *,FLOAT,CONST D3DXVECTOR3 *,CONST D3DXVECTOR3 *); #ifdef __cplusplus diff --git a/include/mstask.idl b/include/mstask.idl index cac9e0813af..cc70cce5eec 100644 --- a/include/mstask.idl +++ b/include/mstask.idl @@ -22,6 +22,37 @@ import "oaidl.idl"; import "oleidl.idl"; +cpp_quote("#define TASK_SUNDAY 0x1") +cpp_quote("#define TASK_MONDAY 0x2") +cpp_quote("#define TASK_TUESDAY 0x4") +cpp_quote("#define TASK_WEDNESDAY 0x8") +cpp_quote("#define TASK_THURSDAY 0x10") +cpp_quote("#define TASK_FRIDAY 0x20") +cpp_quote("#define TASK_SATURDAY 0x40") + +cpp_quote("#define TASK_FIRST_WEEK 1") +cpp_quote("#define TASK_SECOND_WEEK 2") +cpp_quote("#define TASK_THIRD_WEEK 3") +cpp_quote("#define TASK_FOURTH_WEEK 4") +cpp_quote("#define TASK_LAST_WEEK 5") + +cpp_quote("#define TASK_JANUARY 0x1") +cpp_quote("#define TASK_FEBRUARY 0x2") +cpp_quote("#define TASK_MARCH 0x4") +cpp_quote("#define TASK_APRIL 0x8") +cpp_quote("#define TASK_MAY 0x10") +cpp_quote("#define TASK_JUNE 0x20") +cpp_quote("#define TASK_JULY 0x40") +cpp_quote("#define TASK_AUGUST 0x80") +cpp_quote("#define TASK_SEPTEMBER 0x100") +cpp_quote("#define TASK_OCTOBER 0x200") +cpp_quote("#define TASK_NOVEMBER 0x400") +cpp_quote("#define TASK_DECEMBER 0x800") + +cpp_quote("#define TASK_TRIGGER_FLAG_HAS_END_DATE 0x1") +cpp_quote("#define TASK_TRIGGER_FLAG_KILL_AT_DURATION_END 0x2") +cpp_quote("#define TASK_TRIGGER_FLAG_DISABLED 0x4") + [ local, object, diff --git a/include/wincrypt.h b/include/wincrypt.h index 5d8b2034d86..0f0cec6e198 100644 --- a/include/wincrypt.h +++ b/include/wincrypt.h @@ -675,7 +675,7 @@ typedef struct _CRYPT_SMIME_CAPABILITY { typedef struct _CRYPT_SMIME_CAPABILITIES { DWORD cCapability; - CRYPT_SMIME_CAPABILITY rgCapability; + PCRYPT_SMIME_CAPABILITY rgCapability; } CRYPT_SMIME_CAPABILITIES, *PCRYPT_SMIME_CAPABILITIES; typedef struct _VTableProvStruc { @@ -3629,6 +3629,18 @@ typedef struct _CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA { #define CMSG_SIGNER_CERT_ID_PARAM 38 #define CMSG_CMS_SIGNER_INFO_PARAM 39 +typedef struct _CMSG_CMS_SIGNER_INFO { + DWORD dwVersion; + CERT_ID SignerId; + CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm; + CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm; + CRYPT_DATA_BLOB EncryptedHash; + CRYPT_ATTRIBUTES AuthAttrs; + CRYPT_ATTRIBUTES UnauthAttrs; +} CMSG_CMS_SIGNER_INFO, *PCMSG_CMS_SIGNER_INFO; + +typedef CRYPT_ATTRIBUTES CMSG_ATTR, *PCMSG_ATTR; + #define CMSG_SIGNED_DATA_V1 1 #define CMSG_SIGNED_DATA_V3 3 #define CMSG_SIGNED_DATA_PKCS_1_5_VERSION CMSG_SIGNED_DATA_V1 @@ -3649,6 +3661,61 @@ typedef struct _CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA { #define CMSG_ENVELOPED_DATA_PKCS_1_5_VERSION CMSG_ENVELOPED_DATA_V0 #define CMSG_ENVELOPED_DATA_CMS_VERSION CMSG_ENVELOPED_DATA_V2 +typedef struct _CMSG_KEY_TRANS_RECIPIENT_INFO { + DWORD dwVersion; + CERT_ID RecipientId; + CRYPT_ALGORITHM_IDENTIFIER KeyEncryptionAlgorithm; + CRYPT_DATA_BLOB EncryptedKey; +} CMSG_KEY_TRANS_RECIPIENT_INFO, *PCMSG_KEY_TRANS_RECIPIENT_INFO; + +typedef struct _CMSG_RECIPIENT_ENCRYPTED_KEY_INFO { + CERT_ID RecipientId; + CRYPT_DATA_BLOB EncryptedKey; + PCRYPT_ATTRIBUTE_TYPE_VALUE pOtherAttr; +} CMSG_RECIPIENT_ENCRYPTED_KEY_INFO, *PCMSG_RECIPIENT_ENCRYPTED_KEY_INFO; + +typedef struct _CMSG_KEY_AGREE_RECIPIENT_INFO { + DWORD dwVersion; + DWORD dwOriginatorChoice; + union { + CERT_ID OriginatorCertId; + CERT_PUBLIC_KEY_INFO OriginatorPublicKeyInfo; + } DUMMYUNIONNAME; + CRYPT_ALGORITHM_IDENTIFIER UserKeyingMaterial; + DWORD cRecipientEncryptedKeys; + PCMSG_RECIPIENT_ENCRYPTED_KEY_INFO *rgpRecipientEncryptedKeys; +} CMSG_KEY_AGREE_RECIPIENT_INFO, *PCMSG_KEY_AGREE_RECIPIENT_INFO; + +#define CMSG_KEY_AGREE_ORIGINATOR_CERT 1 +#define CMSG_KEY_AGREE_ORIGINATOR_PUBLIC_KEY 2 + +typedef struct _CMSG_MAIL_LIST_RECIPIENT_INFO { + DWORD dwVersion; + CRYPT_DATA_BLOB KeyId; + CRYPT_ALGORITHM_IDENTIFIER KeyEncryptionAlgorithm; + CRYPT_DATA_BLOB EncryptedKey; + FILETIME Date; + PCRYPT_ATTRIBUTE_TYPE_VALUE pOtherAttr; +} CMSG_MAIL_LIST_RECIPIENT_INFO, *PCMSG_MAIL_LIST_RECIPIENT_INFO; + +typedef struct _CMSG_CMS_RECIPIENT_INFO { + DWORD dwRecipientChoice; + union { + PCMSG_KEY_TRANS_RECIPIENT_INFO pKeyTrans; + PCMSG_KEY_AGREE_RECIPIENT_INFO pKeyAgree; + PCMSG_MAIL_LIST_RECIPIENT_INFO pMailList; + } DUMMYUNIONNAME; +} CMSG_CMS_RECIPIENT_INFO, *PCMSG_CMS_RECIPIENT_INFO; + +#define CMSG_ENVELOPED_RECIPIENT_V0 0 +#define CMSG_ENVELOPED_RECIPIENT_V2 2 +#define CMSG_ENVELOPED_RECIPIENT_V3 3 +#define CMSG_ENVELOPED_RECIPIENT_V4 4 +#define CMSG_KEY_TRANS_PKCS_1_5_VERSION CMSG_ENVELOPED_RECIPIENT_V0 +#define CMSG_KEY_TRANS_CMS_VERSION CMSG_ENVELOPED_RECIPIENT_V2 +#define CMSG_KEY_AGREE_VERSION CMSG_ENVELOPED_RECIPIENT_V3 +#define CMSG_MAIL_LIST_VERSION CMSG_ENVELOPED_RECIPIENT_V4 + /* CryptMsgGetAndVerifySigner flags */ #define CMSG_TRUSTED_SIGNER_FLAG 0x1 #define CMSG_SIGNER_ONLY_FLAG 0x2 diff --git a/include/winerror.h b/include/winerror.h index 9cf495e832e..5d32374e2c8 100644 --- a/include/winerror.h +++ b/include/winerror.h @@ -2020,6 +2020,49 @@ static inline HRESULT HRESULT_FROM_WIN32(unsigned long x) #define CO_E_DECODEFAILED _HRESULT_TYPEDEF_(0x8004021AL) #define CO_E_ACNOTINITIALIZED _HRESULT_TYPEDEF_(0x8004021BL) +/* Task Scheduler Service Error Codes */ +#define SCHED_S_TASK_READY _HRESULT_TYPEDEF_(0x00041300L) +#define SCHED_S_TASK_RUNNING _HRESULT_TYPEDEF_(0x00041301L) +#define SCHED_S_TASK_DISABLED _HRESULT_TYPEDEF_(0x00041302L) +#define SCHED_S_TASK_HAS_NOT_RUN _HRESULT_TYPEDEF_(0x00041303L) +#define SCHED_S_TASK_NO_MORE_RUNS _HRESULT_TYPEDEF_(0x00041304L) +#define SCHED_S_TASK_NOT_SCHEDULED _HRESULT_TYPEDEF_(0x00041305L) +#define SCHED_S_TASK_TERMINATED _HRESULT_TYPEDEF_(0x00041306L) +#define SCHED_S_TASK_NO_VALID_TRIGGERS _HRESULT_TYPEDEF_(0x00041307L) +#define SCHED_S_EVENT_TRIGGER _HRESULT_TYPEDEF_(0x00041308L) +#define SCHED_E_TRIGGER_NOT_FOUND _HRESULT_TYPEDEF_(0x80041309L) +#define SCHED_E_TASK_NOT_READY _HRESULT_TYPEDEF_(0x8004130AL) +#define SCHED_E_TASK_NOT_RUNNING _HRESULT_TYPEDEF_(0x8004130BL) +#define SCHED_E_SERVICE_NOT_INSTALLED _HRESULT_TYPEDEF_(0x8004130CL) +#define SCHED_E_CANNOT_OPEN_TASK _HRESULT_TYPEDEF_(0x8004130DL) +#define SCHED_E_INVALID_TASK _HRESULT_TYPEDEF_(0x8004130EL) +#define SCHED_E_ACCOUNT_INFORMATION_NOT_SET _HRESULT_TYPEDEF_(0x8004130FL) +#define SCHED_E_ACCOUNT_NAME_NOT_FOUND _HRESULT_TYPEDEF_(0x80041310L) +#define SCHED_E_ACCOUNT_DBASE_CORRUPT _HRESULT_TYPEDEF_(0x80041311L) +#define SCHED_E_NO_SECURITY_SERVICES _HRESULT_TYPEDEF_(0x80041312L) +#define SCHED_E_UNKNOWN_OBJECT_VERSION _HRESULT_TYPEDEF_(0x80041313L) +#define SCHED_E_UNSUPPORTED_ACCOUNT_OPTION _HRESULT_TYPEDEF_(0x80041314L) +#define SCHED_E_SERVICE_NOT_RUNNING _HRESULT_TYPEDEF_(0x80041315L) +#define SCHED_E_UNEXPECTEDNODE _HRESULT_TYPEDEF_(0x80041316L) +#define SCHED_E_NAMESPACE _HRESULT_TYPEDEF_(0x80041317L) +#define SCHED_E_INVALIDVALUE _HRESULT_TYPEDEF_(0x80041318L) +#define SCHED_E_MISSINGNODE _HRESULT_TYPEDEF_(0x80041319L) +#define SCHED_E_MALFORMEDXML _HRESULT_TYPEDEF_(0x8004131AL) +#define SCHED_S_SOME_TRIGGERS_FAILED _HRESULT_TYPEDEF_(0x0004131BL) +#define SCHED_S_BATCH_LOGON_PROBLEM _HRESULT_TYPEDEF_(0x0004131CL) +#define SCHED_E_TOO_MANY_NODES _HRESULT_TYPEDEF_(0x8004131DL) +#define SCHED_E_PAST_END_BOUNDARY _HRESULT_TYPEDEF_(0x8004131EL) +#define SCHED_E_ALREADY_RUNNING _HRESULT_TYPEDEF_(0x8004131FL) +#define SCHED_E_USER_NOT_LOGGED_ON _HRESULT_TYPEDEF_(0x80041320L) +#define SCHED_E_INVALID_TASK_HASH _HRESULT_TYPEDEF_(0x80041321L) +#define SCHED_E_SERVICE_NOT_AVAILABLE _HRESULT_TYPEDEF_(0x80041322L) +#define SCHED_E_SERVICE_TOO_BUSY _HRESULT_TYPEDEF_(0x80041323L) +#define SCHED_E_TASK_ATTEMPTED _HRESULT_TYPEDEF_(0x80041324L) +#define SCHED_S_TASK_QUEUED _HRESULT_TYPEDEF_(0x00041325L) +#define SCHED_E_TASK_DISABLED _HRESULT_TYPEDEF_(0x80041326L) +#define SCHED_E_TASK_NOT_V1_COMPAT _HRESULT_TYPEDEF_(0x80041327L) +#define SCHED_E_START_ON_DEMAND _HRESULT_TYPEDEF_(0x80041328L) + #define E_ACCESSDENIED _HRESULT_TYPEDEF_(0x80070005L) #define E_HANDLE _HRESULT_TYPEDEF_(0x80070006L) #define E_OUTOFMEMORY _HRESULT_TYPEDEF_(0x8007000EL) diff --git a/programs/regedit/childwnd.c b/programs/regedit/childwnd.c index 23eca7fd1c8..42fefca5422 100644 --- a/programs/regedit/childwnd.c +++ b/programs/regedit/childwnd.c @@ -49,6 +49,28 @@ LPCTSTR GetRootKeyName(HKEY hRootKey) return _T("UNKNOWN HKEY, PLEASE REPORT"); } +LPCWSTR GetRootKeyNameW(HKEY hRootKey) +{ + if(hRootKey == HKEY_CLASSES_ROOT) + return reg_class_namesW[INDEX_HKEY_CLASSES_ROOT]; + if(hRootKey == HKEY_CURRENT_USER) + return reg_class_namesW[INDEX_HKEY_CURRENT_USER]; + if(hRootKey == HKEY_LOCAL_MACHINE) + return reg_class_namesW[INDEX_HKEY_LOCAL_MACHINE]; + if(hRootKey == HKEY_USERS) + return reg_class_namesW[INDEX_HKEY_USERS]; + if(hRootKey == HKEY_CURRENT_CONFIG) + return reg_class_namesW[INDEX_HKEY_CURRENT_CONFIG]; + if(hRootKey == HKEY_DYN_DATA) + return reg_class_namesW[INDEX_HKEY_DYN_DATA]; + else + { + static const WCHAR unknown_key[] = {'U','N','K','N','O','W','N',' ','H','K','E','Y',',',' ', + 'P','L','E','A','S','E',' ','R','E','P','O','R','T',0}; + return unknown_key; + } +} + static void draw_splitbar(HWND hWnd, int x) { RECT rt; @@ -109,6 +131,31 @@ static LPTSTR CombinePaths(LPCTSTR pPaths[], int nPaths) { return combined; } +static LPWSTR CombinePathsW(LPCWSTR pPaths[], int nPaths) { + int i, len, pos; + LPWSTR combined; + for (i=0, len=0; ihTreeWnd) { + WCHAR* keyPathW = GetWideString(keyPath); if (keyPath == 0 || *keyPath == 0) { MessageBeep(MB_ICONHAND); - } else if (DeleteKey(hWnd, hKeyRoot, keyPath)) { + } else if (DeleteKey(hWnd, hKeyRoot, keyPathW)) { DeleteNode(g_pChildWnd->hTreeWnd, 0); } + HeapFree(GetProcessHeap(), 0, keyPathW); } else if (GetFocus() == g_pChildWnd->hListWnd) { curIndex = ListView_GetNextItem(g_pChildWnd->hListWnd, -1, LVNI_SELECTED); while(curIndex != -1) { + WCHAR* valueNameW; + WCHAR* keyPathW; + valueName = GetItemText(g_pChildWnd->hListWnd, curIndex); curIndex = ListView_GetNextItem(g_pChildWnd->hListWnd, curIndex, LVNI_SELECTED); if(curIndex != -1 && firstItem) { - TCHAR title[256]; - TCHAR text[1024]; - if(!LoadString(hInst, IDS_DELETE_BOX_TITLE, title, COUNT_OF(title))) - lstrcpy(title, "Error"); - if(!LoadString(hInst, IDS_DELETE_BOX_TEXT_MULTIPLE, text, COUNT_OF(text))) - lstrcpy(text, "Unknown error string!"); - if (MessageBox(hWnd, text, title, MB_YESNO | MB_ICONEXCLAMATION) != IDYES) + if (MessageBoxW(hWnd, MAKEINTRESOURCEW(IDS_DELETE_BOX_TEXT_MULTIPLE), + MAKEINTRESOURCEW(IDS_DELETE_BOX_TITLE), + MB_YESNO | MB_ICONEXCLAMATION) != IDYES) break; } - if (!DeleteValue(hWnd, hKeyRoot, keyPath, valueName, curIndex==-1 && firstItem)) + valueNameW = GetWideString(valueName); + keyPathW = GetWideString(keyPath); + if (!DeleteValue(hWnd, hKeyRoot, keyPathW, valueNameW, curIndex==-1 && firstItem)) + { + HeapFree(GetProcessHeap(), 0, valueNameW); + HeapFree(GetProcessHeap(), 0, keyPathW); break; + } firstItem = FALSE; + HeapFree(GetProcessHeap(), 0, valueNameW); + HeapFree(GetProcessHeap(), 0, keyPathW); } RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, NULL); } @@ -741,7 +753,7 @@ static BOOL _CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } case ID_EDIT_COPYKEYNAME: { - LPTSTR fullPath = GetItemFullPath(g_pChildWnd->hTreeWnd, NULL, FALSE); + LPWSTR fullPath = GetItemFullPathW(g_pChildWnd->hTreeWnd, NULL, FALSE); if (fullPath) { CopyKeyName(hWnd, fullPath); HeapFree(GetProcessHeap(), 0, fullPath); @@ -833,8 +845,11 @@ static BOOL _CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) toggle_child(hWnd, LOWORD(wParam), hStatusBar); break; case ID_HELP_HELPTOPICS: - WinHelp(hWnd, _T("regedit"), HELP_FINDER, 0); + { + const WCHAR help_regedit[] = {'r','e','g','e','d','i','t',0}; + WinHelpW(hWnd, help_regedit, HELP_FINDER, 0); break; + } case ID_HELP_ABOUT: ShowAboutBox(hWnd); break; @@ -905,8 +920,11 @@ LRESULT CALLBACK FrameWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPa OnMenuSelect(hWnd, LOWORD(wParam), HIWORD(wParam), (HMENU)lParam); break; case WM_DESTROY: - WinHelp(hWnd, _T("regedit"), HELP_QUIT, 0); + { + const WCHAR help_regedit[] = {'r','e','g','e','d','i','t',0}; + WinHelpW(hWnd, help_regedit, HELP_QUIT, 0); PostQuitMessage(0); + } default: return DefWindowProc(hWnd, message, wParam, lParam); } diff --git a/programs/regedit/main.c b/programs/regedit/main.c index 2b95287f92b..5661b263412 100644 --- a/programs/regedit/main.c +++ b/programs/regedit/main.c @@ -30,9 +30,21 @@ #include "main.h" TCHAR g_pszDefaultValueName[64]; +WCHAR g_pszDefaultValueNameW[64]; BOOL ProcessCmdLine(LPSTR lpCmdLine); +static const WCHAR hkey_local_machine[] = {'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',0}; +static const WCHAR hkey_users[] = {'H','K','E','Y','_','U','S','E','R','S',0}; +static const WCHAR hkey_classes_root[] = {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T',0}; +static const WCHAR hkey_current_config[] = {'H','K','E','Y','_','C','U','R','R','E','N','T','_','C','O','N','F','I','G',0}; +static const WCHAR hkey_current_user[] = {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R',0}; +static const WCHAR hkey_dyn_data[] = {'H','K','E','Y','_','D','Y','N','_','D','A','T','A',0}; + +const WCHAR *reg_class_namesW[] = {hkey_local_machine, hkey_users, + hkey_classes_root, hkey_current_config, + hkey_current_user, hkey_dyn_data + }; /******************************************************************************* * Global Variables: @@ -171,6 +183,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, /* Initialize global strings */ LoadString(hInstance, IDS_APP_TITLE, szTitle, COUNT_OF(szTitle)); LoadString(hInstance, IDS_REGISTRY_DEFAULT_VALUE, g_pszDefaultValueName, COUNT_OF(g_pszDefaultValueName)); + LoadStringW(hInstance, IDS_REGISTRY_DEFAULT_VALUE, g_pszDefaultValueNameW, COUNT_OF(g_pszDefaultValueNameW)); /* Store instance handle in our global variable */ hInst = hInstance; diff --git a/programs/regedit/main.h b/programs/regedit/main.h index 7547ea0a8eb..6b5a098e203 100644 --- a/programs/regedit/main.h +++ b/programs/regedit/main.h @@ -91,6 +91,18 @@ extern TCHAR szTitle[]; extern const TCHAR szFrameClass[]; extern const TCHAR szChildClass[]; extern TCHAR g_pszDefaultValueName[]; +extern WCHAR g_pszDefaultValueNameW[]; + +/* Registry class names and their indexes */ +extern const WCHAR* reg_class_namesW[]; +#define INDEX_HKEY_LOCAL_MACHINE 0 +#define INDEX_HKEY_USERS 1 +#define INDEX_HKEY_CLASSES_ROOT 2 +#define INDEX_HKEY_CURRENT_CONFIG 3 +#define INDEX_HKEY_CURRENT_USER 4 +#define INDEX_HKEY_DYN_DATA 5 + + /* about.c */ extern void ShowAboutBox(HWND hWnd); @@ -98,6 +110,7 @@ extern void ShowAboutBox(HWND hWnd); /* childwnd.c */ extern LPCTSTR GetRootKeyName(HKEY hRootKey); extern LPTSTR GetItemFullPath(HWND hwndTV, HTREEITEM hItem, BOOL bFull); +extern LPWSTR GetItemFullPathW(HWND hwndTV, HTREEITEM hItem, BOOL bFull); extern LRESULT CALLBACK ChildWndProc(HWND, UINT, WPARAM, LPARAM); /* framewnd.c */ @@ -119,6 +132,7 @@ extern HWND CreateTreeView(HWND hwndParent, LPTSTR pHostName, UINT id); extern BOOL RefreshTreeView(HWND hWndTV); extern BOOL OnTreeExpanding(HWND hWnd, NMTREEVIEW* pnmtv); extern LPTSTR GetItemPath(HWND hwndTV, HTREEITEM hItem, HKEY* phRootKey); +extern LPWSTR GetItemPathW(HWND hwndTV, HTREEITEM hItem, HKEY* phRootKey); extern BOOL DeleteNode(HWND hwndTV, HTREEITEM hItem); extern HTREEITEM InsertNode(HWND hwndTV, HTREEITEM hItem, LPTSTR name); extern HWND StartKeyRename(HWND hwndTV); @@ -129,8 +143,8 @@ extern HTREEITEM FindNext(HWND hwndTV, HTREEITEM hItem, LPCTSTR sstring, int mod extern BOOL CreateKey(HWND hwnd, HKEY hKeyRoot, LPCTSTR keyPath, LPTSTR newKeyName); extern BOOL CreateValue(HWND hwnd, HKEY hKeyRoot, LPCTSTR keyPath, DWORD valueType, LPTSTR valueName); extern BOOL ModifyValue(HWND hwnd, HKEY hKeyRoot, LPCTSTR keyPath, LPCTSTR valueName); -extern BOOL DeleteKey(HWND hwnd, HKEY hKeyRoot, LPCTSTR keyPath); -extern BOOL DeleteValue(HWND hwnd, HKEY hKeyRoot, LPCTSTR keyPath, LPCTSTR valueName, BOOL showMessageBox); +extern BOOL DeleteKey(HWND hwnd, HKEY hKeyRoot, LPCWSTR keyPath); +extern BOOL DeleteValue(HWND hwnd, HKEY hKeyRoot, LPCWSTR keyPath, LPCWSTR valueName, BOOL showMessageBox); extern BOOL RenameValue(HWND hwnd, HKEY hRootKey, LPCTSTR keyPath, LPCTSTR oldName, LPCTSTR newName); extern BOOL RenameKey(HWND hwnd, HKEY hRootKey, LPCTSTR keyPath, LPCTSTR newName); extern void error(HWND hwnd, INT resId, ...); diff --git a/programs/regedit/regproc.c b/programs/regedit/regproc.c index 13bfc17c90c..8f05a2d6e45 100644 --- a/programs/regedit/regproc.c +++ b/programs/regedit/regproc.c @@ -40,21 +40,10 @@ static const CHAR *reg_class_names[] = { "HKEY_CURRENT_CONFIG", "HKEY_CURRENT_USER", "HKEY_DYN_DATA" }; -static const WCHAR hkey_local_machine[] = {'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',0}; -static const WCHAR hkey_users[] = {'H','K','E','Y','_','U','S','E','R','S',0}; -static const WCHAR hkey_classes_root[] = {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T',0}; -static const WCHAR hkey_current_config[] = {'H','K','E','Y','_','C','U','R','R','E','N','T','_','C','O','N','F','I','G',0}; -static const WCHAR hkey_current_user[] = {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R',0}; -static const WCHAR hkey_dyn_data[] = {'H','K','E','Y','_','D','Y','N','_','D','A','T','A',0}; - -static const WCHAR *reg_class_namesW[] = {hkey_local_machine, hkey_users, - hkey_classes_root, hkey_current_config, - hkey_current_user, hkey_dyn_data - }; - - #define REG_CLASS_NUMBER (sizeof(reg_class_names) / sizeof(reg_class_names[0])) +extern const WCHAR* reg_class_namesW[]; + static HKEY reg_class_keys[REG_CLASS_NUMBER] = { HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT, HKEY_CURRENT_CONFIG, HKEY_CURRENT_USER, HKEY_DYN_DATA diff --git a/programs/regedit/regproc.h b/programs/regedit/regproc.h index 0621d8b62e8..7122379307a 100644 --- a/programs/regedit/regproc.h +++ b/programs/regedit/regproc.h @@ -25,3 +25,4 @@ BOOL export_registry_key(CHAR *file_name, CHAR *reg_key_name); BOOL import_registry_file(FILE *in); void delete_registry_key(WCHAR *reg_key_name); WCHAR* GetWideString(const char* strA); +CHAR* GetMultiByteString(const WCHAR* strW); diff --git a/programs/regedit/treeview.c b/programs/regedit/treeview.c index bfce4aa5bcf..3261a66517c 100644 --- a/programs/regedit/treeview.c +++ b/programs/regedit/treeview.c @@ -91,6 +91,48 @@ static BOOL get_item_path(HWND hwndTV, HTREEITEM hItem, HKEY* phKey, LPTSTR* pKe return TRUE; } +static BOOL get_item_pathW(HWND hwndTV, HTREEITEM hItem, HKEY* phKey, LPWSTR* pKeyPath, int* pPathLen, int* pMaxChars) +{ + TVITEMW item; + int maxChars, chars; + LPWSTR newStr; + + item.mask = TVIF_PARAM; + item.hItem = hItem; + if (!TreeView_GetItem(hwndTV, &item)) return FALSE; + + if (item.lParam) { + /* found root key with valid key value */ + *phKey = (HKEY)item.lParam; + return TRUE; + } + + if(!get_item_pathW(hwndTV, TreeView_GetParent(hwndTV, hItem), phKey, pKeyPath, pPathLen, pMaxChars)) return FALSE; + if (*pPathLen) { + (*pKeyPath)[*pPathLen] = '\\'; + ++(*pPathLen); + } + + do { + item.mask = TVIF_TEXT; + item.hItem = hItem; + item.pszText = *pKeyPath + *pPathLen; + item.cchTextMax = maxChars = *pMaxChars - *pPathLen; + if (!TreeView_GetItemW(hwndTV, &item)) return FALSE; + chars = lstrlenW(item.pszText); + if (chars < maxChars - 1) { + *pPathLen += chars; + break; + } + newStr = HeapReAlloc(GetProcessHeap(), 0, *pKeyPath, *pMaxChars * 2); + if (!newStr) return FALSE; + *pKeyPath = newStr; + *pMaxChars *= 2; + } while(TRUE); + + return TRUE; +} + LPTSTR GetItemPath(HWND hwndTV, HTREEITEM hItem, HKEY* phRootKey) { int pathLen = 0, maxLen; @@ -107,6 +149,23 @@ LPTSTR GetItemPath(HWND hwndTV, HTREEITEM hItem, HKEY* phRootKey) return pathBuffer; } +LPWSTR GetItemPathW(HWND hwndTV, HTREEITEM hItem, HKEY* phRootKey) +{ + int pathLen = 0, maxLen; + WCHAR *pathBuffer; + + pathBuffer = HeapAlloc(GetProcessHeap(), 0, 1024*sizeof(WCHAR)); + if (!pathBuffer) return NULL; + *pathBuffer = 0; + maxLen = HeapSize(GetProcessHeap(), 0, pathBuffer); + if (maxLen == (SIZE_T) - 1) return NULL; + maxLen = maxLen / sizeof(WCHAR); + if (!hItem) hItem = TreeView_GetSelection(hwndTV); + if (!hItem) return NULL; + if (!get_item_pathW(hwndTV, hItem, phRootKey, &pathBuffer, &pathLen, &maxLen)) return NULL; + return pathBuffer; +} + static LPTSTR get_path_component(LPCTSTR *lplpKeyName) { LPCTSTR lpPos = *lplpKeyName; LPTSTR lpResult = NULL; diff --git a/programs/uninstaller/Bg.rc b/programs/uninstaller/Bg.rc index 957f4407f7b..45705148187 100644 --- a/programs/uninstaller/Bg.rc +++ b/programs/uninstaller/Bg.rc @@ -20,25 +20,7 @@ LANGUAGE LANG_BULGARIAN, SUBLANG_DEFAULT -IDD_UNINSTALLER DIALOG DISCARDABLE 0, 0, 330, 160 -STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU -CAPTION "Äåèíñòàëàòîð íà ïðèëîæåíèÿ íà Wine" -FONT 10, "MS Sans Serif" -BEGIN - LTEXT "Èçáåðåòå, êîå ïðèëîæåíèå æåëàåòå äà äà äåèíñòàëèðàòå:",IDC_PLEASESELECT,10,10,250,14 - EDITTEXT IDC_FILTER,10,25,250,14,ES_AUTOHSCROLL - LISTBOX IDC_LIST,10,43,250,106,LBS_NOINTEGRALHEIGHT | - LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "&Äåèíñòàëèðàé",IDC_UNINSTALL,270,48,50,14 - PUSHBUTTON "&Îòíîñíî",IDC_ABOUT,270,65,50,14 - PUSHBUTTON "&Èçõîä",IDC_EXIT,270,81,50,14 -END - - STRINGTABLE DISCARDABLE { IDS_APPNAME, "Wine Application Uninstaller" - IDS_ABOUT, "Wine Application Uninstaller (C) 2005 by Andreas Mohr, Hannu Valtonen and Jonathan Ernst." - IDS_ABOUTTITLE, "Îòíîñíî äåèíñòàëàòîðà" - IDS_REGISTRYKEYNOTAVAILABLE, "Êëþ÷îâåòå çà äåèíñòàëèðàíå ëèïñâàò (âñå îùå) â ñèñòåìíèÿ ðåãèñòúð, íÿìà êàêâî äà ïðàâÿ!" IDS_UNINSTALLFAILED, "Èçïúëíåíèåòî íà êîìàíäàòà çà äåèíñòàëèðàíå '%s' íåóñïåøíî, ìîæå áè çàðàäè ëèïñâàù èçïúëíèì ôàéë.\r\nÈñêàòå ëè äà ïðåìàõíåòå çàïèñà çà äåèíñòàëèðàíå îò ñèñòåìíèÿ ðåãèñòúð?" } diff --git a/programs/uninstaller/Da.rc b/programs/uninstaller/Da.rc index d6f6bb69ae4..1c928d72240 100644 --- a/programs/uninstaller/Da.rc +++ b/programs/uninstaller/Da.rc @@ -20,25 +20,7 @@ LANGUAGE LANG_DANISH, SUBLANG_DEFAULT -IDD_UNINSTALLER DIALOG DISCARDABLE 0, 0, 330, 160 -STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU -CAPTION "Afinstaller programmer" -FONT 10, "MS Sans Serif" -BEGIN - LTEXT "Vælg det program du ønsker at afinstallere:",IDC_PLEASESELECT,10,10,250,14 - EDITTEXT IDC_FILTER,10,25,250,14,ES_AUTOHSCROLL - LISTBOX IDC_LIST,10,43,250,106,LBS_NOINTEGRALHEIGHT | - LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "A&finstaller",IDC_UNINSTALL,270,48,50,14 - PUSHBUTTON "&Om",IDC_ABOUT,270,65,50,14 - PUSHBUTTON "&Luk",IDC_EXIT,270,81,50,14 -END - - STRINGTABLE DISCARDABLE { IDS_APPNAME, "Afinstaller programmer" - IDS_ABOUT, "Oversat af Jens Albretsen\nOphavsret 2005 for afinstalleringsværktøjet tilhører Andreas Mohr, Hannu Valtonen og Jonathan Ernst." - IDS_ABOUTTITLE, "Om" - IDS_REGISTRYKEYNOTAVAILABLE, "Afinstaller registeringsdatabase værdi er ikke tilgængelig (endnu); ingenting at gøre." IDS_UNINSTALLFAILED, "Køring af afinstallerings kommandoen '%s' fejlede, måske er det på grund af en manglende programfil.\r\nVil du fjerne afinstallerings opførselen fra registeringsdatabasen?" } diff --git a/programs/uninstaller/De.rc b/programs/uninstaller/De.rc index 83b17f221c0..a01bd7a8d65 100644 --- a/programs/uninstaller/De.rc +++ b/programs/uninstaller/De.rc @@ -20,24 +20,7 @@ LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL -IDD_UNINSTALLER DIALOG DISCARDABLE 0, 0, 330, 160 -STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU -CAPTION "Wine Anwendungsentferner" -FONT 10, "MS Sans Serif" -BEGIN - LTEXT "Bitte wählen Sie die Anwendung aus, die Sie entfernen möchten:",IDC_PLEASESELECT,10,10,250,14 - EDITTEXT IDC_FILTER,10,25,250,14,ES_AUTOHSCROLL - LISTBOX IDC_LIST,10,43,250,106,LBS_NOINTEGRALHEIGHT | - LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "&Entfernen",IDC_UNINSTALL,270,48,50,14 - PUSHBUTTON "Ü&ber",IDC_ABOUT,270,65,50,14 - PUSHBUTTON "E&nde",IDC_EXIT,270,81,50,14 -END - STRINGTABLE DISCARDABLE { IDS_APPNAME, "Wine Anwendungsentferner" - IDS_ABOUT, "Wine Anwendungsentferner (C) 2005 durch Andreas Mohr, Hannu Valtonen und Jonathan Ernst." - IDS_ABOUTTITLE, "Über den Anwendungsentferner" - IDS_REGISTRYKEYNOTAVAILABLE, "Der Registry-Schlüssel für zu entfernende Anwendung(en) ist (noch) nicht verfügbar, es kann nichts gemacht werden." IDS_UNINSTALLFAILED, "Die Ausführung des Entfernungsbefehls '%s' ist fehlgeschlagen, wahrscheinlich durch eine fehlende, ausführbare Datei.\r\nMöchten Sie, dass der Anwendungseintrag aus der Registry entfernt wird?" } diff --git a/programs/uninstaller/En.rc b/programs/uninstaller/En.rc index 6d24fbb4580..f6ce7b2aa0b 100644 --- a/programs/uninstaller/En.rc +++ b/programs/uninstaller/En.rc @@ -20,25 +20,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT -IDD_UNINSTALLER DIALOG DISCARDABLE 0, 0, 330, 160 -STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU -CAPTION "Wine Application Uninstaller" -FONT 10, "MS Sans Serif" -BEGIN - LTEXT "Please select the application you wish to uninstall:",IDC_PLEASESELECT,10,10,250,14 - EDITTEXT IDC_FILTER,10,25,250,14,ES_AUTOHSCROLL - LISTBOX IDC_LIST,10,43,250,106,LBS_NOINTEGRALHEIGHT | - LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "&Uninstall",IDC_UNINSTALL,270,48,50,14 - PUSHBUTTON "&About",IDC_ABOUT,270,65,50,14 - PUSHBUTTON "&Exit",IDC_EXIT,270,81,50,14 -END - - STRINGTABLE DISCARDABLE { IDS_APPNAME, "Wine Application Uninstaller" - IDS_ABOUT, "Wine Application Uninstaller (C) 2005 by Andreas Mohr, Hannu Valtonen and Jonathan Ernst." - IDS_ABOUTTITLE, "About Uninstaller" - IDS_REGISTRYKEYNOTAVAILABLE, "Uninstall registry key not available (yet), nothing to do !" IDS_UNINSTALLFAILED, "Execution of uninstall command '%s' failed, perhaps due to missing executable.\r\nDo you want to remove the uninstall entry from the registry ?" } diff --git a/programs/uninstaller/Eo.rc b/programs/uninstaller/Eo.rc index de48057962f..52153620c1f 100644 --- a/programs/uninstaller/Eo.rc +++ b/programs/uninstaller/Eo.rc @@ -20,25 +20,7 @@ LANGUAGE LANG_ESPERANTO, SUBLANG_NEUTRAL -IDD_UNINSTALLER DIALOG DISCARDABLE 0, 0, 330, 160 -STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU -CAPTION "Wine Programa Malinstalilo" -FONT 10, "MS Sans Serif" -BEGIN - LTEXT "Elektu la programon kion vi desiras forigi:",IDC_PLEASESELECT,10,10,250,14 - EDITTEXT IDC_FILTER,10,25,250,14,ES_AUTOHSCROLL - LISTBOX IDC_LIST,10,43,250,106,LBS_NOINTEGRALHEIGHT | - LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "&Forigi",IDC_UNINSTALL,270,48,50,14 - PUSHBUTTON "&Pri..",IDC_ABOUT,270,65,50,14 - PUSHBUTTON "&Fermu",IDC_EXIT,270,81,50,14 -END - - STRINGTABLE DISCARDABLE { IDS_APPNAME, "Wine Programa Malinstalilo" - IDS_ABOUT, "Wine Application Uninstaller (C) 2005 by Andreas Mohr, Hannu Valtonen and Jonathan Ernst. Esperanta traduko: Antonio Codazzi" - IDS_ABOUTTITLE, "Pri Malinstalilo" - IDS_REGISTRYKEYNOTAVAILABLE, "Registrþlosilo ne estas je dispono. Nenio estas farebla !" IDS_UNINSTALLFAILED, "Malinstalad-komando '%s' malsukcesis, eble æar mankas programo.\r\nÆu vi volas forigi la malinstalada 'entry' de la registro ?" } diff --git a/programs/uninstaller/Es.rc b/programs/uninstaller/Es.rc index 998134df3a0..0fe7d14763d 100644 --- a/programs/uninstaller/Es.rc +++ b/programs/uninstaller/Es.rc @@ -20,25 +20,7 @@ LANGUAGE LANG_SPANISH, SUBLANG_NEUTRAL -IDD_UNINSTALLER DIALOG DISCARDABLE 0, 0, 330, 160 -STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU -CAPTION "Desinstalador de aplicaciones de Wine" -FONT 10, "MS Sans Serif" -BEGIN - LTEXT "Por favor, elija la aplicación que desee desinstalar:",IDC_PLEASESELECT,10,10,250,14 - EDITTEXT IDC_FILTER,10,25,250,14,ES_AUTOHSCROLL - LISTBOX IDC_LIST,10,43,250,106,LBS_NOINTEGRALHEIGHT | - LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "&Desinstalar",IDC_UNINSTALL,270,48,50,14 - PUSHBUTTON "&Acerca de",IDC_ABOUT,270,65,50,14 - PUSHBUTTON "&Salir",IDC_EXIT,270,81,50,14 -END - - STRINGTABLE DISCARDABLE { IDS_APPNAME, "Desinstalador de aplicaciones de Wine" - IDS_ABOUT, "Desinstalador de aplicaciones de Wine (C) 2005 por Andreas Mohr, Hannu Valtonen y Jonathan Ernst." - IDS_ABOUTTITLE, "Acerca del desinstalador" - IDS_REGISTRYKEYNOTAVAILABLE, "¡Clave de desinstalación del registro no disponible (todavía), nada que hacer!" IDS_UNINSTALLFAILED, "Ejecución del comando de desinstalación '%s' ha fallado, tal vez se deba a que no exista el ejecutable.\r\n¿Desea eliminar la entrada de desinstalación de esta aplicación del registro?" } diff --git a/programs/uninstaller/Fi.rc b/programs/uninstaller/Fi.rc index e6dc77d5b7e..0114990bdb0 100644 --- a/programs/uninstaller/Fi.rc +++ b/programs/uninstaller/Fi.rc @@ -20,25 +20,7 @@ LANGUAGE LANG_FINNISH, SUBLANG_DEFAULT -IDD_UNINSTALLER DIALOG DISCARDABLE 0, 0, 330, 160 -STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU -CAPTION "Wine Sovelluksen Poistaja" -FONT 10, "MS Sans Serif" -BEGIN - LTEXT "Valitse poistettava sovellus:",IDC_PLEASESELECT,10,10,250,14 - EDITTEXT IDC_FILTER,10,25,250,14,ES_AUTOHSCROLL - LISTBOX IDC_LIST,10,43,250,106,LBS_NOINTEGRALHEIGHT | - LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "&Poista",IDC_UNINSTALL,270,48,50,14 - PUSHBUTTON "&Tietoja",IDC_ABOUT,270,65,50,14 - PUSHBUTTON "&Sulje",IDC_EXIT,270,81,50,14 -END - - STRINGTABLE DISCARDABLE { IDS_APPNAME, "Wine Sovelluksen Poistaja" - IDS_ABOUT, "Wine Sovelluksen Poistaja (C) 2005 Andreas Mohr, Hannu Valtonen ja Jonathan Ernst." - IDS_ABOUTTITLE, "Tietoja Ohjelmasta" - IDS_REGISTRYKEYNOTAVAILABLE, "Rekisteriavainta asennuksen poistoon ei ole (vielä) olemassa, mitään ei ole tehtävissä !" IDS_UNINSTALLFAILED, "Poistokomento '%s' epäonnistui, johtuen ehkä puuttuvasta tiedostosta.\r\nHaluatko poistaa ohjelman rekisteristä?" } diff --git a/programs/uninstaller/Fr.rc b/programs/uninstaller/Fr.rc index 8c9c02b007c..d9ec2a86cc5 100644 --- a/programs/uninstaller/Fr.rc +++ b/programs/uninstaller/Fr.rc @@ -20,25 +20,7 @@ LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL -IDD_UNINSTALLER DIALOG DISCARDABLE 0, 0, 330, 160 -STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU -CAPTION "Désinstalleur d'applications de Wine" -FONT 10, "MS Sans Serif" -BEGIN - LTEXT "Veuillez sélectionner l'application à désinstaller :",IDC_PLEASESELECT,10,10,250,14 - EDITTEXT IDC_FILTER,10,25,250,14,ES_AUTOHSCROLL - LISTBOX IDC_LIST,10,43,250,106,LBS_NOINTEGRALHEIGHT | - LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "&Supprimer",IDC_UNINSTALL,270,48,50,14 - PUSHBUTTON "À &propos",IDC_ABOUT,270,65,50,14 - PUSHBUTTON "&Quitter",IDC_EXIT,270,81,50,14 -END - - STRINGTABLE DISCARDABLE { IDS_APPNAME, "Désinstalleur d'applications de Wine" - IDS_ABOUT, "Désinstalleur d'applications de Wine (C) 2005 par Andreas Mohr, Hannu Valtonen et Jonathan Ernst." - IDS_ABOUTTITLE, "À propos du désinstalleur" - IDS_REGISTRYKEYNOTAVAILABLE, "Clé de dsinstallation non disponible dans la base de registre (actuellement). Il n'y a rien faire !" IDS_UNINSTALLFAILED, "Erreur lors de l'excution de la commande de désinstallation « %s ». L'exécutable ne peut peut être pas être trouvé.\r\nSouhaitez-vous supprimmer l'entrée de la base de registre ?" } diff --git a/programs/uninstaller/Hu.rc b/programs/uninstaller/Hu.rc index 7d869ea18e5..bfd689ca577 100644 --- a/programs/uninstaller/Hu.rc +++ b/programs/uninstaller/Hu.rc @@ -20,25 +20,7 @@ LANGUAGE LANG_HUNGARIAN, SUBLANG_DEFAULT -IDD_UNINSTALLER DIALOG DISCARDABLE 0, 0, 330, 160 -STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU -CAPTION "Wine Alkalmazás eltávolító" -FONT 10, "MS Sans Serif" -BEGIN - LTEXT "Kérem válasszon alkalmazást az eltávolításhoz:",IDC_PLEASESELECT,10,10,250,14 - EDITTEXT IDC_FILTER,10,25,250,14,ES_AUTOHSCROLL - LISTBOX IDC_LIST,10,43,250,106,LBS_NOINTEGRALHEIGHT | - LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "&Eltávolítás",IDC_UNINSTALL,270,48,50,14 - PUSHBUTTON "&Névjegy",IDC_ABOUT,270,65,50,14 - PUSHBUTTON "&Kilépés",IDC_EXIT,270,81,50,14 -END - - STRINGTABLE DISCARDABLE { IDS_APPNAME, "Wine Alkalamazás eltávolító" - IDS_ABOUT, "Wine Alkalmazás eltávolító (C) 2005 by Andreas Mohr, Hannu Valtonen és Jonathan Ernst." - IDS_ABOUTTITLE, "Az Eltávolító névjegye" - IDS_REGISTRYKEYNOTAVAILABLE, "Az eltávolítási regisztrációs kulcs nem elérhetõ (még), nem lehet semmit sem tenni !" IDS_UNINSTALLFAILED, "Az eltávolítási parancs '%s' végrehajtása sikertelen, feltehetõleg a hiányzó futtatható állomány miatt.\r\nEl szeretné távolítani az eltávolítási bejegyzést a regisztrációs adatbázisból ?" } diff --git a/programs/uninstaller/It.rc b/programs/uninstaller/It.rc index b61dd96fc20..af21f6cbc49 100644 --- a/programs/uninstaller/It.rc +++ b/programs/uninstaller/It.rc @@ -20,25 +20,7 @@ LANGUAGE LANG_ITALIAN, SUBLANG_NEUTRAL -IDD_UNINSTALLER DIALOG DISCARDABLE 0, 0, 330, 160 -STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU -CAPTION "WINE Disinstallazione Applicazioni" -FONT 10, "MS Sans Serif" -BEGIN -LTEXT "Selezionare dall'elenco l'applicazione che si desidera rimuovere",IDC_PLEASESELECT,10,10,250,14 -EDITTEXT IDC_FILTER,10,25,250,14,ES_AUTOHSCROLL -LISTBOX IDC_LIST,10,43,250,106,LBS_NOINTEGRALHEIGHT | -LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP -PUSHBUTTON "&Rimuovi",IDC_UNINSTALL,270,48,50,14 -PUSHBUTTON "&Info",IDC_ABOUT,270,65,50,14 -PUSHBUTTON "&Esci",IDC_EXIT,270,81,50,14 -END - - STRINGTABLE DISCARDABLE { IDS_APPNAME, "Wine Disinstallazione Applicazioni" -IDS_ABOUT, "Wine Application Uninstaller (C) 2005 by Andreas Mohr, Hannu Valtonen and Jonathan Ernst. Traduzione italiana: Antonio Codazzi" -IDS_ABOUTTITLE, "Informazioni" -IDS_REGISTRYKEYNOTAVAILABLE, "Chiave del registro non disponibile, nulla da fare !" IDS_UNINSTALLFAILED, "Esecuzione del comando di disinstallazione '%s' è fallita, forse a causa di un eseguibile mancante.\r\nVuoi rimuovere dal registro la entry di disinstallazione?" } diff --git a/programs/uninstaller/Ko.rc b/programs/uninstaller/Ko.rc index fbbbb9208db..a7cb3e90928 100644 --- a/programs/uninstaller/Ko.rc +++ b/programs/uninstaller/Ko.rc @@ -21,25 +21,7 @@ LANGUAGE LANG_KOREAN, SUBLANG_NEUTRAL -IDD_UNINSTALLER DIALOG DISCARDABLE 0, 0, 330, 160 -STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU -CAPTION "Wine Ç®±×¸² Á¦°ÅÇϱâ" -FONT 10, "MS Sans Serif" -BEGIN - LTEXT "´ç½ÅÀÌ ¾ðÀνºÅçÇÏ°í ½ÍÀº Ç®±×¸²À» ¼±ÅÃÇϽÿÀ:",IDC_PLEASESELECT,10,10,250,14 - EDITTEXT IDC_FILTER,10,25,250,14,ES_AUTOHSCROLL - LISTBOX IDC_LIST,10,43,250,106,LBS_NOINTEGRALHEIGHT | - LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Á¦°Å(&U)",IDC_UNINSTALL,270,48,50,14 - PUSHBUTTON "Á¤º¸(&A)",IDC_ABOUT,270,65,50,14 - PUSHBUTTON "³ª°¡±â(&E)",IDC_EXIT,270,81,50,14 -END - - STRINGTABLE DISCARDABLE { IDS_APPNAME, "Wine Application Á¦°ÅÇϱâ" - IDS_ABOUT, "Wine Application Uninstaller (C) 2005 by Andreas Mohr, Hannu Valtonen and Jonathan Ernst." - IDS_ABOUTTITLE, " Uninstaller Á¤º¸" - IDS_REGISTRYKEYNOTAVAILABLE, "·¹Áö½ºÆ®¸® Å° ¾ðÀνºÅçÀº ¾ÆÁ÷ °¡´ÉÇÏÁö ¾Ê½À´Ï´Ù, ¾Æ¹«Àϵµ ¾ÈÇÒ °Ì´Ï´Ù!" IDS_UNINSTALLFAILED, "¾ðÀνºÅç ¸í·É '%s' ½ÇÇà ½ÇÆÐ, ½ÇÇàÆÄÀÏÀÌ ¾ø´Â °Í °°½À´Ï´Ù.\r\n´ç½ÅÀº ·¹Áö½ºÆ®¸®¿¡¼­ ¾ðÀνºÅç µî·ÏÅ°¸¦ Á¦°ÅÇÏ°Ú½À´Ï±î ?" } diff --git a/programs/uninstaller/Makefile.in b/programs/uninstaller/Makefile.in index 7694c6aae4e..7783efaa9ce 100644 --- a/programs/uninstaller/Makefile.in +++ b/programs/uninstaller/Makefile.in @@ -4,7 +4,7 @@ SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = uninstaller.exe APPMODE = -mconsole -municode -IMPORTS = shlwapi user32 gdi32 advapi32 kernel32 +IMPORTS = shlwapi shell32 user32 gdi32 advapi32 kernel32 C_SRCS = \ main.c diff --git a/programs/uninstaller/Nl.rc b/programs/uninstaller/Nl.rc index ca3679fc270..8c645b707eb 100644 --- a/programs/uninstaller/Nl.rc +++ b/programs/uninstaller/Nl.rc @@ -20,25 +20,7 @@ LANGUAGE LANG_DUTCH, SUBLANG_NEUTRAL -IDD_UNINSTALLER DIALOG DISCARDABLE 0, 0, 330, 160 -STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU -CAPTION "Programma verwijderen" -FONT 10, "MS Sans Serif" -BEGIN - LTEXT "Kies het programma dat u wenst te verwijderen:",IDC_PLEASESELECT,10,10,250,14 - EDITTEXT IDC_FILTER,10,25,250,14,ES_AUTOHSCROLL - LISTBOX IDC_LIST,10,43,250,106,LBS_NOINTEGRALHEIGHT | - LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "&Verwijderen",IDC_UNINSTALL,270,48,50,14 - PUSHBUTTON "&Info",IDC_ABOUT,270,65,50,14 - PUSHBUTTON "&Afsluiten",IDC_EXIT,270,81,50,14 -END - - STRINGTABLE DISCARDABLE { IDS_APPNAME, "Programma verwijderen" - IDS_ABOUT, "Programma verwijderen (C) 2005 by Andreas Mohr, Hannu Valtonen and Jonathan Ernst." - IDS_ABOUTTITLE, "Info" - IDS_REGISTRYKEYNOTAVAILABLE, "Verwijdersleutel in de registry is (nog) niet beschikbaar, niets te doen!" IDS_UNINSTALLFAILED, "Het uitvoeren van de verwijderopdracht '%s' is mislukt, wellicht vanwege een ontbrekend bestand.\r\nWilt u de verwijdersleutel verwijderen uit de registry?" } diff --git a/programs/uninstaller/No.rc b/programs/uninstaller/No.rc index a88196fdf4f..2aaa1ecd2f3 100644 --- a/programs/uninstaller/No.rc +++ b/programs/uninstaller/No.rc @@ -20,25 +20,7 @@ LANGUAGE LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL -IDD_UNINSTALLER DIALOG DISCARDABLE 0, 0, 330, 160 -STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU -CAPTION "Avinstaller programmer" -FONT 10, "MS Sans Serif" -BEGIN - LTEXT "Velg programmet du ønsker å avinstallere:",IDC_PLEASESELECT,10,10,250,14 - EDITTEXT IDC_FILTER,10,25,250,14,ES_AUTOHSCROLL - LISTBOX IDC_LIST,10,43,250,106,LBS_NOINTEGRALHEIGHT | - LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "A&vinstaller",IDC_UNINSTALL,270,48,50,14 - PUSHBUTTON "&Om",IDC_ABOUT,270,65,50,14 - PUSHBUTTON "&Lukk",IDC_EXIT,270,81,50,14 -END - - STRINGTABLE DISCARDABLE { IDS_APPNAME, "Avinstaller programmer" - IDS_ABOUT, "Oversatt av Alexander N. Sørnes\nKopirett 2005 for avinstalleringsverktøyet tilhører Andreas Mohr, Hannu Valtonen og Jonathan Ernst." - IDS_ABOUTTITLE, "Om avinstallereren" - IDS_REGISTRYKEYNOTAVAILABLE, "Avinstaller registerverdi er ikke tilgjengelig (ennå); ingenting å gjøre." IDS_UNINSTALLFAILED, "Kjøring av avinstalleringskommandoen '%s' feilet, kanskje på grunn av en manglende programfil.\r\nFjerne avinstalleringsoppføringen fra registeret?" } diff --git a/programs/uninstaller/Pl.rc b/programs/uninstaller/Pl.rc index 4b5937d8ce6..7451e63da0f 100644 --- a/programs/uninstaller/Pl.rc +++ b/programs/uninstaller/Pl.rc @@ -21,25 +21,7 @@ LANGUAGE LANG_POLISH, SUBLANG_DEFAULT -IDD_UNINSTALLER DIALOG DISCARDABLE 0, 0, 330, 160 -STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU -CAPTION "Wine - usuwanie programów" -FONT 10, "MS Sans Serif" -BEGIN - LTEXT "Proszê wybraæ program, których chcesz usun¹æ:",IDC_PLEASESELECT,10,10,250,14 - EDITTEXT IDC_FILTER,10,25,250,14,ES_AUTOHSCROLL - LISTBOX IDC_LIST,10,43,250,106,LBS_NOINTEGRALHEIGHT | - LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "&Usuñ",IDC_UNINSTALL,270,48,50,14 - PUSHBUTTON "&O progamie",IDC_ABOUT,270,65,50,14 - PUSHBUTTON "&Zakoñcz",IDC_EXIT,270,81,50,14 -END - - STRINGTABLE DISCARDABLE { IDS_APPNAME, "Wine - usuwanie programów" - IDS_ABOUT, "Wine - usuwanie programów (C) 2005 by Andreas Mohr, Hannu Valtonen and Jonathan Ernst." - IDS_ABOUTTITLE, "O narzêdziu do usuwania programów" - IDS_REGISTRYKEYNOTAVAILABLE, "Nie ma (jeszcze) informacji o programach do usuniêcia w rejestrze. Nie ma nic do zrobienia!" IDS_UNINSTALLFAILED, "Nie uda³o siê wykonaæ polecenia '%s', które powinno usun¹æ progam. Byæ mo¿e ju¿ by³ usuniêty.\r\nCzy chcesz usun¹æ jego wpis z tej listy?" } diff --git a/programs/uninstaller/Pt.rc b/programs/uninstaller/Pt.rc index 4df2abd0652..14c7867133b 100644 --- a/programs/uninstaller/Pt.rc +++ b/programs/uninstaller/Pt.rc @@ -20,24 +20,7 @@ LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE -IDD_UNINSTALLER DIALOG DISCARDABLE 0, 0, 330, 160 -STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU -CAPTION "Desinstalador de Aplicações Wine" -FONT 10, "MS Sans Serif" -BEGIN - LTEXT "Por favor seleccione a aplicação que deseja desinstalar:",IDC_PLEASESELECT,10,10,250,14 - EDITTEXT IDC_FILTER,10,25,250,14,ES_AUTOHSCROLL - LISTBOX IDC_LIST,10,43,250,106,LBS_NOINTEGRALHEIGHT | - LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "&Desinstalar",IDC_UNINSTALL,270,48,50,14 - PUSHBUTTON "&Acerca",IDC_ABOUT,270,65,50,14 - PUSHBUTTON "&Sair",IDC_EXIT,270,81,50,14 -END - STRINGTABLE DISCARDABLE { IDS_APPNAME, "Desinstalador de Aplicações Wine" - IDS_ABOUT, "Desinstalador de Aplicações Wine (C) 2005 por Andreas Mohr, Hannu Valtonen e Jonathan Ernst." - IDS_ABOUTTITLE, "Acerca do Desinstalador" - IDS_REGISTRYKEYNOTAVAILABLE, "Chave de registo de desinstalação não disponível (ainda), nada a fazer !" IDS_UNINSTALLFAILED, "Execução do comando de desinstalação '%s' falhado, talvez devido a faltar o executável.\r\nDeseja remover a entrada de desinstalação do registo ?" } diff --git a/programs/uninstaller/Ru.rc b/programs/uninstaller/Ru.rc index e1f182e1eb8..bada09cafa1 100644 --- a/programs/uninstaller/Ru.rc +++ b/programs/uninstaller/Ru.rc @@ -20,25 +20,7 @@ LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT -IDD_UNINSTALLER DIALOG DISCARDABLE 0, 0, 330, 160 -STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU -CAPTION "Óäàëåíèå ïðèëîæåíèé WINE" -FONT 10, "MS Sans Serif" -BEGIN - LTEXT "Ïîæàëóéñòà, âûáåðèòå ïðèëîæåíèå äëÿ óäàëåíèÿ:",IDC_PLEASESELECT,10,10,250,14 - EDITTEXT IDC_FILTER,10,25,250,14,ES_AUTOHSCROLL - LISTBOX IDC_LIST,10,43,250,106,LBS_NOINTEGRALHEIGHT | - LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "&Óäàëèòü",IDC_UNINSTALL,270,48,50,14 - PUSHBUTTON "&Î ïðîãðàììå",IDC_ABOUT,270,65,50,14 - PUSHBUTTON "&Âûõîä",IDC_EXIT,270,81,50,14 -END - - STRINGTABLE DISCARDABLE { IDS_APPNAME, "Óäàëåíèå ïðèëîæåíèé WINE" - IDS_ABOUT, "Óäàëåíèå ïðèëîæåíèé WINE (C) 2005 by Andreas Mohr, Hannu Valtonen and Jonathan Ernst." - IDS_ABOUTTITLE, "Î ïðîãðàììå" - IDS_REGISTRYKEYNOTAVAILABLE, "Íåîáõîäèìàÿ çàïèñü â ðååñòðå îòñóòñòâóåò!" IDS_UNINSTALLFAILED, "Îøèáêà âûïîëíåíèÿ êîìàíäû óäàëåíèÿ '%s', âîçìîæíî èç-çà ïîòåðè ôàéëîâ ïðèëîæåíèÿ.\r\nÓäàëèòü èíôîðìàöèþ îá óñòàíîâêå èç ðååñòðà?" } diff --git a/programs/uninstaller/Si.rc b/programs/uninstaller/Si.rc index 4a7a8f0af80..a971ae35b3a 100644 --- a/programs/uninstaller/Si.rc +++ b/programs/uninstaller/Si.rc @@ -22,26 +22,8 @@ LANGUAGE LANG_SLOVENIAN, SUBLANG_DEFAULT -IDD_UNINSTALLER DIALOG DISCARDABLE 0, 0, 330, 160 -STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU -CAPTION "Wine Odstranjevalec programov" -FONT 10, "MS Sans Serif" -BEGIN - LTEXT "Izberite program, ki ga želite odstraniti:",IDC_PLEASESELECT,10,10,250,14 - EDITTEXT IDC_FILTER,10,25,250,14,ES_AUTOHSCROLL - LISTBOX IDC_LIST,10,43,250,106,LBS_NOINTEGRALHEIGHT | - LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "O&dstrani",IDC_UNINSTALL,270,48,50,14 - PUSHBUTTON "&O programu",IDC_ABOUT,270,65,50,14 - PUSHBUTTON "Iz&hod",IDC_EXIT,270,81,50,14 -END - - STRINGTABLE DISCARDABLE { IDS_APPNAME, "Wine Odstranjevalec programov" - IDS_ABOUT, "Wine Odstranjevalec programov (C) 2005 by Andreas Mohr, Hannu Valtonen and Jonathan Ernst." - IDS_ABOUTTITLE, "O Odstranjevalcu" - IDS_REGISTRYKEYNOTAVAILABLE, "Odstranitveni ključ ni (še) na voljo. Ničesar nimam za storiti!" IDS_UNINSTALLFAILED, "Izvedba odstranitvenega ukaza '%s' ni uspela, morda zaradi manjkajoče izvršljive datoteke.\r\nAli želite odstraniti odstranitveni ključ iz registra?" } diff --git a/programs/uninstaller/Sv.rc b/programs/uninstaller/Sv.rc index 13537cffc71..00d08103dee 100644 --- a/programs/uninstaller/Sv.rc +++ b/programs/uninstaller/Sv.rc @@ -20,25 +20,7 @@ LANGUAGE LANG_SWEDISH, SUBLANG_NEUTRAL -IDD_UNINSTALLER DIALOG DISCARDABLE 0, 0, 330, 160 -STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU -CAPTION "Avinstallera Wine-program" -FONT 10, "MS Sans Serif" -BEGIN - LTEXT "Välj programmet som du vill avinstallera:",IDC_PLEASESELECT,10,10,250,14 - EDITTEXT IDC_FILTER,10,25,250,14,ES_AUTOHSCROLL - LISTBOX IDC_LIST,10,43,250,106,LBS_NOINTEGRALHEIGHT | - LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "&Avinstallera",IDC_UNINSTALL,270,48,50,14 - PUSHBUTTON "&Om",IDC_ABOUT,270,65,50,14 - PUSHBUTTON "A&vsluta",IDC_EXIT,270,81,50,14 -END - - STRINGTABLE DISCARDABLE { IDS_APPNAME, "Avinstallera Wine-program" - IDS_ABOUT, "Wine Application Uninstaller (C) 2005 Andreas Mohr, Hannu Valtonen och Jonathan Ernst." - IDS_ABOUTTITLE, "Om Uninstaller" - IDS_REGISTRYKEYNOTAVAILABLE, "Uninstall registry key not available (yet), nothing to do !" IDS_UNINSTALLFAILED, "Execution of uninstall command '%s' failed, perhaps due to missing executable.\r\nDo you want to remove the uninstall entry from the registry ?" } diff --git a/programs/uninstaller/Tr.rc b/programs/uninstaller/Tr.rc index eea501d1e1f..5a46812552a 100644 --- a/programs/uninstaller/Tr.rc +++ b/programs/uninstaller/Tr.rc @@ -20,25 +20,7 @@ LANGUAGE LANG_TURKISH, SUBLANG_DEFAULT -IDD_UNINSTALLER DIALOG DISCARDABLE 0, 0, 330, 160 -STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU -CAPTION "Wine Uygulama Kaldýrýcý" -FONT 10, "MS Sans Serif" -BEGIN - LTEXT "Lütfen kaldýrmak istediðiniz uygulamayý seçin:",IDC_PLEASESELECT,10,10,250,14 - EDITTEXT IDC_FILTER,10,25,250,14,ES_AUTOHSCROLL - LISTBOX IDC_LIST,10,43,250,106,LBS_NOINTEGRALHEIGHT | - LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "&Kaldýr",IDC_UNINSTALL,270,48,50,14 - PUSHBUTTON "&Hakkýnda",IDC_ABOUT,270,65,50,14 - PUSHBUTTON "&Çýkýþ",IDC_EXIT,270,81,50,14 -END - - STRINGTABLE DISCARDABLE { IDS_APPNAME, "Wine Uygulama Kaldýrýcý" - IDS_ABOUT, "Wine Uygulama Kaldýrýcý (C) 2005 Andreas Mohr, Hannu Valtonen ve Jonathan Ernst." - IDS_ABOUTTITLE, "About Kaldýrýcý" - IDS_REGISTRYKEYNOTAVAILABLE, "Sistem kaydýnda kurulu program bilgisi bulunmuyor. Yapýlacak birþey yok!" IDS_UNINSTALLFAILED, "'%s' kaldýrma komutu çalýþtýrýlamadý, çalýþtýrýbilir dosya var olmayabilir.\r\nSistem kaydýndan bu kaldýrma giriþini silmek ister misiniz?" } diff --git a/programs/uninstaller/main.c b/programs/uninstaller/main.c index d731de46f55..1eaa3f30bf4 100644 --- a/programs/uninstaller/main.c +++ b/programs/uninstaller/main.c @@ -31,6 +31,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(uninstaller); +extern void WINAPI Control_RunDLL(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow); + typedef struct { HKEY root; WCHAR *key; @@ -44,17 +46,11 @@ static int list_need_update = 1; static int oldsel = -1; static WCHAR *sFilter; static WCHAR sAppName[MAX_STRING_LEN]; -static WCHAR sAboutTitle[MAX_STRING_LEN]; -static WCHAR sAbout[MAX_STRING_LEN]; -static WCHAR sRegistryKeyNotAvailable[MAX_STRING_LEN]; static WCHAR sUninstallFailed[MAX_STRING_LEN]; static int FetchUninstallInformation(void); static void UninstallProgram(void); -static void UpdateList(HWND hList); static int cmp_by_name(const void *a, const void *b); -static INT_PTR CALLBACK DlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam); - static const WCHAR BackSlashW[] = { '\\', 0 }; static const WCHAR DisplayNameW[] = {'D','i','s','p','l','a','y','N','a','m','e',0}; @@ -162,12 +158,11 @@ int wmain(int argc, WCHAR *argv[]) /* Load MessageBox's strings */ LoadStringW(hInst, IDS_APPNAME, sAppName, sizeof(sAppName)/sizeof(WCHAR)); - LoadStringW(hInst, IDS_ABOUTTITLE, sAboutTitle, sizeof(sAboutTitle)/sizeof(WCHAR)); - LoadStringW(hInst, IDS_ABOUT, sAbout, sizeof(sAbout)/sizeof(WCHAR)); - LoadStringW(hInst, IDS_REGISTRYKEYNOTAVAILABLE, sRegistryKeyNotAvailable, sizeof(sRegistryKeyNotAvailable)/sizeof(WCHAR)); LoadStringW(hInst, IDS_UNINSTALLFAILED, sUninstallFailed, sizeof(sUninstallFailed)/sizeof(WCHAR)); - return DialogBoxW(hInst, MAKEINTRESOURCEW(IDD_UNINSTALLER), NULL, DlgProc); + /* Start the GUI control panel */ + Control_RunDLL(GetDesktopWindow(), 0, "appwiz.cpl", SW_SHOW); + return 1; } @@ -285,114 +280,3 @@ static void UninstallProgram(void) WINE_TRACE("finished uninstall phase.\n"); list_need_update = 1; } - -static void UpdateButtons(HWND hDlg, HWND hList) -{ - EnableWindow(GetDlgItem(hDlg, IDC_UNINSTALL), SendMessageW(hList, LB_GETSELCOUNT, 0, 0) > 0); -} - -static INT_PTR CALLBACK DlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) -{ - TEXTMETRICW tm; - HDC hdc; - HWND hList = GetDlgItem(hwnd, IDC_LIST); - switch(Message) - { - case WM_INITDIALOG: - hdc = GetDC(hwnd); - GetTextMetricsW(hdc, &tm); - UpdateList(hList); - ReleaseDC(hwnd, hdc); - UpdateButtons(hwnd, hList); - break; - case WM_COMMAND: - switch(LOWORD(wParam)) - { - case IDC_FILTER: - { - if (HIWORD(wParam) == EN_CHANGE) - { - int len = GetWindowTextLengthW(GetDlgItem(hwnd, IDC_FILTER)); - list_need_update = 1; - if(len > 0) - { - sFilter = (WCHAR*)GlobalAlloc(GPTR, (len + 1)*sizeof(WCHAR)); - GetDlgItemTextW(hwnd, IDC_FILTER, sFilter, len + 1); - } - else sFilter = NULL; - UpdateList(hList); - UpdateButtons(hwnd, hList); - } - break; - } - case IDC_UNINSTALL: - { - int count = SendMessageW(hList, LB_GETSELCOUNT, 0, 0); - if(count != 0) - { - UninstallProgram(); - UpdateList(hList); - UpdateButtons(hwnd, hList); - } - break; - } - case IDC_LIST: - if (HIWORD(wParam) == LBN_SELCHANGE) - { - int sel = SendMessageW(hList, LB_GETCURSEL, 0, 0); - if (oldsel != -1) - { - entries[oldsel].active ^= 1; /* toggle */ - WINE_TRACE("toggling %d old %s\n", entries[oldsel].active, - wine_dbgstr_w(entries[oldsel].descr)); - } - entries[sel].active ^= 1; /* toggle */ - WINE_TRACE("toggling %d %s\n", entries[sel].active, - wine_dbgstr_w(entries[sel].descr)); - oldsel = sel; - } - UpdateButtons(hwnd, hList); - break; - case IDC_ABOUT: - MessageBoxW(0, sAbout, sAboutTitle, MB_OK); - break; - case IDCANCEL: - case IDC_EXIT: - EndDialog(hwnd, 0); - break; - } - break; - default: - return FALSE; - } - return TRUE; -} - - -static void UpdateList(HWND hList) -{ - unsigned int i; - if (list_need_update) - { - int prevsel; - prevsel = SendMessageW(hList, LB_GETCURSEL, 0, 0); - if (!(FetchUninstallInformation())) - { - MessageBoxW(0, sRegistryKeyNotAvailable, sAppName, MB_OK); - PostQuitMessage(0); - return; - } - SendMessageW(hList, LB_RESETCONTENT, 0, 0); - SendMessageW(hList, WM_SETREDRAW, FALSE, 0); - for (i=0; i < numentries; i++) - { - WINE_TRACE("adding %s\n", wine_dbgstr_w(entries[i].descr)); - SendMessageW(hList, LB_ADDSTRING, 0, (LPARAM)entries[i].descr); - } - WINE_TRACE("setting prevsel %d\n", prevsel); - if (prevsel != -1) - SendMessageW(hList, LB_SETCURSEL, prevsel, 0 ); - SendMessageW(hList, WM_SETREDRAW, TRUE, 0); - list_need_update = 0; - } -} diff --git a/programs/uninstaller/resource.h b/programs/uninstaller/resource.h index fbb17925afc..b30be4ecba3 100644 --- a/programs/uninstaller/resource.h +++ b/programs/uninstaller/resource.h @@ -18,16 +18,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#define IDD_UNINSTALLER 101 -#define IDC_FILTER 1001 -#define IDC_LIST 1002 -#define IDC_UNINSTALL 1003 -#define IDC_ABOUT 1004 -#define IDC_EXIT 1005 -#define IDC_PLEASESELECT 1006 -#define IDS_APPNAME 1007 -#define IDS_ABOUT 1008 -#define IDS_ABOUTTITLE 1009 -#define IDS_REGISTRYKEYNOTAVAILABLE 1010 -#define IDS_UNINSTALLFAILED 1011 +#define IDS_APPNAME 1000 +#define IDS_UNINSTALLFAILED 1001 #define MAX_STRING_LEN 255 diff --git a/programs/uninstaller/rsrc.rc b/programs/uninstaller/rsrc.rc index 5913ca5758f..72bcc9a6538 100644 --- a/programs/uninstaller/rsrc.rc +++ b/programs/uninstaller/rsrc.rc @@ -46,8 +46,3 @@ #include "Si.rc" #include "Sv.rc" #include "Tr.rc" - -LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL - -/* @makedep: uninstaller.ico */ -UNINSTALLER ICON MOVEABLE uninstaller.ico diff --git a/programs/uninstaller/uninstaller.ico b/programs/uninstaller/uninstaller.ico deleted file mode 100644 index fcc5894c69cb0de40227d44089dedfd8b8cc579d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcwPel00001 literal 766 zcwV)UJx;?w5QWEKBT8(^LZTwtxS+*O&nABKDYEBrj>ai`297|1w9Jp!u|-3}Sfky~ z@9p0VQNiDCSCYi%hUk&U7tS4L;4H|gMjM)=oW}HI<1h@AQj$M3jwAgwP^|(uF0lr% zavy7i8#;((DOXjAzMJBJg4rQ6f-vFaeb;*5fRqoD0ljf629Z1C&J4Woqt1zU1s5&kbry diff --git a/tools/winapi/msvcmaker b/tools/winapi/msvcmaker index 132d6550b16..01b6d4b2f96 100755 --- a/tools/winapi/msvcmaker +++ b/tools/winapi/msvcmaker @@ -135,7 +135,7 @@ MAKEFILE_IN: foreach my $makefile_in_file (@makefile_in_files) { chomp $line; if($lookahead) { $lookahead = 0; - $_ .= "\n" . $line; + $_ .= " " . $line; } else { $_ = $line; } -- 2.11.4.GIT