From 0f172f368eb3960aeaef84308df850e832c3739d Mon Sep 17 00:00:00 2001 From: Jan Zerebecki Date: Sat, 28 Nov 2009 12:12:53 +0100 Subject: [PATCH] push a983949f12fdeee03aaeb40359f0911e8a4bb18f --- .gitignore | 3 + configure | 2 + configure.ac | 2 + dlls/advapi32/Makefile.in | 3 +- dlls/advapi32/eventlog.c | 8 +- dlls/advapi32/security.c | 4 +- dlls/advapi32/tests/eventlog.c | 95 ++- dlls/advapi32/tests/registry.c | 23 + dlls/advapi32/tests/security.c | 86 +- dlls/avrt/main.c | 2 +- dlls/comctl32/imagelist.c | 316 ++++++-- dlls/comctl32/imagelist.h | 30 +- dlls/comctl32/listview.c | 198 +++-- dlls/comctl32/tab.c | 26 +- dlls/comctl32/tests/imagelist.c | 361 ++++++++- dlls/comctl32/tests/listview.c | 107 ++- dlls/comctl32/tests/monthcal.c | 1 + dlls/comctl32/tests/propsheet.c | 29 +- dlls/comctl32/tests/tab.c | 572 ++++++++------ dlls/comctl32/toolbar.c | 4 +- dlls/comctl32/updown.c | 4 +- dlls/comdlg32/colordlg.c | 12 +- dlls/comdlg32/tests/filedlg.c | 13 +- dlls/commdlg.dll16/finddlg.c | 2 - dlls/commdlg.dll16/printdlg.c | 2 +- dlls/crypt32/Makefile.in | 1 + dlls/crypt32/cert.c | 86 ++ dlls/crypt32/chain.c | 732 +++++++++++++---- dlls/crypt32/crl.c | 235 +++++- dlls/crypt32/crypt32.spec | 2 +- dlls/crypt32/rootstore.c | 32 + dlls/crypt32/tests/cert.c | 362 ++++++++- dlls/crypt32/tests/chain.c | 433 +++++++++- dlls/crypt32/tests/crl.c | 553 +++++++++++-- dlls/crypt32/tests/encode.c | 37 - dlls/cryptnet/cryptnet_main.c | 159 +++- dlls/cryptnet/tests/cryptnet.c | 205 +++++ dlls/d3d10core/d3d10core_main.c | 8 +- dlls/d3d10core/d3d10core_private.h | 5 +- dlls/d3d10core/device.c | 15 +- dlls/d3d8/d3d8_private.h | 18 +- dlls/d3d8/device.c | 127 ++- dlls/d3d8/directx.c | 131 +-- dlls/d3d8/vertexdeclaration.c | 3 +- dlls/d3d9/d3d9_private.h | 16 +- dlls/d3d9/device.c | 140 +++- dlls/d3d9/directx.c | 129 +-- dlls/dbghelp/dbghelp.spec | 2 +- dlls/dbghelp/dbghelp_private.h | 2 +- dlls/dbghelp/module.c | 27 +- dlls/dbghelp/msc.c | 11 +- dlls/dbghelp/type.c | 21 +- dlls/ddraw/ddraw.c | 47 +- dlls/ddraw/tests/dsurface.c | 2 +- dlls/dsound/capture.c | 130 --- dlls/dsound/dsound_main.c | 143 +++- dlls/dsound/dsound_private.h | 51 -- dlls/dsound/duplex.c | 43 + dlls/dsound/tests/dsound.c | 13 +- dlls/dsound/tests/dsound8.c | 13 +- dlls/dxgi/device.c | 79 +- dlls/dxgi/dxgi_main.c | 75 +- dlls/dxgi/dxgi_private.h | 68 +- dlls/gdi32/brush.c | 21 - dlls/gdi32/dc.c | 22 +- dlls/gdi32/driver.c | 2 +- dlls/gdi32/enhmfdrv/bitblt.c | 124 +-- dlls/gdi32/enhmfdrv/init.c | 1 - dlls/gdi32/font.c | 22 - dlls/gdi32/gdi16.c | 409 ++++++---- dlls/gdi32/gdi32.spec | 2 - dlls/gdi32/gdi_private.h | 18 +- dlls/gdi32/metafile.c | 6 +- dlls/gdi32/metafile16.c | 133 +--- dlls/gdi32/mfdrv/init.c | 1 - dlls/gdi32/opengl.c | 25 +- dlls/gdi32/palette.c | 2 +- dlls/gdi32/printdrv16.c | 66 -- dlls/gdi32/tests/font.c | 34 + dlls/gdi32/tests/metafile.c | 122 +++ dlls/jscript/activex.c | 2 +- dlls/jscript/error.c | 5 - dlls/jscript/global.c | 120 ++- dlls/jscript/tests/api.js | 20 + dlls/kernel32/file.c | 1 + dlls/kernel32/file16.c | 1 + dlls/kernel32/kernel32.spec | 2 +- dlls/kernel32/sync.c | 12 + dlls/kernel32/tests/file.c | 202 ++++- dlls/kernel32/tests/volume.c | 5 +- dlls/mountmgr.sys/mountmgr.c | 16 + dlls/msdaps/usrmarshal.c | 1 + dlls/mshtml/De.rc | 8 +- dlls/mshtml/Lt.rc | 14 +- dlls/mshtml/Ru.rc | 25 +- dlls/mshtml/Sv.rc | 6 +- dlls/mshtml/conpoint.c | 6 +- dlls/mshtml/dispex.c | 57 ++ dlls/mshtml/htmlanchor.c | 60 +- dlls/mshtml/htmlbody.c | 2 +- dlls/mshtml/htmldoc.c | 13 +- dlls/mshtml/htmldoc3.c | 58 +- dlls/mshtml/htmlelem.c | 81 +- dlls/mshtml/htmlelemcol.c | 31 +- dlls/mshtml/htmlevent.c | 147 +++- dlls/mshtml/htmlstyle3.c | 10 +- dlls/mshtml/htmltable.c | 2 +- dlls/mshtml/htmltextcont.c | 2 +- dlls/mshtml/htmlwindow.c | 245 +++++- dlls/mshtml/install.c | 2 +- dlls/mshtml/mshtml_private.h | 18 +- dlls/mshtml/nsiface.idl | 33 + dlls/mshtml/secmgr.c | 38 +- dlls/mshtml/task.c | 6 - dlls/mshtml/tests/dom.c | 312 +++++++- dlls/mshtml/tests/events.c | 131 +++ dlls/mshtml/tests/htmldoc.c | 76 +- dlls/mshtml/tests/script.c | 144 ++-- dlls/msi/action.c | 1 - dlls/msi/files.c | 2 +- dlls/msi/media.c | 2 +- dlls/msi/package.c | 17 +- dlls/msi/select.c | 10 +- dlls/msi/storages.c | 11 + dlls/msi/streams.c | 11 + dlls/msi/table.c | 4 +- dlls/msi/tests/automation.c | 3 +- dlls/msi/tests/db.c | 75 ++ dlls/msi/tests/install.c | 71 ++ dlls/msvcr71/msvcr71.spec | 6 +- dlls/msvcrt/msvcrt.h | 12 +- dlls/msvcrt/msvcrt.spec | 2 + dlls/msvcrt/scanf.h | 2 +- dlls/msvcrt/tests/cpp.c | 2 + dlls/msvcrt/tests/string.c | 90 +++ dlls/msvcrt/undname.c | 61 +- dlls/msvcrt/wcs.c | 29 + dlls/msvidc32/msvideo1.c | 6 +- dlls/msxml3/node.c | 217 ++++- dlls/msxml3/tests/domdoc.c | 366 ++++++++- dlls/netapi32/tests/access.c | 5 +- dlls/ntdll/directory.c | 280 ++++--- dlls/ntdll/file.c | 311 +++++--- dlls/ntdll/nt.c | 51 +- dlls/ntdll/ntdll_misc.h | 49 +- dlls/ntdll/signal_i386.c | 115 ++- dlls/ntdll/signal_powerpc.c | 59 +- dlls/ntdll/signal_sparc.c | 59 +- dlls/ntdll/signal_x86_64.c | 64 +- dlls/ntdll/tests/file.c | 53 ++ dlls/ntdll/thread.c | 129 +-- dlls/ntoskrnl.exe/ntoskrnl.c | 19 + dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 4 +- dlls/ole32/compobj.c | 31 +- dlls/ole32/compobj_private.h | 3 + dlls/ole32/defaulthandler.c | 96 +++ dlls/ole32/filemoniker.c | 20 +- dlls/ole32/marshal.c | 2 +- dlls/ole32/ole2.c | 3 + dlls/ole32/oleproxy.c | 8 +- dlls/ole32/stg_prop.c | 2 +- dlls/ole32/stg_stream.c | 73 +- dlls/ole32/storage32.c | 1182 +++++++++++++++------------- dlls/ole32/storage32.h | 47 +- dlls/ole32/stubmanager.c | 8 +- dlls/ole32/tests/compobj.c | 21 +- dlls/ole32/tests/marshal.c | 36 +- dlls/ole32/tests/storage32.c | 83 +- dlls/ole32/usrmarshal.c | 10 +- dlls/oleaut32/tests/tmarshal.c | 32 +- dlls/oleaut32/tests/tmarshal.idl | 3 + dlls/oleaut32/tests/tmarshal_dispids.h | 1 + dlls/oleaut32/tests/vartest.c | 3 + dlls/oleaut32/tmarshal.c | 210 ++--- dlls/oleaut32/typelib.c | 216 ++--- dlls/oleaut32/usrmarshal.c | 14 +- dlls/oleaut32/variant.c | 61 +- dlls/oleaut32/variant.h | 1 + dlls/oledb32/tests/marshal.c | 3 +- dlls/opengl32/make_opengl | 3 + dlls/opengl32/opengl_ext.c | 438 +++++++++++ dlls/opengl32/tests/opengl.c | 39 +- dlls/pdh/pdh.spec | 4 +- dlls/pdh/pdh_main.c | 18 + dlls/quartz/filtergraph.c | 87 +- dlls/rpcrt4/ndr_fullpointer.c | 3 + dlls/rpcrt4/ndr_marshall.c | 2 +- dlls/rpcrt4/ndr_stubless.c | 84 +- dlls/rpcrt4/rpc_binding.c | 7 +- dlls/rpcrt4/rpc_epmap.c | 4 +- dlls/rpcrt4/rpc_server.c | 1 + dlls/rpcrt4/tests/ndr_marshall.c | 3 + dlls/rpcrt4/tests/rpc.c | 12 + dlls/rpcrt4/tests/server.c | 19 + dlls/rpcrt4/tests/server.idl | 4 + dlls/rsaenh/tests/rsaenh.c | 10 +- dlls/secur32/schannel.c | 3 + dlls/setupapi/tests/install.c | 8 +- dlls/shdocvw/oleobject.c | 14 +- dlls/shdocvw/tests/webbrowser.c | 34 - dlls/shell32/assoc.c | 17 +- dlls/shell32/shelllink.c | 25 +- dlls/shell32/shellord.c | 39 +- dlls/shell32/shfldr_unixfs.c | 2 +- dlls/shell32/tests/progman_dde.c | 93 ++- dlls/shell32/tests/shelllink.c | 14 + dlls/shell32/tests/shlfileop.c | 5 +- dlls/snmpapi/tests/util.c | 4 +- dlls/urlmon/bindprot.c | 2 +- dlls/urlmon/tests/url.c | 34 - dlls/user32/dde_misc.c | 8 +- dlls/user32/edit.c | 10 +- dlls/user32/tests/edit.c | 40 + dlls/user32/win.c | 4 +- dlls/usp10/usp10.c | 45 ++ dlls/usp10/usp10.spec | 4 +- dlls/uxtheme/msstyles.c | 10 +- dlls/wined3d/device.c | 106 ++- dlls/wined3d/directx.c | 221 +----- dlls/wined3d/state.c | 2 +- dlls/wined3d/utils.c | 287 ++++--- dlls/wined3d/volume.c | 2 + dlls/wined3d/wined3d_private.h | 16 +- dlls/wineps.drv/bitmap.c | 35 +- dlls/wineps.drv/init.c | 46 +- dlls/winex11.drv/bitmap.c | 2 +- dlls/winex11.drv/clipboard.c | 116 ++- dlls/winex11.drv/graphics.c | 12 - dlls/winex11.drv/opengl.c | 265 +++++-- dlls/winex11.drv/winex11.drv.spec | 2 +- dlls/winex11.drv/x11drv.h | 1 + dlls/winex11.drv/x11drv_main.c | 1 + dlls/wing.dll16/wing.c | 83 +- dlls/wininet/http.c | 20 +- dlls/winmm/mci.c | 23 +- dlls/winmm/tests/mci.c | 379 ++++++--- dlls/winspool.drv/info.c | 2 - dlls/winspool.drv/tests/info.c | 11 + include/Makefile.in | 3 + include/audioclient.idl | 326 ++++++++ include/audiopolicy.idl | 245 ++++++ include/commctrl.h | 12 +- include/config.h.in | 6 + include/dbghelp.h | 1 + include/ddk/wdm.h | 2 + include/devicetopology.idl | 738 +++++++++++++++++ include/dsound.h | 2 +- include/gdiplusflat.h | 33 + include/ksmedia.h | 98 +++ include/mmsystem.h | 2 +- include/msvcrt/crtdefs.h | 12 +- include/msvcrt/io.h | 4 +- include/msvcrt/stdio.h | 2 +- include/msvcrt/wchar.h | 2 +- include/propkeydef.h | 6 +- include/prsht.h | 2 +- include/rpcndr.h | 4 +- include/winbase.h | 5 + include/wine/rpcfc.h | 1 + include/wine/server_protocol.h | 17 +- include/wine/wgl.h | 9 + include/wine/wined3d.idl | 2 - include/winnt.h | 2 +- include/winternl.h | 52 +- include/ws2def.h | 2 +- programs/cmd/It.rc | 2 +- programs/winemenubuilder/winemenubuilder.c | 12 +- programs/winetest/main.c | 10 + programs/wordpad/wordpad.c | 7 + server/fd.c | 207 ++++- server/file.c | 61 +- server/file.h | 13 +- server/mapping.c | 143 +++- server/protocol.def | 9 +- server/registry.c | 15 +- server/request.h | 11 +- server/thread.c | 4 +- server/token.c | 42 +- server/trace.c | 17 +- tools/widl/header.c | 8 +- tools/widl/parser.y | 2 +- tools/widl/typegen.c | 2 +- tools/wine.inf.in | 5 +- tools/winebuild/build.h | 4 +- tools/winebuild/import.c | 12 + tools/winebuild/main.c | 2 + tools/winebuild/spec32.c | 7 + tools/winebuild/utils.c | 26 +- tools/winedump/minidump.c | 3 + tools/winedump/pe.c | 1 + tools/winemaker | 2 + 291 files changed, 13689 insertions(+), 4665 deletions(-) create mode 100644 include/audioclient.idl create mode 100644 include/audiopolicy.idl create mode 100644 include/devicetopology.idl diff --git a/.gitignore b/.gitignore index 77763397213..ade07836ed7 100644 --- a/.gitignore +++ b/.gitignore @@ -125,6 +125,8 @@ include/activdbg.h include/activscp.h include/amstream.h include/amvideo.h +include/audioclient.h +include/audiopolicy.h include/austream.h include/bits.h include/bits1_5.h @@ -135,6 +137,7 @@ include/control.h include/ctxtcall.h include/d3d10.h include/ddstream.h +include/devicetopology.h include/dimm.h include/dispex.h include/docobj.h diff --git a/configure b/configure index a6192d88411..62f529ad2fc 100755 --- a/configure +++ b/configure @@ -6085,6 +6085,7 @@ for ac_header in \ openssl/ssl.h \ png.h \ poll.h \ + port.h \ process.h \ pthread.h \ pwd.h \ @@ -18490,6 +18491,7 @@ for ac_func in \ pipe2 \ poll \ popen \ + port_create \ prctl \ pread \ pwrite \ diff --git a/configure.ac b/configure.ac index ab0733d9c46..e1dc237a192 100644 --- a/configure.ac +++ b/configure.ac @@ -365,6 +365,7 @@ AC_CHECK_HEADERS(\ openssl/ssl.h \ png.h \ poll.h \ + port.h \ process.h \ pthread.h \ pwd.h \ @@ -1732,6 +1733,7 @@ AC_CHECK_FUNCS(\ pipe2 \ poll \ popen \ + port_create \ prctl \ pread \ pwrite \ diff --git a/dlls/advapi32/Makefile.in b/dlls/advapi32/Makefile.in index d9236dc4831..3fb0948938c 100644 --- a/dlls/advapi32/Makefile.in +++ b/dlls/advapi32/Makefile.in @@ -5,9 +5,8 @@ SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = advapi32.dll IMPORTLIB = advapi32 -IMPORTS = kernel32 ntdll +IMPORTS = rpcrt4 kernel32 ntdll EXTRALIBS = @SECURITYLIB@ -DELAYIMPORTS = rpcrt4 C_SRCS = \ advapi.c \ diff --git a/dlls/advapi32/eventlog.c b/dlls/advapi32/eventlog.c index d336f746c13..a5d1837b480 100644 --- a/dlls/advapi32/eventlog.c +++ b/dlls/advapi32/eventlog.c @@ -717,8 +717,8 @@ ULONG WINAPI RegisterTraceGuidsW( WMIDPREQUEST RequestAddress, PTRACE_GUID_REGISTRATION TraceGuidReg, LPCWSTR MofImagePath, LPCWSTR MofResourceName, PTRACEHANDLE RegistrationHandle ) { - FIXME("%p %p %p %u %p %s %s %p\n", RequestAddress, RequestContext, - ControlGuid, GuidCount, TraceGuidReg, debugstr_w(MofImagePath), + FIXME("(%p, %p, %s, %u, %p, %s, %s, %p,)\n", RequestAddress, RequestContext, + debugstr_guid(ControlGuid), GuidCount, TraceGuidReg, debugstr_w(MofImagePath), debugstr_w(MofResourceName), RegistrationHandle); return ERROR_CALL_NOT_IMPLEMENTED; } @@ -736,8 +736,8 @@ ULONG WINAPI RegisterTraceGuidsA( WMIDPREQUEST RequestAddress, PTRACE_GUID_REGISTRATION TraceGuidReg, LPCSTR MofImagePath, LPCSTR MofResourceName, PTRACEHANDLE RegistrationHandle ) { - FIXME("%p %p %p %u %p %s %s %p\n", RequestAddress, RequestContext, - ControlGuid, GuidCount, TraceGuidReg, debugstr_a(MofImagePath), + FIXME("(%p, %p, %s, %u, %p, %s, %s, %p,)\n", RequestAddress, RequestContext, + debugstr_guid(ControlGuid), GuidCount, TraceGuidReg, debugstr_a(MofImagePath), debugstr_a(MofResourceName), RegistrationHandle); return ERROR_CALL_NOT_IMPLEMENTED; } diff --git a/dlls/advapi32/security.c b/dlls/advapi32/security.c index 7dd39a4a75d..3e79a614291 100644 --- a/dlls/advapi32/security.c +++ b/dlls/advapi32/security.c @@ -1055,7 +1055,9 @@ IsValidSid( PSID pSid ) BOOL WINAPI EqualSid( PSID pSid1, PSID pSid2 ) { - return RtlEqualSid( pSid1, pSid2 ); + BOOL ret = RtlEqualSid( pSid1, pSid2 ); + SetLastError(ERROR_SUCCESS); + return ret; } /****************************************************************************** diff --git a/dlls/advapi32/tests/eventlog.c b/dlls/advapi32/tests/eventlog.c index c989d4a3c8b..207fec5836d 100644 --- a/dlls/advapi32/tests/eventlog.c +++ b/dlls/advapi32/tests/eventlog.c @@ -31,13 +31,19 @@ static BOOL (WINAPI *pCreateWellKnownSid)(WELL_KNOWN_SID_TYPE,PSID,PSID,DWORD*); static BOOL (WINAPI *pGetEventLogInformation)(HANDLE,DWORD,LPVOID,DWORD,LPDWORD); +static BOOL (WINAPI *pWow64DisableWow64FsRedirection)(PVOID *); +static BOOL (WINAPI *pWow64RevertWow64FsRedirection)(PVOID); static void init_function_pointers(void) { HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll"); + HMODULE hkernel32 = GetModuleHandleA("kernel32.dll"); pCreateWellKnownSid = (void*)GetProcAddress(hadvapi32, "CreateWellKnownSid"); pGetEventLogInformation = (void*)GetProcAddress(hadvapi32, "GetEventLogInformation"); + + pWow64DisableWow64FsRedirection = (void*)GetProcAddress(hkernel32, "Wow64DisableWow64FsRedirection"); + pWow64RevertWow64FsRedirection = (void*)GetProcAddress(hkernel32, "Wow64RevertWow64FsRedirection"); } static void create_backup(const char *filename) @@ -701,7 +707,7 @@ static void test_readwrite(void) PSID user; DWORD sidsize, count; BOOL ret, sidavailable; - BOOL on_vista = FALSE; /* Used to indicate Vista or higher */ + BOOL on_vista = FALSE; /* Used to indicate Vista, W2K8 or Win7 */ int i; char localcomputer[MAX_COMPUTERNAME_LENGTH + 1]; DWORD len = sizeof(localcomputer); @@ -727,6 +733,34 @@ static void test_readwrite(void) * but succeed on all others, hence it's not part of the struct. */ handle = OpenEventLogA(NULL, eventlogname); + if (!handle) + { + /* Intermittently seen on NT4 when tests are run immediately after boot */ + win_skip("Could not get a handle to the eventlog\n"); + HeapFree(GetProcessHeap(), 0, user); + return; + } + + count = 0xdeadbeef; + GetNumberOfEventLogRecords(handle, &count); + if (count != 0) + { + /* Needed for W2K3 without a service pack */ + win_skip("We most likely opened the Application eventlog\n"); + CloseEventLog(handle); + Sleep(2000); + + handle = OpenEventLogA(NULL, eventlogname); + count = 0xdeadbeef; + GetNumberOfEventLogRecords(handle, &count); + if (count != 0) + { + win_skip("We didn't open our new eventlog\n"); + HeapFree(GetProcessHeap(), 0, user); + CloseEventLog(handle); + return; + } + } SetLastError(0xdeadbeef); ret = ReportEvent(handle, 0x20, 0, 0, NULL, 0, 0, NULL, NULL); @@ -735,12 +769,38 @@ static void test_readwrite(void) win_skip("Win7 fails when using incorrect event types\n"); ret = ReportEvent(handle, 0, 0, 0, NULL, 0, 0, NULL, NULL); } + else + { + void *buf; + DWORD read, needed; + EVENTLOGRECORD *record; + + /* Needed to catch earlier Vista (with no ServicePack for example) */ + buf = HeapAlloc(GetProcessHeap(), 0, sizeof(EVENTLOGRECORD)); + ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ, + 0, buf, sizeof(EVENTLOGRECORD), &read, &needed); + + buf = HeapReAlloc(GetProcessHeap(), 0, buf, needed); + ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ, + 0, buf, needed, &read, &needed); + + record = (EVENTLOGRECORD *)buf; + + /* Vista and W2K8 return EVENTLOG_SUCCESS, Windows versions before return + * the written eventtype (0x20 in this case). + */ + if (record->EventType == EVENTLOG_SUCCESS) + on_vista = TRUE; + + HeapFree(GetProcessHeap(), 0, buf); + } ok(ret, "Expected success : %d\n", GetLastError()); /* This will clear the eventlog. The record numbering for new - * events however differs on Vista+. Before Vista the first - * event would be numbered 1, on Vista+ it's now 2 as we already - * had one event. + * events however differs on Vista SP1+. Before Vista the first + * event would be numbered 1, on Vista SP1+ it's higher as we already + * had at least one event (more in case of multiple test runs without + * a reboot). */ ClearEventLogA(handle, NULL); CloseEventLog(handle); @@ -772,9 +832,9 @@ static void test_readwrite(void) ret = GetOldestEventLogRecord(handle, &oldest); ok(ret, "Expected success\n"); ok(oldest == 1 || - oldest == 2, /* Vista+ */ - "Expected oldest to be 1 or 2, got %d\n", oldest); - if (oldest == 2) + (oldest > 1 && oldest != 0xdeadbeef), /* Vista SP1+, W2K8 and Win7 */ + "Expected oldest to be 1 or higher, got %d\n", oldest); + if (oldest > 1 && oldest != 0xdeadbeef) on_vista = TRUE; if (i % 2) @@ -799,7 +859,7 @@ static void test_readwrite(void) /* Report only once */ if (on_vista) - skip("There is no DWORD alignment for UserSid on Vista or higher\n"); + skip("There is no DWORD alignment enforced for UserSid on Vista, W2K8 or Win7\n"); /* Read all events from our created eventlog, one by one */ handle = OpenEventLogA(NULL, eventlogname); @@ -839,8 +899,8 @@ static void test_readwrite(void) ok(record->Reserved == 0x654c664c, "Expected 0x654c664c, got %d\n", record->Reserved); ok(record->RecordNumber == i + 1 || - (on_vista && (record->RecordNumber == i + 2)), - "Expected %d or %d, got %d\n", i + 1, i + 2, record->RecordNumber); + (on_vista && (record->RecordNumber > i + 1)), + "Expected %d or higher, got %d\n", i + 1, record->RecordNumber); ok(record->EventID == read_write[i].evt_id, "Expected %d, got %d\n", read_write[i].evt_id, record->EventID); ok(record->EventType == read_write[i].evt_type, @@ -870,7 +930,7 @@ static void test_readwrite(void) /* We are already DWORD aligned, there should still be some padding */ if ((((UINT_PTR)buf + calculated_sidoffset) % sizeof(DWORD)) == 0) - ok(*(DWORD_PTR *)((BYTE *)buf + calculated_sidoffset) == 0, "Expected 0\n"); + ok(*(DWORD *)((BYTE *)buf + calculated_sidoffset) == 0, "Expected 0\n"); ok((((UINT_PTR)buf + record->UserSidOffset) % sizeof(DWORD)) == 0, "Expected DWORD alignment\n"); } @@ -894,7 +954,7 @@ static void test_readwrite(void) ptr += lstrlenA(ptr) + 1; } - ok(record->Length == *(DWORD_PTR *)((BYTE *)buf + record->Length - sizeof(DWORD)), + ok(record->Length == *(DWORD *)((BYTE *)buf + record->Length - sizeof(DWORD)), "Expected the closing DWORD to contain the length of the record\n"); HeapFree(GetProcessHeap(), 0, buf); @@ -945,6 +1005,7 @@ static void test_autocreation(void) char *p; char sources[sizeof(eventsources)]; char sysdir[MAX_PATH]; + void *redir = 0; RegOpenKeyA(HKEY_LOCAL_MACHINE, eventlogsvc, &key); RegOpenKeyA(key, eventlogname, &eventkey); @@ -968,12 +1029,17 @@ static void test_autocreation(void) } lstrcpyA(p, eventlogname); - ok(!memcmp(sources, sources_verify, size), "Expected a correct 'Sources' value\n"); + ok(!memcmp(sources, sources_verify, size), + "Expected a correct 'Sources' value (size : %d)\n", size); } RegCloseKey(eventkey); RegCloseKey(key); + /* The directory that holds the eventlog files could be redirected */ + if (pWow64DisableWow64FsRedirection) + pWow64DisableWow64FsRedirection(&redir); + /* On Windows we also automatically get an eventlog file */ GetSystemDirectoryA(sysdir, sizeof(sysdir)); @@ -994,6 +1060,9 @@ static void test_autocreation(void) ok(GetFileAttributesA(eventlogfile) != INVALID_FILE_ATTRIBUTES, "Expected an eventlog file\n"); + + if (pWow64RevertWow64FsRedirection) + pWow64RevertWow64FsRedirection(redir); } static void cleanup_eventlog(void) diff --git a/dlls/advapi32/tests/registry.c b/dlls/advapi32/tests/registry.c index abc2eb4aeb6..dee7664ce27 100644 --- a/dlls/advapi32/tests/registry.c +++ b/dlls/advapi32/tests/registry.c @@ -956,6 +956,28 @@ static void test_reg_create_key(void) /* clean up */ RegDeleteKey(hkey2, ""); RegDeleteKey(hkey1, ""); + RegCloseKey(hkey2); + RegCloseKey(hkey1); + + /* test creation of volatile keys */ + ret = RegCreateKeyExA(hkey_main, "Volatile", 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey1, NULL); + ok(!ret, "RegCreateKeyExA failed with error %d\n", ret); + ret = RegCreateKeyExA(hkey1, "Subkey2", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey2, NULL); + ok(ret == ERROR_CHILD_MUST_BE_VOLATILE || broken(!ret), /* win9x */ + "RegCreateKeyExA failed with error %d\n", ret); + if (!ret) RegCloseKey( hkey2 ); + ret = RegCreateKeyExA(hkey1, "Subkey2", 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey2, NULL); + ok(!ret, "RegCreateKeyExA failed with error %d\n", ret); + RegCloseKey(hkey2); + /* should succeed if the key already exists */ + ret = RegCreateKeyExA(hkey1, "Subkey2", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey2, NULL); + ok(!ret, "RegCreateKeyExA failed with error %d\n", ret); + + /* clean up */ + RegDeleteKey(hkey2, ""); + RegDeleteKey(hkey1, ""); + RegCloseKey(hkey2); + RegCloseKey(hkey1); /* beginning backslash character */ ret = RegCreateKeyExA(hkey_main, "\\Subkey3", 0, NULL, 0, KEY_NOTIFY, NULL, &hkey1, NULL); @@ -964,6 +986,7 @@ static void test_reg_create_key(void) else { ok(!ret, "RegCreateKeyExA failed with error %d\n", ret); RegDeleteKey(hkey1, NULL); + RegCloseKey(hkey1); } /* WOW64 flags - open an existing key */ diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c index b71d64f6837..470164a6006 100644 --- a/dlls/advapi32/tests/security.c +++ b/dlls/advapi32/tests/security.c @@ -1228,10 +1228,18 @@ static void test_token_attr(void) ok(ret, "OpenProcessToken failed with error %d\n", GetLastError()); /* groups */ + SetLastError(0xdeadbeef); ret = GetTokenInformation(Token, TokenGroups, NULL, 0, &Size); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "GetTokenInformation(TokenGroups) %s with error %d\n", + ret ? "succeeded" : "failed", GetLastError()); Groups = HeapAlloc(GetProcessHeap(), 0, Size); + SetLastError(0xdeadbeef); ret = GetTokenInformation(Token, TokenGroups, Groups, Size, &Size); ok(ret, "GetTokenInformation(TokenGroups) failed with error %d\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, + "GetTokenInformation shouldn't have set last error to %d\n", + GetLastError()); trace("TokenGroups:\n"); for (i = 0; i < Groups->GroupCount; i++) { @@ -3148,8 +3156,10 @@ static void test_GetSecurityInfo(void) ok(sd != NULL, "GetSecurityInfo\n"); ok(owner != NULL, "GetSecurityInfo\n"); ok(group != NULL, "GetSecurityInfo\n"); - ok(dacl != NULL, "GetSecurityInfo\n"); - ok(IsValidAcl(dacl), "GetSecurityInfo\n"); + if (dacl != NULL) + ok(IsValidAcl(dacl), "GetSecurityInfo\n"); + else + win_skip("No ACL information returned\n"); LocalFree(sd); @@ -3168,8 +3178,10 @@ static void test_GetSecurityInfo(void) ok(ret == ERROR_SUCCESS, "GetSecurityInfo returned %d\n", ret); ok(owner != NULL, "GetSecurityInfo\n"); ok(group != NULL, "GetSecurityInfo\n"); - ok(dacl != NULL, "GetSecurityInfo\n"); - ok(IsValidAcl(dacl), "GetSecurityInfo\n"); + if (dacl != NULL) + ok(IsValidAcl(dacl), "GetSecurityInfo\n"); + else + win_skip("No ACL information returned\n"); CloseHandle(obj); } @@ -3266,6 +3278,71 @@ todo_wine { CloseHandle(process_token); } +static void test_EqualSid(void) +{ + PSID sid1, sid2; + BOOL ret; + SID_IDENTIFIER_AUTHORITY SIDAuthWorld = { SECURITY_WORLD_SID_AUTHORITY }; + SID_IDENTIFIER_AUTHORITY SIDAuthNT = { SECURITY_NT_AUTHORITY }; + + SetLastError(0xdeadbeef); + ret = AllocateAndInitializeSid(&SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &sid1); + if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("AllocateAndInitializeSid is not implemented\n"); + return; + } + ok(ret, "AllocateAndInitializeSid failed with error %d\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, + "AllocateAndInitializeSid shouldn't have set last error to %d\n", + GetLastError()); + + ret = AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, + 0, 0, 0, 0, 0, 0, 0, &sid2); + ok(ret, "AllocateAndInitializeSid failed with error %d\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = EqualSid(sid1, sid2); + ok(!ret, "World and domain admins sids shouldn't have been equal\n"); + ok(GetLastError() == ERROR_SUCCESS || + broken(GetLastError() == 0xdeadbeef), /* NT4 */ + "EqualSid should have set last error to ERROR_SUCCESS instead of %d\n", + GetLastError()); + + SetLastError(0xdeadbeef); + sid2 = FreeSid(sid2); + ok(!sid2, "FreeSid should have returned NULL instead of %p\n", sid2); + ok(GetLastError() == 0xdeadbeef, + "FreeSid shouldn't have set last error to %d\n", + GetLastError()); + + ret = AllocateAndInitializeSid(&SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &sid2); + ok(ret, "AllocateAndInitializeSid failed with error %d\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = EqualSid(sid1, sid2); + ok(ret, "Same sids should have been equal\n"); + ok(GetLastError() == ERROR_SUCCESS || + broken(GetLastError() == 0xdeadbeef), /* NT4 */ + "EqualSid should have set last error to ERROR_SUCCESS instead of %d\n", + GetLastError()); + + ((SID *)sid2)->Revision = 2; + SetLastError(0xdeadbeef); + ret = EqualSid(sid1, sid2); + ok(!ret, "EqualSid with invalid sid should have returned FALSE\n"); + ok(GetLastError() == ERROR_SUCCESS || + broken(GetLastError() == 0xdeadbeef), /* NT4 */ + "EqualSid should have set last error to ERROR_SUCCESS instead of %d\n", + GetLastError()); + ((SID *)sid2)->Revision = SID_REVISION; + + FreeSid(sid1); + FreeSid(sid2); +} + START_TEST(security) { init(); @@ -3297,4 +3374,5 @@ START_TEST(security) test_GetSecurityInfo(); test_GetSidSubAuthority(); test_CheckTokenMembership(); + test_EqualSid(); } diff --git a/dlls/avrt/main.c b/dlls/avrt/main.c index c4e53dd2d76..4552c6ffba8 100644 --- a/dlls/avrt/main.c +++ b/dlls/avrt/main.c @@ -55,7 +55,7 @@ HANDLE WINAPI AvSetMmThreadCharacteristicsA(LPCSTR TaskName, LPDWORD TaskIndex) if (TaskName) { DWORD len = (lstrlenA(TaskName)+1); - str = HeapAlloc(GetProcessHeap, 0, len*sizeof(WCHAR)); + str = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); if (!str) { SetLastError(ERROR_OUTOFMEMORY); diff --git a/dlls/comctl32/imagelist.c b/dlls/comctl32/imagelist.c index 82d2664b4af..9f310c302f9 100644 --- a/dlls/comctl32/imagelist.c +++ b/dlls/comctl32/imagelist.c @@ -81,11 +81,7 @@ static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0 }; static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count, UINT width); static HRESULT ImageListImpl_CreateInstance(const IUnknown *pUnkOuter, REFIID iid, void** ppv); - -static inline BOOL is_valid(HIMAGELIST himl) -{ - return himl && himl->magic == IMAGELIST_MAGIC; -} +static inline BOOL is_valid(HIMAGELIST himl); /* * An imagelist with N images is tiled like this: @@ -607,7 +603,6 @@ ImageList_Create (INT cx, INT cy, UINT flags, cGrow = (cGrow < 4) ? 4 : (cGrow + 3) & ~3; - himl->magic = IMAGELIST_MAGIC; himl->cx = cx; himl->cy = cy; himl->flags = flags; @@ -673,7 +668,7 @@ ImageList_Create (INT cx, INT cy, UINT flags, return himl; cleanup: - if (himl) ImageList_Destroy(himl); + ImageList_Destroy(himl); return NULL; } @@ -697,25 +692,6 @@ ImageList_Destroy (HIMAGELIST himl) if (!is_valid(himl)) return FALSE; - /* delete image bitmaps */ - if (himl->hbmImage) - DeleteObject (himl->hbmImage); - if (himl->hbmMask) - DeleteObject (himl->hbmMask); - - /* delete image & mask DCs */ - if (himl->hdcImage) - DeleteDC(himl->hdcImage); - if (himl->hdcMask) - DeleteDC(himl->hdcMask); - - /* delete blending brushes */ - if (himl->hbrBlend25) - DeleteObject (himl->hbrBlend25); - if (himl->hbrBlend50) - DeleteObject (himl->hbrBlend50); - - /* Free the IImageList instance */ IImageList_Release((IImageList *) himl); return TRUE; } @@ -2977,7 +2953,22 @@ static ULONG WINAPI ImageListImpl_Release(IImageList *iface) TRACE("(%p) refcount=%u\n", iface, ref); if (ref == 0) + { + /* delete image bitmaps */ + if (This->hbmImage) DeleteObject (This->hbmImage); + if (This->hbmMask) DeleteObject (This->hbmMask); + + /* delete image & mask DCs */ + if (This->hdcImage) DeleteDC (This->hdcImage); + if (This->hdcMask) DeleteDC (This->hdcMask); + + /* delete blending brushes */ + if (This->hbrBlend25) DeleteObject (This->hbrBlend25); + if (This->hbrBlend50) DeleteObject (This->hbrBlend50); + + This->lpVtbl = NULL; HeapFree(GetProcessHeap(), 0, This); + } return ref; } @@ -2985,185 +2976,323 @@ static ULONG WINAPI ImageListImpl_Release(IImageList *iface) static HRESULT WINAPI ImageListImpl_Add(IImageList *iface, HBITMAP hbmImage, HBITMAP hbmMask, int *pi) { - FIXME("STUB: %p %p %p %p\n", iface, hbmImage, hbmMask, pi); - return E_NOTIMPL; + HIMAGELIST This = (HIMAGELIST) iface; + int ret; + + if (!pi) + return E_FAIL; + + ret = ImageList_Add(This, hbmImage, hbmMask); + + if (ret == -1) + return E_FAIL; + + *pi = ret; + return S_OK; } static HRESULT WINAPI ImageListImpl_ReplaceIcon(IImageList *iface, int i, HICON hicon, int *pi) { - FIXME("STUB: %p %d %p %p\n", iface, i, hicon, pi); - return E_NOTIMPL; + HIMAGELIST This = (HIMAGELIST) iface; + int ret; + + if (!pi) + return E_FAIL; + + ret = ImageList_ReplaceIcon(This, i, hicon); + + if (ret == -1) + return E_FAIL; + + *pi = ret; + return S_OK; } static HRESULT WINAPI ImageListImpl_SetOverlayImage(IImageList *iface, int iImage, int iOverlay) { - FIXME("STUB: %p %d %d\n", iface, iImage, iOverlay); - return E_NOTIMPL; + return ImageList_SetOverlayImage((HIMAGELIST) iface, iImage, iOverlay) + ? S_OK : E_FAIL; } static HRESULT WINAPI ImageListImpl_Replace(IImageList *iface, int i, HBITMAP hbmImage, HBITMAP hbmMask) { - FIXME("STUB: %p %d %p %p\n", iface, i, hbmImage, hbmMask); - return E_NOTIMPL; + return ImageList_Replace((HIMAGELIST) iface, i, hbmImage, hbmMask) ? S_OK : + E_FAIL; } static HRESULT WINAPI ImageListImpl_AddMasked(IImageList *iface, HBITMAP hbmImage, COLORREF crMask, int *pi) { - FIXME("STUB: %p %p %x %p\n", iface, hbmImage, crMask, pi); - return E_NOTIMPL; + HIMAGELIST This = (HIMAGELIST) iface; + int ret; + + if (!pi) + return E_FAIL; + + ret = ImageList_AddMasked(This, hbmImage, crMask); + + if (ret == -1) + return E_FAIL; + + *pi = ret; + return S_OK; } static HRESULT WINAPI ImageListImpl_Draw(IImageList *iface, IMAGELISTDRAWPARAMS *pimldp) { - FIXME("STUB: %p %p\n", iface, pimldp); - return E_NOTIMPL; + HIMAGELIST This = (HIMAGELIST) iface; + HIMAGELIST old_himl = 0; + int ret = 0; + + if (!pimldp) + return E_FAIL; + + /* As far as I can tell, Windows simply ignores the contents of pimldp->himl + so we shall simulate the same */ + old_himl = pimldp->himl; + pimldp->himl = This; + + ret = ImageList_DrawIndirect(pimldp); + + pimldp->himl = old_himl; + return ret ? S_OK : E_FAIL; } static HRESULT WINAPI ImageListImpl_Remove(IImageList *iface, int i) { - FIXME("STUB: %p %d\n", iface, i); - return E_NOTIMPL; + return (ImageList_Remove((HIMAGELIST) iface, i) == 0) ? E_FAIL : S_OK; } static HRESULT WINAPI ImageListImpl_GetIcon(IImageList *iface, int i, UINT flags, HICON *picon) { - FIXME("STUB: %p %d %x %p\n", iface, i, flags, picon); - return E_NOTIMPL; + HICON hIcon; + + if (!picon) + return E_FAIL; + + hIcon = ImageList_GetIcon((HIMAGELIST) iface, i, flags); + + if (hIcon == NULL) + return E_FAIL; + + *picon = hIcon; + return S_OK; } static HRESULT WINAPI ImageListImpl_GetImageInfo(IImageList *iface, int i, IMAGEINFO *pImageInfo) { - FIXME("STUB: %p %d %p\n", iface, i, pImageInfo); - return E_NOTIMPL; + return ImageList_GetImageInfo((HIMAGELIST) iface, i, pImageInfo) ? S_OK : E_FAIL; } static HRESULT WINAPI ImageListImpl_Copy(IImageList *iface, int iDst, IUnknown *punkSrc, int iSrc, UINT uFlags) { - FIXME("STUB: %p %d %p %d %x\n", iface, iDst, punkSrc, iSrc, uFlags); - return E_NOTIMPL; + HIMAGELIST This = (HIMAGELIST) iface; + IImageList *src = NULL; + HRESULT ret; + + if (!punkSrc) + return E_FAIL; + + /* TODO: Add test for IID_ImageList2 too */ + if (!SUCCEEDED(IImageList_QueryInterface(punkSrc, &IID_IImageList, + (void **) &src))) + return E_FAIL; + + if (ImageList_Copy(This, iDst, (HIMAGELIST) src, iSrc, uFlags)) + ret = S_OK; + else + ret = E_FAIL; + + IImageList_Release(src); + return ret; } static HRESULT WINAPI ImageListImpl_Merge(IImageList *iface, int i1, IUnknown *punk2, int i2, int dx, int dy, REFIID riid, PVOID *ppv) { - FIXME("STUB: %p %d %p %d %d %d %s %p\n", iface, i1, punk2, i2, dx, dy, - debugstr_guid(riid), ppv); - return E_NOTIMPL; + HIMAGELIST This = (HIMAGELIST) iface; + IImageList *iml2 = NULL; + HIMAGELIST hNew; + HRESULT ret = E_FAIL; + + if (!punk2 || !ppv) + return E_FAIL; + + /* TODO: Add test for IID_ImageList2 too */ + if (!SUCCEEDED(IImageList_QueryInterface(punk2, &IID_IImageList, + (void **) &iml2))) + return E_FAIL; + + hNew = ImageList_Merge(This, i1, (HIMAGELIST) iml2, i2, dx, dy); + + /* Get the interface for the new image list */ + if (hNew) + ret = HIMAGELIST_QueryInterface(hNew, riid, ppv); + + IImageList_Release(iml2); + return ret; } static HRESULT WINAPI ImageListImpl_Clone(IImageList *iface, REFIID riid, PVOID *ppv) { - FIXME("STUB: %p %s %p\n", iface, debugstr_guid(riid), ppv); - return E_NOTIMPL; + HIMAGELIST This = (HIMAGELIST) iface; + HIMAGELIST hNew; + HRESULT ret = E_FAIL; + + if (!ppv) + return E_FAIL; + + hNew = ImageList_Duplicate(This); + + /* Get the interface for the new image list */ + if (hNew) + ret = HIMAGELIST_QueryInterface(hNew, riid, ppv); + + return ret; } static HRESULT WINAPI ImageListImpl_GetImageRect(IImageList *iface, int i, RECT *prc) { - FIXME("STUB: %p %d %p\n", iface, i, prc); - return E_NOTIMPL; + HIMAGELIST This = (HIMAGELIST) iface; + IMAGEINFO info; + + if (!prc) + return E_FAIL; + + if (!ImageList_GetImageInfo(This, i, &info)) + return E_FAIL; + + return CopyRect(prc, &info.rcImage) ? S_OK : E_FAIL; } static HRESULT WINAPI ImageListImpl_GetIconSize(IImageList *iface, int *cx, int *cy) { - FIXME("STUB: %p %p %p\n", iface, cx, cy); - return E_NOTIMPL; + HIMAGELIST This = (HIMAGELIST) iface; + + return ImageList_GetIconSize(This, cx, cy) ? S_OK : E_FAIL; } static HRESULT WINAPI ImageListImpl_SetIconSize(IImageList *iface, int cx, int cy) { - FIXME("STUB: %p %d %d\n", iface, cx, cy); - return E_NOTIMPL; + return ImageList_SetIconSize((HIMAGELIST) iface, cx, cy) ? S_OK : E_FAIL; } static HRESULT WINAPI ImageListImpl_GetImageCount(IImageList *iface, int *pi) { - FIXME("STUB: %p %p\n", iface, pi); - return E_NOTIMPL; + if (!pi) + return E_FAIL; + + *pi = ImageList_GetImageCount((HIMAGELIST) iface); + return S_OK; } static HRESULT WINAPI ImageListImpl_SetImageCount(IImageList *iface, UINT uNewCount) { - FIXME("STUB: %p %d\n", iface, uNewCount); - return E_NOTIMPL; + return ImageList_SetImageCount((HIMAGELIST) iface, uNewCount) ? S_OK : E_FAIL; } static HRESULT WINAPI ImageListImpl_SetBkColor(IImageList *iface, COLORREF clrBk, COLORREF *pclr) { - FIXME("STUB: %p %x %p\n", iface, clrBk, pclr); - return E_NOTIMPL; + if (!pclr) + return E_FAIL; + + *pclr = ImageList_SetBkColor((HIMAGELIST) iface, clrBk); + return *pclr == CLR_NONE ? E_FAIL : S_OK; } static HRESULT WINAPI ImageListImpl_GetBkColor(IImageList *iface, COLORREF *pclr) { - FIXME("STUB: %p %p\n", iface, pclr); - return E_NOTIMPL; + if (!pclr) + return E_FAIL; + + *pclr = ImageList_GetBkColor((HIMAGELIST) iface); + return S_OK; } static HRESULT WINAPI ImageListImpl_BeginDrag(IImageList *iface, int iTrack, int dxHotspot, int dyHotspot) { - FIXME("STUB: %p %d %d %d\n", iface, iTrack, dxHotspot, dyHotspot); - return E_NOTIMPL; + return ImageList_BeginDrag((HIMAGELIST) iface, iTrack, dxHotspot, dyHotspot) ? S_OK : E_FAIL; } static HRESULT WINAPI ImageListImpl_EndDrag(IImageList *iface) { - FIXME("STUB: %p\n", iface); - return E_NOTIMPL; + ImageList_EndDrag(); + return S_OK; } static HRESULT WINAPI ImageListImpl_DragEnter(IImageList *iface, HWND hwndLock, int x, int y) { - FIXME("STUB: %p %p %d %d\n", iface, hwndLock, x, y); - return E_NOTIMPL; + return ImageList_DragEnter(hwndLock, x, y) ? S_OK : E_FAIL; } static HRESULT WINAPI ImageListImpl_DragLeave(IImageList *iface, HWND hwndLock) { - FIXME("STUB: %p %p\n", iface, hwndLock); - return E_NOTIMPL; + return ImageList_DragLeave(hwndLock) ? S_OK : E_FAIL; } static HRESULT WINAPI ImageListImpl_DragMove(IImageList *iface, int x, int y) { - FIXME("STUB: %p %d %d\n", iface, x, y); - return E_NOTIMPL; + return ImageList_DragMove(x, y) ? S_OK : E_FAIL; } static HRESULT WINAPI ImageListImpl_SetDragCursorImage(IImageList *iface, IUnknown *punk, int iDrag, int dxHotspot, int dyHotspot) { - FIXME("STUB: %p %p %d %d %d\n", iface, punk, iDrag, dxHotspot, dyHotspot); - return E_NOTIMPL; + IImageList *iml2 = NULL; + HRESULT ret; + + if (!punk) + return E_FAIL; + + /* TODO: Add test for IID_ImageList2 too */ + if (!SUCCEEDED(IImageList_QueryInterface(punk, &IID_IImageList, + (void **) &iml2))) + return E_FAIL; + + ret = ImageList_SetDragCursorImage((HIMAGELIST) iml2, iDrag, dxHotspot, + dyHotspot); + + IImageList_Release(iml2); + + return ret ? S_OK : E_FAIL; } static HRESULT WINAPI ImageListImpl_DragShowNolock(IImageList *iface, BOOL fShow) { - FIXME("STUB: %p %d\n", iface, fShow); - return E_NOTIMPL; + return ImageList_DragShowNolock(fShow) ? S_OK : E_FAIL; } static HRESULT WINAPI ImageListImpl_GetDragImage(IImageList *iface, POINT *ppt, POINT *pptHotspot, REFIID riid, PVOID *ppv) { - FIXME("STUB: %p %p %p %s %p\n", iface, ppt, pptHotspot, debugstr_guid(riid), - ppv); - return E_NOTIMPL; + HRESULT ret = E_FAIL; + HIMAGELIST hNew; + + if (!ppv) + return E_FAIL; + + hNew = ImageList_GetDragImage(ppt, pptHotspot); + + /* Get the interface for the new image list */ + if (hNew) + ret = HIMAGELIST_QueryInterface(hNew, riid, ppv); + + return ret; } static HRESULT WINAPI ImageListImpl_GetItemFlags(IImageList *iface, int i, @@ -3176,8 +3305,22 @@ static HRESULT WINAPI ImageListImpl_GetItemFlags(IImageList *iface, int i, static HRESULT WINAPI ImageListImpl_GetOverlayImage(IImageList *iface, int iOverlay, int *piIndex) { - FIXME("STUB: %p %d %p\n", iface, iOverlay, piIndex); - return E_NOTIMPL; + HIMAGELIST This = (HIMAGELIST) iface; + int i; + + if ((iOverlay < 0) || (iOverlay > This->cCurImage)) + return E_FAIL; + + for (i = 0; i < MAX_OVERLAYIMAGE; i++) + { + if (This->nOvlIdx[i] == iOverlay) + { + *piIndex = i + 1; + return S_OK; + } + } + + return E_FAIL; } @@ -3216,6 +3359,11 @@ static const IImageListVtbl ImageListImpl_Vtbl = { ImageListImpl_GetOverlayImage }; +static inline BOOL is_valid(HIMAGELIST himl) +{ + return himl && himl->lpVtbl == &ImageListImpl_Vtbl; +} + /************************************************************************* * HIMAGELIST_QueryInterface [COMCTL32.@] * diff --git a/dlls/comctl32/imagelist.h b/dlls/comctl32/imagelist.h index efcd1b086a7..a979ebf3de9 100644 --- a/dlls/comctl32/imagelist.h +++ b/dlls/comctl32/imagelist.h @@ -30,31 +30,31 @@ struct _IMAGELIST { const struct IImageListVtbl *lpVtbl; /* 00: IImageList vtable */ - LONG ref; /* 04: reference count */ - DWORD magic; /* 08: 'SAMX' */ - INT cCurImage; /* 0C: ImageCount */ - INT cMaxImage; /* 10: maximages */ - INT cGrow; /* 14: cGrow */ - INT cx; /* 18: cx */ - INT cy; /* 1C: cy */ + INT cCurImage; /* 04: ImageCount */ + INT cMaxImage; /* 08: maximages */ + INT cGrow; /* 0C: cGrow */ + INT cx; /* 10: cx */ + INT cy; /* 14: cy */ DWORD x4; - UINT flags; /* 24: flags */ - COLORREF clrFg; /* 28: foreground color */ - COLORREF clrBk; /* 2C: background color */ + UINT flags; /* 1C: flags */ + COLORREF clrFg; /* 20: foreground color */ + COLORREF clrBk; /* 24: background color */ - HBITMAP hbmImage; /* 30: images Bitmap */ - HBITMAP hbmMask; /* 34: masks Bitmap */ - HDC hdcImage; /* 38: images MemDC */ - HDC hdcMask; /* 3C: masks MemDC */ - INT nOvlIdx[15]; /* 40: overlay images index */ + HBITMAP hbmImage; /* 28: images Bitmap */ + HBITMAP hbmMask; /* 2C: masks Bitmap */ + HDC hdcImage; /* 30: images MemDC */ + HDC hdcMask; /* 34: masks MemDC */ + INT nOvlIdx[15]; /* 38: overlay images index */ /* not yet found out */ HBRUSH hbrBlend25; HBRUSH hbrBlend50; INT cInitial; UINT uBitsPixel; + + LONG ref; /* reference count */ }; #define IMAGELIST_MAGIC 0x53414D58 diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c index ae658bd623c..5b45ffbf75c 100644 --- a/dlls/comctl32/listview.c +++ b/dlls/comctl32/listview.c @@ -237,86 +237,120 @@ typedef struct tagDELAYED_ITEM_EDIT typedef struct tagLISTVIEW_INFO { + /* control window */ HWND hwndSelf; - HBRUSH hBkBrush; - COLORREF clrBk; - COLORREF clrText; - COLORREF clrTextBk; - HIMAGELIST himlNormal; - HIMAGELIST himlSmall; - HIMAGELIST himlState; - BOOL bLButtonDown; - BOOL bRButtonDown; - BOOL bDragging; - BOOL bMarqueeSelect; /* marquee selection/highlight underway */ - BOOL bScrolling; - RECT marqueeRect; /* absolute coordinates of marquee selection */ - RECT marqueeDrawRect; /* relative coordinates for drawing marquee */ - POINT marqueeOrigin; /* absolute coordinates of marquee click origin */ - POINT ptClickPos; /* point where the user clicked */ - BOOL bNoItemMetrics; /* flags if item metrics are not yet computed */ - INT nItemHeight; - INT nItemWidth; - RANGES selectionRanges; - INT nSelectionMark; - INT nHotItem; - SHORT notifyFormat; - HWND hwndNotify; RECT rcList; /* This rectangle is really the window * client rectangle possibly reduced by the * horizontal scroll bar and/or header - see * LISTVIEW_UpdateSize. This rectangle offset * by the LISTVIEW_GetOrigin value is in * client coordinates */ - SIZE iconSize; - SIZE iconSpacing; - SIZE iconStateSize; - UINT uCallbackMask; - HWND hwndHeader; - HCURSOR hHotCursor; - HFONT hDefaultFont; - HFONT hFont; - INT ntmHeight; /* Some cached metrics of the font used */ - INT ntmMaxCharWidth; /* by the listview to draw items */ - INT nEllipsisWidth; - BOOL bRedraw; /* Turns on/off repaints & invalidations */ - BOOL bAutoarrange; /* Autoarrange flag when NOT in LVS_AUTOARRANGE */ - BOOL bFocus; + + /* notification window */ + SHORT notifyFormat; + HWND hwndNotify; BOOL bDoChangeNotify; /* send change notification messages? */ - INT nFocusedItem; - RECT rcFocus; - DWORD dwStyle; /* the cached window GWL_STYLE */ - DWORD dwLvExStyle; /* extended listview style */ - DWORD uView; /* current view available through LVM_[G,S]ETVIEW */ + UINT uCallbackMask; + + /* tooltips */ + HWND hwndToolTip; + + /* items */ INT nItemCount; /* the number of items in the list */ HDPA hdpaItems; /* array ITEM_INFO pointers */ HDPA hdpaItemIds; /* array of ITEM_ID pointers */ HDPA hdpaPosX; /* maintains the (X, Y) coordinates of the */ HDPA hdpaPosY; /* items in LVS_ICON, and LVS_SMALLICON modes */ + RANGES selectionRanges; + INT nSelectionMark; /* item to start next multiselection from */ + INT nHotItem; + BOOL bAutoarrange; /* Autoarrange flag when NOT in LVS_AUTOARRANGE */ + + /* columns */ HDPA hdpaColumns; /* array of COLUMN_INFO pointers */ BOOL colRectsDirty; /* trigger column rectangles requery from header */ - POINT currIconPos; /* this is the position next icon will be placed */ - PFNLVCOMPARE pfnCompare; + + /* item metrics */ + BOOL bNoItemMetrics; /* flags if item metrics are not yet computed */ + INT nItemHeight; + INT nItemWidth; + + /* sorting */ + PFNLVCOMPARE pfnCompare; /* sorting callback pointer */ LPARAM lParamSort; + + /* style */ + DWORD dwStyle; /* the cached window GWL_STYLE */ + DWORD dwLvExStyle; /* extended listview style */ + DWORD uView; /* current view available through LVM_[G,S]ETVIEW */ + + /* edit item */ HWND hwndEdit; WNDPROC EditWndProc; INT nEditLabelItem; - INT nLButtonDownItem; /* tracks item to reset multiselection on WM_LBUTTONUP */ - DWORD dwHoverTime; - HWND hwndToolTip; + DELAYED_ITEM_EDIT itemEdit; /* Pointer to this structure will be the timer ID */ - DWORD cditemmode; /* Keep the custom draw flags for an item/row */ + /* icons */ + HIMAGELIST himlNormal; + HIMAGELIST himlSmall; + HIMAGELIST himlState; + SIZE iconSize; + SIZE iconSpacing; + SIZE iconStateSize; + POINT currIconPos; /* this is the position next icon will be placed */ + + /* header */ + HWND hwndHeader; + INT xTrackLine; /* The x coefficient of the track line or -1 if none */ + + /* marquee selection */ + BOOL bMarqueeSelect; /* marquee selection/highlight underway */ + BOOL bScrolling; + RECT marqueeRect; /* absolute coordinates of marquee selection */ + RECT marqueeDrawRect; /* relative coordinates for drawing marquee */ + POINT marqueeOrigin; /* absolute coordinates of marquee click origin */ + /* focus drawing */ + BOOL bFocus; /* control has focus */ + INT nFocusedItem; + RECT rcFocus; /* focus bounds */ + + /* colors */ + HBRUSH hBkBrush; + COLORREF clrBk; + COLORREF clrText; + COLORREF clrTextBk; + + /* font */ + HFONT hDefaultFont; + HFONT hFont; + INT ntmHeight; /* Some cached metrics of the font used */ + INT ntmMaxCharWidth; /* by the listview to draw items */ + INT nEllipsisWidth; + + /* mouse operation */ + BOOL bLButtonDown; + BOOL bRButtonDown; + BOOL bDragging; + POINT ptClickPos; /* point where the user clicked */ + INT nLButtonDownItem; /* tracks item to reset multiselection on WM_LBUTTONUP */ + DWORD dwHoverTime; + HCURSOR hHotCursor; + + /* keyboard operation */ DWORD lastKeyPressTimestamp; WPARAM charCode; INT nSearchParamLength; WCHAR szSearchParam[ MAX_PATH ]; - BOOL bIsDrawing; - INT nMeasureItemHeight; - INT xTrackLine; /* The x coefficient of the track line or -1 if none */ - DELAYED_ITEM_EDIT itemEdit; /* Pointer to this structure will be the timer ID */ - DWORD iVersion; /* CCM_[G,S]ETVERSION */ + /* painting */ + DWORD cditemmode; /* Keep the custom draw flags for an item/row */ + BOOL bIsDrawing; /* Drawing in progress */ + INT nMeasureItemHeight; /* WM_MEASUREITEM result */ + BOOL bRedraw; /* WM_SETREDRAW switch */ + + /* misc */ + DWORD iVersion; /* CCM_[G,S]ETVERSION */ } LISTVIEW_INFO; /* @@ -5081,11 +5115,14 @@ static DWORD LISTVIEW_ApproximateViewRect(const LISTVIEW_INFO *infoPtr, INT nIte */ static LRESULT LISTVIEW_CancelEditLabel(LISTVIEW_INFO *infoPtr) { - /* handle value will be lost after LISTVIEW_EndEditLabelT */ - HWND edit = infoPtr->hwndEdit; + if (infoPtr->hwndEdit) + { + /* handle value will be lost after LISTVIEW_EndEditLabelT */ + HWND edit = infoPtr->hwndEdit; - LISTVIEW_EndEditLabelT(infoPtr, TRUE, IsWindowUnicode(infoPtr->hwndEdit)); - SendMessageW(edit, WM_CLOSE, 0, 0); + LISTVIEW_EndEditLabelT(infoPtr, TRUE, IsWindowUnicode(infoPtr->hwndEdit)); + SendMessageW(edit, WM_CLOSE, 0, 0); + } return TRUE; } @@ -5582,16 +5619,11 @@ static BOOL LISTVIEW_EndEditLabelT(LISTVIEW_INFO *infoPtr, BOOL storeText, BOOL bSame = (lstrcmpW(dispInfo.item.pszText, tmp) == 0); textfreeT(tmp, FALSE); } - if (bSame) - { - res = TRUE; - goto cleanup; - } /* add the text from the edit in */ dispInfo.item.mask |= LVIF_TEXT; - dispInfo.item.pszText = pszText; - dispInfo.item.cchTextMax = textlenT(pszText, isW); + dispInfo.item.pszText = bSame ? NULL : pszText; + dispInfo.item.cchTextMax = bSame ? 0 : textlenT(pszText, isW); /* Do we need to update the Item Text */ if (!notify_dispinfoT(infoPtr, LVN_ENDLABELEDITW, &dispInfo, isW)) @@ -5605,6 +5637,11 @@ static BOOL LISTVIEW_EndEditLabelT(LISTVIEW_INFO *infoPtr, BOOL storeText, BOOL goto cleanup; } if (!pszText) return TRUE; + if (bSame) + { + res = TRUE; + goto cleanup; + } if (!(infoPtr->dwStyle & LVS_OWNERDATA)) { @@ -5851,7 +5888,8 @@ static INT LISTVIEW_FindItemW(const LISTVIEW_INFO *infoPtr, INT nStart, if (!lpFindInfo || nItem < 0) return -1; lvItem.mask = 0; - if (lpFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL)) + if (lpFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL) || + lpFindInfo->flags & LVFI_SUBSTRING) { lvItem.mask |= LVIF_TEXT; lvItem.pszText = szDispText; @@ -5912,12 +5950,13 @@ again: else continue; } - + if (lvItem.mask & LVIF_TEXT) { - if (lpFindInfo->flags & LVFI_PARTIAL) + if (lpFindInfo->flags & (LVFI_PARTIAL | LVFI_SUBSTRING)) { - if (strstrW(lvItem.pszText, lpFindInfo->psz) == NULL) continue; + WCHAR *p = strstrW(lvItem.pszText, lpFindInfo->psz); + if (!p || p != lvItem.pszText) continue; } else { @@ -5926,7 +5965,7 @@ again: } if (!bNearest) return nItem; - + /* This is very inefficient. To do a good job here, * we need a sorted array of (x,y) item positions */ LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position); @@ -5971,7 +6010,8 @@ again: static INT LISTVIEW_FindItemA(const LISTVIEW_INFO *infoPtr, INT nStart, const LVFINDINFOA *lpFindInfo) { - BOOL hasText = lpFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL); + BOOL hasText = lpFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL) || + lpFindInfo->flags & LVFI_SUBSTRING; LVFINDINFOW fiw; INT res; LPWSTR strW = NULL; @@ -6168,8 +6208,13 @@ static HIMAGELIST LISTVIEW_GetImageList(const LISTVIEW_INFO *infoPtr, INT nImage switch (nImageList) { case LVSIL_NORMAL: return infoPtr->himlNormal; - case LVSIL_SMALL: return infoPtr->himlSmall; - case LVSIL_STATE: return infoPtr->himlState; + case LVSIL_SMALL: return infoPtr->himlSmall; + case LVSIL_STATE: return infoPtr->himlState; + case LVSIL_GROUPHEADER: + FIXME("LVSIL_GROUPHEADER not supported\n"); + break; + default: + WARN("got unknown imagelist index - %d\n", nImageList); } return NULL; } @@ -7395,7 +7440,7 @@ static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, hItem = DPA_GetPtr( infoPtr->hdpaItems, i); item_s = (ITEM_INFO*)DPA_GetPtr(hItem, 0); - cmpv = textcmpWT(item_s->hdr.pszText, lpLVItem->pszText, TRUE); + cmpv = textcmpWT(item_s->hdr.pszText, lpLVItem->pszText, isW); if (infoPtr->dwStyle & LVS_SORTDESCENDING) cmpv *= -1; if (cmpv >= 0) break; @@ -10986,10 +11031,8 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) /* case LVM_INSERTGROUPSORTED: */ case LVM_INSERTITEMA: - return LISTVIEW_InsertItemT(infoPtr, (LPLVITEMW)lParam, FALSE); - case LVM_INSERTITEMW: - return LISTVIEW_InsertItemT(infoPtr, (LPLVITEMW)lParam, TRUE); + return LISTVIEW_InsertItemT(infoPtr, (LPLVITEMW)lParam, uMsg == LVM_INSERTITEMW); /* case LVM_INSERTMARKHITTEST: */ @@ -11408,6 +11451,7 @@ static LRESULT LISTVIEW_Command(LISTVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lP case EN_KILLFOCUS: { LISTVIEW_CancelEditLabel(infoPtr); + break; } default: diff --git a/dlls/comctl32/tab.c b/dlls/comctl32/tab.c index 15534afb835..35985f8e130 100644 --- a/dlls/comctl32/tab.c +++ b/dlls/comctl32/tab.c @@ -247,16 +247,17 @@ static inline LRESULT TAB_SetCurSel (TAB_INFO *infoPtr, INT iItem) TRACE("(%p %d)\n", infoPtr, iItem); if (iItem < 0) - infoPtr->iSelected=-1; + infoPtr->iSelected = -1; else if (iItem >= infoPtr->uNumItem) return -1; else { - if (infoPtr->iSelected != iItem) { - TAB_GetItem(infoPtr, prevItem)->dwState &= ~TCIS_BUTTONPRESSED; + if (prevItem != iItem) { + if (prevItem != -1) + TAB_GetItem(infoPtr, prevItem)->dwState &= ~TCIS_BUTTONPRESSED; TAB_GetItem(infoPtr, iItem)->dwState |= TCIS_BUTTONPRESSED; - infoPtr->iSelected=iItem; - infoPtr->uFocus=iItem; + infoPtr->iSelected = iItem; + infoPtr->uFocus = iItem; TAB_EnsureSelectionVisible(infoPtr); TAB_InvalidateTabArea(infoPtr); } @@ -268,8 +269,14 @@ static LRESULT TAB_SetCurFocus (TAB_INFO *infoPtr, INT iItem) { TRACE("(%p %d)\n", infoPtr, iItem); - if (iItem < 0) + if (iItem < 0) { infoPtr->uFocus = -1; + if (infoPtr->iSelected != -1) { + infoPtr->iSelected = -1; + TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGE); + TAB_InvalidateTabArea(infoPtr); + } + } else if (iItem < infoPtr->uNumItem) { if (infoPtr->dwStyle & TCS_BUTTONS) { /* set focus to new item, leave selection as is */ @@ -2915,10 +2922,9 @@ static LRESULT TAB_DeleteItem (TAB_INFO *infoPtr, INT iItem) Free(oldItems); /* Readjust the selected index */ - if ((iItem == infoPtr->iSelected) && (iItem > 0)) - infoPtr->iSelected--; - - if (iItem < infoPtr->iSelected) + if (iItem == infoPtr->iSelected) + infoPtr->iSelected = -1; + else if (iItem < infoPtr->iSelected) infoPtr->iSelected--; if (infoPtr->uNumItem == 0) diff --git a/dlls/comctl32/tests/imagelist.c b/dlls/comctl32/tests/imagelist.c index d67252a4f2e..e06b9746805 100644 --- a/dlls/comctl32/tests/imagelist.c +++ b/dlls/comctl32/tests/imagelist.c @@ -336,7 +336,7 @@ static BOOL DoTest1(void) HICON hicon3 ; /* create an imagelist to play with */ - himl = ImageList_Create(84,84,0x10,0,3); + himl = ImageList_Create(84, 84, ILC_COLOR16, 0, 3); ok(himl!=0,"failed to create imagelist\n"); /* load the icons to add to the image list */ @@ -402,7 +402,7 @@ static BOOL DoTest2(void) HICON hicon3 ; /* create an imagelist to play with */ - himl = ImageList_Create(84,84,0x10,0,3); + himl = ImageList_Create(84, 84, ILC_COLOR16, 0, 3); ok(himl!=0,"failed to create imagelist\n"); /* load the icons to add to the image list */ @@ -451,7 +451,7 @@ static BOOL DoTest3(void) ok(hdc!=NULL, "couldn't get DC\n"); /* create an imagelist to play with */ - himl = ImageList_Create(48,48,0x10,0,3); + himl = ImageList_Create(48, 48, ILC_COLOR16, 0, 3); ok(himl!=0,"failed to create imagelist\n"); /* load the icons to add to the image list */ @@ -998,6 +998,7 @@ static void test_shell_imagelist(void) HRESULT hr; int out = 0; RECT rect; + int cx, cy; /* Try to load function from shell32 */ hShell32 = LoadLibrary("shell32.dll"); @@ -1010,21 +1011,23 @@ static void test_shell_imagelist(void) } /* Get system image list */ - hr = (pSHGetImageList)(SHIL_LARGE, &IID_IImageList, (void**)&iml); + hr = (pSHGetImageList)(SHIL_SYSSMALL, &IID_IImageList, (void**)&iml); - todo_wine ok(SUCCEEDED(hr), "SHGetImageList failed, hr=%x\n", hr); + ok(SUCCEEDED(hr), "SHGetImageList failed, hr=%x\n", hr); if (hr != S_OK) return; IImageList_GetImageCount(iml, &out); - todo_wine ok(out > 0, "IImageList_GetImageCount returned out <= 0\n"); + ok(out > 0, "IImageList_GetImageCount returned out <= 0\n"); - /* right and bottom should be 32x32 for large icons, or 48x48 if larger - icons enabled in control panel */ + /* Fetch the small icon size */ + cx = GetSystemMetrics(SM_CXSMICON); + cy = GetSystemMetrics(SM_CYSMICON); + + /* Check icon size matches */ IImageList_GetImageRect(iml, 0, &rect); - todo_wine ok((((rect.right == 32) && (rect.bottom == 32)) || - ((rect.right == 48) && (rect.bottom == 48))), + ok(((rect.right == cx) && (rect.bottom == cy)), "IImageList_GetImageRect returned r:%d,b:%d\n", rect.right, rect.bottom); @@ -1251,8 +1254,36 @@ static void test_iimagelist(void) IImageList *imgl; HIMAGELIST himl; HRESULT hr; + ULONG ret; - if (!pImageList_CoCreateInstance || !pHIMAGELIST_QueryInterface) + if (!pHIMAGELIST_QueryInterface) + { + win_skip("XP imagelist functions not available\n"); + return; + } + + /* test reference counting on destruction */ + imgl = (IImageList*)createImageList(32, 32); + ret = IUnknown_AddRef(imgl); + ok(ret == 2, "Expected 2, got %d\n", ret); + ret = ImageList_Destroy((HIMAGELIST)imgl); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); + ret = ImageList_Destroy((HIMAGELIST)imgl); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); + ret = ImageList_Destroy((HIMAGELIST)imgl); + ok(ret == FALSE, "Expected FALSE, got %d\n", ret); + + imgl = (IImageList*)createImageList(32, 32); + ret = IUnknown_AddRef(imgl); + ok(ret == 2, "Expected 2, got %d\n", ret); + ret = ImageList_Destroy((HIMAGELIST)imgl); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); + ret = IImageList_Release(imgl); + ok(ret == 0, "Expected 0, got %d\n", ret); + ret = ImageList_Destroy((HIMAGELIST)imgl); + ok(ret == FALSE, "Expected FALSE, got %d\n", ret); + + if (!pImageList_CoCreateInstance) { win_skip("Vista imagelist functions not available\n"); return; @@ -1278,6 +1309,309 @@ static void test_iimagelist(void) ImageList_Destroy(himl); } +static void testHotspot_v6(void) +{ + struct hotspot { + int dx; + int dy; + }; + +#define SIZEX1 47 +#define SIZEY1 31 +#define SIZEX2 11 +#define SIZEY2 17 +#define HOTSPOTS_MAX 4 /* Number of entries in hotspots */ + static const struct hotspot hotspots[HOTSPOTS_MAX] = { + { 10, 7 }, + { SIZEX1, SIZEY1 }, + { -9, -8 }, + { -7, 35 } + }; + int i, j; + HIMAGELIST himl1 = createImageList(SIZEX1, SIZEY1); + HIMAGELIST himl2 = createImageList(SIZEX2, SIZEY2); + IImageList *imgl1, *imgl2; + HRESULT hr; + + /* cast to IImageList */ + imgl1 = (IImageList *) himl1; + imgl2 = (IImageList *) himl2; + + for (i = 0; i < HOTSPOTS_MAX; i++) { + for (j = 0; j < HOTSPOTS_MAX; j++) { + int dx1 = hotspots[i].dx; + int dy1 = hotspots[i].dy; + int dx2 = hotspots[j].dx; + int dy2 = hotspots[j].dy; + int correctx, correcty, newx, newy; + char loc[256]; + IImageList *imglNew; + POINT ppt; + + hr = IImageList_BeginDrag(imgl1, 0, dx1, dy1); + ok(SUCCEEDED(hr), "BeginDrag failed for { %d, %d }\n", dx1, dy1); + sprintf(loc, "BeginDrag (%d,%d)\n", i, j); + + /* check merging the dragged image with a second image */ + hr = IImageList_SetDragCursorImage(imgl2, (IUnknown *) imgl2, 0, dx2, dy2); + ok(SUCCEEDED(hr), "SetDragCursorImage failed for {%d, %d}{%d, %d}\n", + dx1, dy1, dx2, dy2); + sprintf(loc, "SetDragCursorImage (%d,%d)\n", i, j); + + /* check new hotspot, it should be the same like the old one */ + hr = IImageList_GetDragImage(imgl2, NULL, &ppt, &IID_IImageList, (PVOID *) &imglNew); + ok(SUCCEEDED(hr), "GetDragImage failed\n"); + ok(ppt.x == dx1 && ppt.y == dy1, + "Expected drag hotspot [%d,%d] got [%d,%d]\n", + dx1, dy1, ppt.x, ppt.y); + /* check size of new dragged image */ + IImageList_GetIconSize(imglNew, &newx, &newy); + correctx = max(SIZEX1, max(SIZEX2 + dx2, SIZEX1 - dx2)); + correcty = max(SIZEY1, max(SIZEY2 + dy2, SIZEY1 - dy2)); + ok(newx == correctx && newy == correcty, + "Expected drag image size [%d,%d] got [%d,%d]\n", + correctx, correcty, newx, newy); + sprintf(loc, "GetDragImage (%d,%d)\n", i, j); + IImageList_EndDrag(imgl2); + } + } +#undef SIZEX1 +#undef SIZEY1 +#undef SIZEX2 +#undef SIZEY2 +#undef HOTSPOTS_MAX + IImageList_Release(imgl2); + IImageList_Release(imgl1); +} + +static void DoTest1_v6(void) +{ + IImageList *imgl; + HIMAGELIST himl; + HRESULT hr; + + HICON hicon1; + HICON hicon2; + HICON hicon3; + + int ret = 0; + + /* create an imagelist to play with */ + himl = ImageList_Create(84, 84, ILC_COLOR16, 0, 3); + ok(himl != 0,"failed to create imagelist\n"); + + imgl = (IImageList *) himl; + + /* load the icons to add to the image list */ + hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits); + ok(hicon1 != 0, "no hicon1\n"); + hicon2 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits); + ok(hicon2 != 0, "no hicon2\n"); + hicon3 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits); + ok(hicon3 != 0, "no hicon3\n"); + + /* remove when nothing exists */ + hr = IImageList_Remove(imgl, 0); + ok(!(SUCCEEDED(hr)), "removed nonexistent icon\n"); + + /* removing everything from an empty imagelist should succeed */ + hr = IImageList_Remove(imgl, -1); + ok(SUCCEEDED(hr), "removed nonexistent icon\n"); + + /* add three */ + ok(SUCCEEDED(IImageList_ReplaceIcon(imgl, -1, hicon1, &ret)) && (ret == 0),"failed to add icon1\n"); + ok(SUCCEEDED(IImageList_ReplaceIcon(imgl, -1, hicon2, &ret)) && (ret == 1),"failed to add icon2\n"); + ok(SUCCEEDED(IImageList_ReplaceIcon(imgl, -1, hicon3, &ret)) && (ret == 2),"failed to add icon3\n"); + + /* remove an index out of range */ + ok(!SUCCEEDED(IImageList_Remove(imgl,4711)),"removed nonexistent icon\n"); + + /* remove three */ + ok(SUCCEEDED(IImageList_Remove(imgl,0)),"can't remove 0\n"); + ok(SUCCEEDED(IImageList_Remove(imgl,0)),"can't remove 0\n"); + ok(SUCCEEDED(IImageList_Remove(imgl,0)),"can't remove 0\n"); + + /* remove one extra */ + ok(!SUCCEEDED(IImageList_Remove(imgl,0)),"removed nonexistent icon\n"); + + /* check SetImageCount/GetImageCount */ + ok(SUCCEEDED(IImageList_SetImageCount(imgl, 3)), "couldn't increase image count\n"); + ok(SUCCEEDED(IImageList_GetImageCount(imgl, &ret)) && (ret == 3), "invalid image count after increase\n"); + ok(SUCCEEDED(IImageList_SetImageCount(imgl, 1)), "couldn't decrease image count\n"); + ok(SUCCEEDED(IImageList_GetImageCount(imgl, &ret)) && (ret == 1), "invalid image count after decrease to 1\n"); + ok(SUCCEEDED(IImageList_SetImageCount(imgl, 0)), "couldn't decrease image count\n"); + ok(SUCCEEDED(IImageList_GetImageCount(imgl, &ret)) && (ret == 0), "invalid image count after decrease to 0\n"); + + /* destroy it */ + ok(SUCCEEDED(IImageList_Release(imgl)),"release imagelist failed\n"); + + ok(DestroyIcon(hicon1),"icon 1 wasn't deleted\n"); + ok(DestroyIcon(hicon2),"icon 2 wasn't deleted\n"); + ok(DestroyIcon(hicon3),"icon 3 wasn't deleted\n"); +} + +static void DoTest3_v6(void) +{ + IImageList *imgl; + HIMAGELIST himl; + + HBITMAP hbm1; + HBITMAP hbm2; + HBITMAP hbm3; + + IMAGELISTDRAWPARAMS imldp; + HWND hwndfortest; + HDC hdc; + int ret; + + hwndfortest = create_a_window(); + hdc = GetDC(hwndfortest); + ok(hdc!=NULL, "couldn't get DC\n"); + + /* create an imagelist to play with */ + himl = ImageList_Create(48, 48, ILC_COLOR16, 0, 3); + ok(himl!=0,"failed to create imagelist\n"); + + imgl = (IImageList *) himl; + + /* load the icons to add to the image list */ + hbm1 = CreateBitmap(48, 48, 1, 1, bitmap_bits); + ok(hbm1 != 0, "no bitmap 1\n"); + hbm2 = CreateBitmap(48, 48, 1, 1, bitmap_bits); + ok(hbm2 != 0, "no bitmap 2\n"); + hbm3 = CreateBitmap(48, 48, 1, 1, bitmap_bits); + ok(hbm3 != 0, "no bitmap 3\n"); + + /* add three */ + ok(SUCCEEDED(IImageList_Add(imgl, hbm1, 0, &ret)) && (ret == 0), "failed to add bitmap 1\n"); + ok(SUCCEEDED(IImageList_Add(imgl, hbm2, 0, &ret)) && (ret == 1), "failed to add bitmap 2\n"); + + ok(SUCCEEDED(IImageList_SetImageCount(imgl, 3)), "Setimage count failed\n"); + ok(SUCCEEDED(IImageList_Replace(imgl, 2, hbm3, 0)), "failed to replace bitmap 3\n"); + + memset(&imldp, 0, sizeof (imldp)); + ok(FAILED(IImageList_Draw(imgl, &imldp)), "zero data succeeded!\n"); + + imldp.cbSize = sizeof (imldp); + imldp.hdcDst = hdc; + imldp.himl = himl; + + if (FAILED(IImageList_Draw(imgl, &imldp))) + { + /* Earlier versions of native comctl32 use a smaller structure */ + imldp.cbSize -= 3 * sizeof(DWORD); + ok(SUCCEEDED(IImageList_Draw(imgl, &imldp)), "should succeed\n"); + } + + REDRAW(hwndfortest); + WAIT; + + imldp.fStyle = SRCCOPY; + imldp.rgbBk = CLR_DEFAULT; + imldp.rgbFg = CLR_DEFAULT; + imldp.y = 100; + imldp.x = 100; + ok(SUCCEEDED(IImageList_Draw(imgl, &imldp)), "should succeed\n"); + imldp.i ++; + ok(SUCCEEDED(IImageList_Draw(imgl, &imldp)), "should succeed\n"); + imldp.i ++; + ok(SUCCEEDED(IImageList_Draw(imgl, &imldp)), "should succeed\n"); + imldp.i ++; + ok(FAILED(IImageList_Draw(imgl, &imldp)), "should fail\n"); + + /* remove three */ + ok(SUCCEEDED(IImageList_Remove(imgl, 0)), "removing 1st bitmap\n"); + ok(SUCCEEDED(IImageList_Remove(imgl, 0)), "removing 2nd bitmap\n"); + ok(SUCCEEDED(IImageList_Remove(imgl, 0)), "removing 3rd bitmap\n"); + + /* destroy it */ + ok(SUCCEEDED(IImageList_Release(imgl)), "release imagelist failed\n"); + + /* bitmaps should not be deleted by the imagelist */ + ok(DeleteObject(hbm1),"bitmap 1 can't be deleted\n"); + ok(DeleteObject(hbm2),"bitmap 2 can't be deleted\n"); + ok(DeleteObject(hbm3),"bitmap 3 can't be deleted\n"); + + ReleaseDC(hwndfortest, hdc); + DestroyWindow(hwndfortest); +} + +static void testMerge_v6(void) +{ + HIMAGELIST himl1, himl2; + IImageList *imgl1, *imgl2, *merge; + HICON hicon1; + HWND hwnd = create_a_window(); + HRESULT hr; + int ret; + + himl1 = ImageList_Create(32,32,0,0,3); + ok(himl1 != NULL,"failed to create himl1\n"); + + himl2 = ImageList_Create(32,32,0,0,3); + ok(himl2 != NULL,"failed to create himl2\n"); + + hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits); + ok(hicon1 != NULL, "failed to create hicon1\n"); + + if (!himl1 || !himl2 || !hicon1) + return; + + /* cast to IImageList */ + imgl1 = (IImageList *) himl1; + imgl2 = (IImageList *) himl2; + + ok(SUCCEEDED(IImageList_ReplaceIcon(imgl2, -1, hicon1, &ret)) && (ret == 0),"add icon1 to himl2 failed\n"); + + /* If himl1 has no images, merge still succeeds */ + hr = IImageList_Merge(imgl1, -1, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge); + ok(SUCCEEDED(hr), "merge himl1,-1 failed\n"); + if (SUCCEEDED(hr)) IImageList_Release(merge); + + hr = IImageList_Merge(imgl1, 0, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge); + ok(SUCCEEDED(hr), "merge himl1,0 failed\n"); + if (SUCCEEDED(hr)) IImageList_Release(merge); + + /* Same happens if himl2 is empty */ + IImageList_Release(imgl2); + himl2 = ImageList_Create(32,32,0,0,3); + ok(himl2 != NULL,"failed to recreate himl2\n"); + + imgl2 = (IImageList *) himl2; + + hr = IImageList_Merge(imgl1, -1, (IUnknown *) imgl2, -1, 0, 0, &IID_IImageList, (void **) &merge); + ok(SUCCEEDED(hr), "merge himl2,-1 failed\n"); + if (SUCCEEDED(hr)) IImageList_Release(merge); + + hr = IImageList_Merge(imgl1, -1, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge); + ok(SUCCEEDED(hr), "merge himl2,0 failed\n"); + if (SUCCEEDED(hr)) IImageList_Release(merge); + + /* Now try merging an image with itself */ + ok(SUCCEEDED(IImageList_ReplaceIcon(imgl2, -1, hicon1, &ret)) && (ret == 0),"re-add icon1 to himl2 failed\n"); + + hr = IImageList_Merge(imgl2, 0, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge); + ok(SUCCEEDED(hr), "merge himl2 with itself failed\n"); + if (SUCCEEDED(hr)) IImageList_Release(merge); + + /* Try merging 2 different image lists */ + ok(SUCCEEDED(IImageList_ReplaceIcon(imgl1, -1, hicon1, &ret)) && (ret == 0),"add icon1 to himl1 failed\n"); + + hr = IImageList_Merge(imgl1, 0, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge); + ok(SUCCEEDED(hr), "merge himl1 with himl2 failed\n"); + if (SUCCEEDED(hr)) IImageList_Release(merge); + + hr = IImageList_Merge(imgl1, 0, (IUnknown *) imgl2, 0, 8, 16, &IID_IImageList, (void **) &merge); + ok(SUCCEEDED(hr), "merge himl1 with himl2 8,16 failed\n"); + if (SUCCEEDED(hr)) IImageList_Release(merge); + + IImageList_Release(imgl1); + IImageList_Release(imgl2); + + DestroyIcon(hicon1); + DestroyWindow(hwnd); +} + START_TEST(imagelist) { ULONG_PTR ctx_cookie; @@ -1323,6 +1657,11 @@ START_TEST(imagelist) test_shell_imagelist(); test_iimagelist(); + testHotspot_v6(); + DoTest1_v6(); + DoTest3_v6(); + testMerge_v6(); + CoUninitialize(); unload_v6_module(ctx_cookie, hCtx); diff --git a/dlls/comctl32/tests/listview.c b/dlls/comctl32/tests/listview.c index 44c5eb2c49d..95d9ddcc837 100644 --- a/dlls/comctl32/tests/listview.c +++ b/dlls/comctl32/tests/listview.c @@ -271,6 +271,13 @@ static const struct message lvs_ex_transparentbkgnd_seq[] = { { 0 } }; +static const struct message edit_end_nochange[] = { + { WM_NOTIFY, sent|id, 0, 0, LVN_ENDLABELEDITA }, + { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW }, /* todo */ + { WM_NOTIFY, sent|id, 0, 0, NM_SETFOCUS }, + { 0 } +}; + static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static LONG defwndproc_counter = 0; @@ -314,8 +321,12 @@ static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LP return blockEdit; case LVN_ENDLABELEDIT: + { /* always accept new item text */ + NMLVDISPINFO *di = (NMLVDISPINFO*)lParam; + trace("LVN_ENDLABELEDIT: text=%s\n", di->item.pszText); return TRUE; + } case LVN_BEGINSCROLL: case LVN_ENDSCROLL: { @@ -3419,9 +3430,24 @@ static void test_editbox(void) r = SendMessage(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item); expect(lstrlen(item.pszText), r); ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n"); + ok(!IsWindow(hwndedit), "Expected Edit window to be freed\n"); /* end edit without saving */ + SetFocus(hwnd); + hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0); + flush_sequences(sequences, NUM_MSG_SEQUENCES); r = SendMessage(hwndedit, WM_KEYDOWN, VK_ESCAPE, 0); expect(0, r); + ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange, + "edit box - end edit, no change, escape", TRUE); + /* end edit with saving */ + SetFocus(hwnd); + hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0); + flush_sequences(sequences, NUM_MSG_SEQUENCES); + r = SendMessage(hwndedit, WM_KEYDOWN, VK_RETURN, 0); + expect(0, r); + ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange, + "edit box - end edit, no change, return", TRUE); + memset(&item, 0, sizeof(item)); item.pszText = buffer; item.cchTextMax = 10; @@ -3473,6 +3499,16 @@ static void test_editbox(void) ok_sequence(sequences, EDITBOX_SEQ_INDEX, editbox_create_pos, "edit box create - sizing", FALSE); + /* WM_COMMAND with EN_KILLFOCUS isn't forwared to parent */ + SetFocus(hwnd); + hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0); + ok(IsWindow(hwndedit), "Expected Edit window to be created\n"); + flush_sequences(sequences, NUM_MSG_SEQUENCES); + r = SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit); + expect(0, r); + ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange, + "edit box WM_COMMAND (EN_KILLFOCUS)", TRUE); + DestroyWindow(hwnd); } @@ -3720,8 +3756,11 @@ static void test_canceleditlabel(void) insert_item(hwnd, 0); /* try without edit created */ + flush_sequences(sequences, NUM_MSG_SEQUENCES); ret = SendMessage(hwnd, LVM_CANCELEDITLABEL, 0, 0); expect(TRUE, ret); + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, + "cancel edit label without edit", FALSE); /* cancel without data change */ SetFocus(hwnd); @@ -3984,7 +4023,7 @@ static void test_LVS_EX_TRANSPARENTBKGND(void) DestroyWindow(hwnd); } -static void test_ApproximateViewRect(void) +static void test_approximate_viewrect(void) { HWND hwnd; DWORD ret; @@ -4058,6 +4097,69 @@ static void test_ApproximateViewRect(void) DestroyWindow(hwnd); } +static void test_finditem(void) +{ + LVFINDINFOA fi; + static char f[5]; + HWND hwnd; + DWORD r; + + hwnd = create_listview_control(0); + insert_item(hwnd, 0); + + memset(&fi, 0, sizeof(fi)); + + /* full string search, inserted text was "foo" */ + strcpy(f, "foo"); + fi.flags = LVFI_STRING; + fi.psz = f; + r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi); + expect(0, r); + /* partial string search, inserted text was "foo" */ + strcpy(f, "fo"); + fi.flags = LVFI_STRING | LVFI_PARTIAL; + fi.psz = f; + r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi); + expect(0, r); + /* partial string search, part after start char */ + strcpy(f, "oo"); + fi.flags = LVFI_STRING | LVFI_PARTIAL; + fi.psz = f; + r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi); + expect(-1, r); + + /* try with LVFI_SUBSTRING */ + strcpy(f, "fo"); + fi.flags = LVFI_SUBSTRING; + fi.psz = f; + r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi); + if (r == -1) + { + win_skip("LVFI_SUBSTRING not supported\n"); + DestroyWindow(hwnd); + return; + } + expect(0, r); + strcpy(f, "f"); + fi.flags = LVFI_SUBSTRING; + fi.psz = f; + r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi); + expect(0, r); + strcpy(f, "o"); + fi.flags = LVFI_SUBSTRING; + fi.psz = f; + r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi); + expect(-1, r); + + strcpy(f, "f"); + fi.flags = LVFI_SUBSTRING | LVFI_STRING; + fi.psz = f; + r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi); + expect(0, r); + + DestroyWindow(hwnd); +} + START_TEST(listview) { HMODULE hComctl32; @@ -4115,7 +4217,8 @@ START_TEST(listview) test_indentation(); test_getitemspacing(); test_getcolumnwidth(); - test_ApproximateViewRect(); + test_approximate_viewrect(); + test_finditem(); if (!load_v6_module(&ctx_cookie, &hCtx)) { diff --git a/dlls/comctl32/tests/monthcal.c b/dlls/comctl32/tests/monthcal.c index de6df2d04e0..a7aeddda4e8 100644 --- a/dlls/comctl32/tests/monthcal.c +++ b/dlls/comctl32/tests/monthcal.c @@ -1243,6 +1243,7 @@ static void test_monthcal_today(void) /* Setter and Getters for "today" information */ /* check for overflow, should be ok */ + memset(&st_test, 0, sizeof(st_test)); st_test.wDay = 38; st_test.wMonth = 38; diff --git a/dlls/comctl32/tests/propsheet.c b/dlls/comctl32/tests/propsheet.c index 111482e8354..bf40db4f6ec 100644 --- a/dlls/comctl32/tests/propsheet.c +++ b/dlls/comctl32/tests/propsheet.c @@ -110,6 +110,12 @@ static void test_title(void) psh.pfnCallback = sheet_callback; hdlg = (HWND)PropertySheetA(&psh); + if (hdlg == INVALID_HANDLE_VALUE) + { + win_skip("comctl32 4.70 needs dwSize adjustment\n"); + psh.dwSize = sizeof(psh) - sizeof(HBITMAP) - sizeof(HPALETTE) - sizeof(HBITMAP); + hdlg = (HWND)PropertySheetA(&psh); + } DestroyWindow(hdlg); } @@ -141,6 +147,12 @@ static void test_nopage(void) psh.pfnCallback = sheet_callback; hdlg = (HWND)PropertySheetA(&psh); + if (hdlg == INVALID_HANDLE_VALUE) + { + win_skip("comctl32 4.70 needs dwSize adjustment\n"); + psh.dwSize = sizeof(psh) - sizeof(HBITMAP) - sizeof(HPALETTE) - sizeof(HBITMAP); + hdlg = (HWND)PropertySheetA(&psh); + } ShowWindow(hdlg,SW_NORMAL); SendMessage(hdlg, PSM_REMOVEPAGE, 0, 0); RedrawWindow(hdlg,NULL,NULL,RDW_UPDATENOW|RDW_ERASENOW); @@ -183,6 +195,7 @@ static void test_disableowner(void) HPROPSHEETPAGE hpsp[1]; PROPSHEETPAGEA psp; PROPSHEETHEADERA psh; + INT_PTR p; register_parent_wnd_class(); parent = CreateWindowA("parent class", "", WS_CAPTION | WS_SYSMENU | WS_VISIBLE, 100, 100, 100, 100, GetDesktopWindow(), NULL, GetModuleHandleA(NULL), 0); @@ -207,7 +220,9 @@ static void test_disableowner(void) U3(psh).phpage = hpsp; psh.pfnCallback = disableowner_callback; - PropertySheetA(&psh); + p = PropertySheetA(&psh); + todo_wine + ok(p == 0, "Expected 0, got %ld\n", p); ok(IsWindowEnabled(parent) != 0, "parent window should be enabled\n"); DestroyWindow(parent); } @@ -283,6 +298,12 @@ static void test_wiznavigation(void) psh.hwndParent = GetDesktopWindow(); U3(psh).phpage = hpsp; hdlg = (HWND)PropertySheetA(&psh); + if (hdlg == INVALID_HANDLE_VALUE) + { + win_skip("comctl32 4.70 needs dwSize adjustment\n"); + psh.dwSize = sizeof(psh) - sizeof(HBITMAP) - sizeof(HPALETTE) - sizeof(HBITMAP); + hdlg = (HWND)PropertySheetA(&psh); + } ok(active_page == 0, "Active page should be 0. Is: %d\n", active_page); @@ -381,6 +402,12 @@ static void test_buttons(void) psh.pfnCallback = sheet_callback; hdlg = (HWND)PropertySheetA(&psh); + if (hdlg == INVALID_HANDLE_VALUE) + { + win_skip("comctl32 4.70 needs dwSize adjustment\n"); + psh.dwSize = sizeof(psh) - sizeof(HBITMAP) - sizeof(HPALETTE) - sizeof(HBITMAP); + hdlg = (HWND)PropertySheetA(&psh); + } /* OK button */ button = GetDlgItem(hdlg, IDOK); diff --git a/dlls/comctl32/tests/tab.c b/dlls/comctl32/tests/tab.c index bab747a917c..6774d51a1a5 100644 --- a/dlls/comctl32/tests/tab.c +++ b/dlls/comctl32/tests/tab.c @@ -638,7 +638,290 @@ static void test_tab(INT nMinTabWidth) DeleteObject(hFont); } -static void test_getters_setters(HWND parent_wnd, INT nTabs) +static void test_curfocus(HWND parent_wnd, INT nTabs) +{ + INT focusIndex; + HWND hTab; + + hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs); + ok(hTab != NULL, "Failed to create tab control\n"); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + /* Testing CurFocus with largest appropriate value */ + SendMessage(hTab, TCM_SETCURFOCUS, nTabs-1, 0); + focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); + expect(nTabs-1, focusIndex); + + /* Testing CurFocus with negative value */ + SendMessage(hTab, TCM_SETCURFOCUS, -10, 0); + focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); + expect(-1, focusIndex); + + /* Testing CurFocus with value larger than number of tabs */ + focusIndex = SendMessage(hTab, TCM_SETCURSEL, 1, 0); + expect(-1, focusIndex); + + SendMessage(hTab, TCM_SETCURFOCUS, nTabs+1, 0); + focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); + expect(1, focusIndex); + + ok_sequence(sequences, TAB_SEQ_INDEX, getset_cur_focus_seq, "Getset curFoc test sequence", FALSE); + + DestroyWindow(hTab); +} + +static void test_cursel(HWND parent_wnd, INT nTabs) +{ + INT selectionIndex; + INT focusIndex; + TCITEM tcItem; + HWND hTab; + + hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs); + ok(hTab != NULL, "Failed to create tab control\n"); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + /* Testing CurSel with largest appropriate value */ + selectionIndex = SendMessage(hTab, TCM_SETCURSEL, nTabs-1, 0); + expect(0, selectionIndex); + selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0); + expect(nTabs-1, selectionIndex); + + /* Focus should switch with selection */ + focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); + expect(nTabs-1, focusIndex); + + /* Testing CurSel with negative value */ + SendMessage(hTab, TCM_SETCURSEL, -10, 0); + selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0); + expect(-1, selectionIndex); + + /* Testing CurSel with value larger than number of tabs */ + selectionIndex = SendMessage(hTab, TCM_SETCURSEL, 1, 0); + expect(-1, selectionIndex); + + selectionIndex = SendMessage(hTab, TCM_SETCURSEL, nTabs+1, 0); + expect(-1, selectionIndex); + selectionIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); + expect(1, selectionIndex); + + ok_sequence(sequences, TAB_SEQ_INDEX, getset_cur_sel_seq, "Getset curSel test sequence", FALSE); + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset curSel test parent sequence", FALSE); + + /* selected item should have TCIS_BUTTONPRESSED state + It doesn't depend on button state */ + memset(&tcItem, 0, sizeof(TCITEM)); + tcItem.mask = TCIF_STATE; + tcItem.dwStateMask = TCIS_BUTTONPRESSED; + selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0); + SendMessage(hTab, TCM_GETITEM, selectionIndex, (LPARAM) &tcItem); + ok (tcItem.dwState & TCIS_BUTTONPRESSED || broken(tcItem.dwState == 0), /* older comctl32 */ + "Selected item should have TCIS_BUTTONPRESSED\n"); + + DestroyWindow(hTab); +} + +static void test_extendedstyle(HWND parent_wnd, INT nTabs) +{ + DWORD prevExtendedStyle; + DWORD extendedStyle; + HWND hTab; + + hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs); + ok(hTab != NULL, "Failed to create tab control\n"); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + /* Testing Flat Separators */ + extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0); + prevExtendedStyle = SendMessage(hTab, TCM_SETEXTENDEDSTYLE, 0, TCS_EX_FLATSEPARATORS); + expect(extendedStyle, prevExtendedStyle); + + extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0); + expect(TCS_EX_FLATSEPARATORS, extendedStyle); + + /* Testing Register Drop */ + prevExtendedStyle = SendMessage(hTab, TCM_SETEXTENDEDSTYLE, 0, TCS_EX_REGISTERDROP); + expect(extendedStyle, prevExtendedStyle); + + extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0); + todo_wine{ + expect(TCS_EX_REGISTERDROP, extendedStyle); + } + + ok_sequence(sequences, TAB_SEQ_INDEX, getset_extended_style_seq, "Getset extendedStyle test sequence", FALSE); + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset extendedStyle test parent sequence", FALSE); + + DestroyWindow(hTab); +} + +static void test_unicodeformat(HWND parent_wnd, INT nTabs) +{ + INT unicodeFormat; + HWND hTab; + + hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs); + ok(hTab != NULL, "Failed to create tab control\n"); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, TRUE, 0); + todo_wine{ + expect(0, unicodeFormat); + } + unicodeFormat = SendMessage(hTab, TCM_GETUNICODEFORMAT, 0, 0); + expect(1, unicodeFormat); + + unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, FALSE, 0); + expect(1, unicodeFormat); + unicodeFormat = SendMessage(hTab, TCM_GETUNICODEFORMAT, 0, 0); + expect(0, unicodeFormat); + + unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, TRUE, 0); + expect(0, unicodeFormat); + + ok_sequence(sequences, TAB_SEQ_INDEX, getset_unicode_format_seq, "Getset unicodeFormat test sequence", FALSE); + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset unicodeFormat test parent sequence", FALSE); + + DestroyWindow(hTab); +} + +static void test_getset_item(HWND parent_wnd, INT nTabs) +{ + TCITEM tcItem; + DWORD ret; + char szText[32] = "New Label"; + HWND hTab; + + hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs); + ok(hTab != NULL, "Failed to create tab control\n"); + + /* passing invalid index should result in initialization to zero + for members mentioned in mask requested */ + + /* valid range here is [0,4] */ + memset(&tcItem, 0xcc, sizeof(tcItem)); + tcItem.mask = TCIF_PARAM; + ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem); + expect(FALSE, ret); + ok(tcItem.lParam == 0, "Expected zero lParam, got %lu\n", tcItem.lParam); + + memset(&tcItem, 0xcc, sizeof(tcItem)); + tcItem.mask = TCIF_IMAGE; + ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem); + expect(FALSE, ret); + expect(0, tcItem.iImage); + + memset(&tcItem, 0xcc, sizeof(tcItem)); + tcItem.mask = TCIF_TEXT; + tcItem.pszText = szText; + szText[0] = 'a'; + ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem); + expect(FALSE, ret); + expect('a', szText[0]); + + memset(&tcItem, 0xcc, sizeof(tcItem)); + tcItem.mask = TCIF_STATE; + tcItem.dwStateMask = 0; + tcItem.dwState = TCIS_BUTTONPRESSED; + ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem); + expect(FALSE, ret); + ok(tcItem.dwState == 0, "Expected zero dwState, got %u\n", tcItem.dwState); + + memset(&tcItem, 0xcc, sizeof(tcItem)); + tcItem.mask = TCIF_STATE; + tcItem.dwStateMask = TCIS_BUTTONPRESSED; + tcItem.dwState = TCIS_BUTTONPRESSED; + ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem); + expect(FALSE, ret); + ok(tcItem.dwState == 0, "Expected zero dwState\n"); + + /* check with negative index to be sure */ + memset(&tcItem, 0xcc, sizeof(tcItem)); + tcItem.mask = TCIF_PARAM; + ret = SendMessage(hTab, TCM_GETITEM, -1, (LPARAM)&tcItem); + expect(FALSE, ret); + ok(tcItem.lParam == 0, "Expected zero lParam, got %lu\n", tcItem.lParam); + + memset(&tcItem, 0xcc, sizeof(tcItem)); + tcItem.mask = TCIF_PARAM; + ret = SendMessage(hTab, TCM_GETITEM, -2, (LPARAM)&tcItem); + expect(FALSE, ret); + ok(tcItem.lParam == 0, "Expected zero lParam, got %lu\n", tcItem.lParam); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + tcItem.mask = TCIF_TEXT; + tcItem.pszText = &szText[0]; + tcItem.cchTextMax = sizeof(szText); + + strcpy(szText, "New Label"); + ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n"); + ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n"); + expect_str("New Label", tcItem.pszText); + + ok ( SendMessage(hTab, TCM_GETITEM, 1, (LPARAM) &tcItem), "Getting item failed.\n"); + expect_str("Tab 2", tcItem.pszText); + + ok_sequence(sequences, TAB_SEQ_INDEX, getset_item_seq, "Getset item test sequence", FALSE); + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset item test parent sequence", FALSE); + + /* TCIS_BUTTONPRESSED doesn't depend on tab style */ + memset(&tcItem, 0, sizeof(tcItem)); + tcItem.mask = TCIF_STATE; + tcItem.dwStateMask = TCIS_BUTTONPRESSED; + tcItem.dwState = TCIS_BUTTONPRESSED; + ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n"); + tcItem.dwState = 0; + ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n"); + if (tcItem.dwState) + { + ok (tcItem.dwState == TCIS_BUTTONPRESSED, "TCIS_BUTTONPRESSED should be set.\n"); + /* next highlight item, test that dwStateMask actually masks */ + tcItem.mask = TCIF_STATE; + tcItem.dwStateMask = TCIS_HIGHLIGHTED; + tcItem.dwState = TCIS_HIGHLIGHTED; + ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n"); + tcItem.dwState = 0; + ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n"); + ok (tcItem.dwState == TCIS_HIGHLIGHTED, "TCIS_HIGHLIGHTED should be set.\n"); + tcItem.mask = TCIF_STATE; + tcItem.dwStateMask = TCIS_BUTTONPRESSED; + tcItem.dwState = 0; + ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n"); + ok (tcItem.dwState == TCIS_BUTTONPRESSED, "TCIS_BUTTONPRESSED should be set.\n"); + } + else win_skip( "Item state mask not supported\n" ); + + DestroyWindow(hTab); +} + +static void test_getset_tooltips(HWND parent_wnd, INT nTabs) +{ + HWND hTab, toolTip; + char toolTipText[32] = "ToolTip Text Test"; + + hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs); + ok(hTab != NULL, "Failed to create tab control\n"); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + toolTip = create_tooltip(hTab, toolTipText); + SendMessage(hTab, TCM_SETTOOLTIPS, (LPARAM) toolTip, 0); + ok (toolTip == (HWND) SendMessage(hTab,TCM_GETTOOLTIPS,0,0), "ToolTip was set incorrectly.\n"); + + SendMessage(hTab, TCM_SETTOOLTIPS, 0, 0); + ok (NULL == (HWND) SendMessage(hTab,TCM_GETTOOLTIPS,0,0), "ToolTip was set incorrectly.\n"); + + ok_sequence(sequences, TAB_SEQ_INDEX, getset_tooltip_seq, "Getset tooltip test sequence", TRUE); + ok_sequence(sequences, PARENT_SEQ_INDEX, getset_tooltip_parent_seq, "Getset tooltip test parent sequence", TRUE); + + DestroyWindow(hTab); +} + +static void test_misc(HWND parent_wnd, INT nTabs) { HWND hTab; RECT rTab; @@ -696,256 +979,6 @@ static void test_getters_setters(HWND parent_wnd, INT nTabs) ok_sequence(sequences, TAB_SEQ_INDEX, get_item_rect_seq, "Get itemRect test sequence", FALSE); ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Get itemRect test parent sequence", FALSE); - /* Testing CurFocus */ - { - INT focusIndex; - - flush_sequences(sequences, NUM_MSG_SEQUENCES); - - /* Testing CurFocus with largest appropriate value */ - SendMessage(hTab, TCM_SETCURFOCUS, nTabs-1, 0); - focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); - expect(nTabs-1, focusIndex); - - /* Testing CurFocus with negative value */ - SendMessage(hTab, TCM_SETCURFOCUS, -10, 0); - focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); - expect(-1, focusIndex); - - /* Testing CurFocus with value larger than number of tabs */ - focusIndex = SendMessage(hTab, TCM_SETCURSEL, 1, 0); - todo_wine{ - expect(-1, focusIndex); - } - - SendMessage(hTab, TCM_SETCURFOCUS, nTabs+1, 0); - focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); - expect(1, focusIndex); - - ok_sequence(sequences, TAB_SEQ_INDEX, getset_cur_focus_seq, "Getset curFoc test sequence", FALSE); - } - - /* Testing CurSel */ - { - INT selectionIndex; - INT focusIndex; - TCITEM tcItem; - - flush_sequences(sequences, NUM_MSG_SEQUENCES); - - /* Testing CurSel with largest appropriate value */ - selectionIndex = SendMessage(hTab, TCM_SETCURSEL, nTabs-1, 0); - expect(1, selectionIndex); - selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0); - expect(nTabs-1, selectionIndex); - - /* Focus should switch with selection */ - focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); - expect(nTabs-1, focusIndex); - - /* Testing CurSel with negative value */ - SendMessage(hTab, TCM_SETCURSEL, -10, 0); - selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0); - expect(-1, selectionIndex); - - /* Testing CurSel with value larger than number of tabs */ - selectionIndex = SendMessage(hTab, TCM_SETCURSEL, 1, 0); - expect(-1, selectionIndex); - - selectionIndex = SendMessage(hTab, TCM_SETCURSEL, nTabs+1, 0); - expect(-1, selectionIndex); - selectionIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0); - expect(1, selectionIndex); - - ok_sequence(sequences, TAB_SEQ_INDEX, getset_cur_sel_seq, "Getset curSel test sequence", FALSE); - ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset curSel test parent sequence", FALSE); - - /* selected item should have TCIS_BUTTONPRESSED state - It doesn't depend on button state */ - memset(&tcItem, 0, sizeof(TCITEM)); - tcItem.mask = TCIF_STATE; - tcItem.dwStateMask = TCIS_BUTTONPRESSED; - selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0); - SendMessage(hTab, TCM_GETITEM, selectionIndex, (LPARAM) &tcItem); - ok (tcItem.dwState & TCIS_BUTTONPRESSED || broken(tcItem.dwState == 0), /* older comctl32 */ - "Selected item should have TCIS_BUTTONPRESSED\n"); - } - - /* Testing ExtendedStyle */ - { - DWORD prevExtendedStyle; - DWORD extendedStyle; - - flush_sequences(sequences, NUM_MSG_SEQUENCES); - - /* Testing Flat Separators */ - extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0); - prevExtendedStyle = SendMessage(hTab, TCM_SETEXTENDEDSTYLE, 0, TCS_EX_FLATSEPARATORS); - expect(extendedStyle, prevExtendedStyle); - - extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0); - expect(TCS_EX_FLATSEPARATORS, extendedStyle); - - /* Testing Register Drop */ - prevExtendedStyle = SendMessage(hTab, TCM_SETEXTENDEDSTYLE, 0, TCS_EX_REGISTERDROP); - expect(extendedStyle, prevExtendedStyle); - - extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0); - todo_wine{ - expect(TCS_EX_REGISTERDROP, extendedStyle); - } - - ok_sequence(sequences, TAB_SEQ_INDEX, getset_extended_style_seq, "Getset extendedStyle test sequence", FALSE); - ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset extendedStyle test parent sequence", FALSE); - } - - /* Testing UnicodeFormat */ - { - INT unicodeFormat; - - flush_sequences(sequences, NUM_MSG_SEQUENCES); - - unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, TRUE, 0); - todo_wine{ - expect(0, unicodeFormat); - } - unicodeFormat = SendMessage(hTab, TCM_GETUNICODEFORMAT, 0, 0); - expect(1, unicodeFormat); - - unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, FALSE, 0); - expect(1, unicodeFormat); - unicodeFormat = SendMessage(hTab, TCM_GETUNICODEFORMAT, 0, 0); - expect(0, unicodeFormat); - - unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, TRUE, 0); - expect(0, unicodeFormat); - - ok_sequence(sequences, TAB_SEQ_INDEX, getset_unicode_format_seq, "Getset unicodeFormat test sequence", FALSE); - ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset unicodeFormat test parent sequence", FALSE); - } - - /* Testing GetSet Item */ - { - TCITEM tcItem; - DWORD ret; - char szText[32] = "New Label"; - - /* passing invalid index should result in initialization to zero - for members mentioned in mask requested */ - - /* valid range here is [0,4] */ - memset(&tcItem, 0xcc, sizeof(tcItem)); - tcItem.mask = TCIF_PARAM; - ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem); - expect(FALSE, ret); - ok(tcItem.lParam == 0, "Expected zero lParam, got %lu\n", tcItem.lParam); - - memset(&tcItem, 0xcc, sizeof(tcItem)); - tcItem.mask = TCIF_IMAGE; - ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem); - expect(FALSE, ret); - expect(0, tcItem.iImage); - - memset(&tcItem, 0xcc, sizeof(tcItem)); - tcItem.mask = TCIF_TEXT; - tcItem.pszText = szText; - szText[0] = 'a'; - ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem); - expect(FALSE, ret); - expect('a', szText[0]); - - memset(&tcItem, 0xcc, sizeof(tcItem)); - tcItem.mask = TCIF_STATE; - tcItem.dwStateMask = 0; - tcItem.dwState = TCIS_BUTTONPRESSED; - ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem); - expect(FALSE, ret); - ok(tcItem.dwState == 0, "Expected zero dwState, got %u\n", tcItem.dwState); - - memset(&tcItem, 0xcc, sizeof(tcItem)); - tcItem.mask = TCIF_STATE; - tcItem.dwStateMask = TCIS_BUTTONPRESSED; - tcItem.dwState = TCIS_BUTTONPRESSED; - ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem); - expect(FALSE, ret); - ok(tcItem.dwState == 0, "Expected zero dwState\n"); - - /* check with negative index to be sure */ - memset(&tcItem, 0xcc, sizeof(tcItem)); - tcItem.mask = TCIF_PARAM; - ret = SendMessage(hTab, TCM_GETITEM, -1, (LPARAM)&tcItem); - expect(FALSE, ret); - ok(tcItem.lParam == 0, "Expected zero lParam, got %lu\n", tcItem.lParam); - - memset(&tcItem, 0xcc, sizeof(tcItem)); - tcItem.mask = TCIF_PARAM; - ret = SendMessage(hTab, TCM_GETITEM, -2, (LPARAM)&tcItem); - expect(FALSE, ret); - ok(tcItem.lParam == 0, "Expected zero lParam, got %lu\n", tcItem.lParam); - - flush_sequences(sequences, NUM_MSG_SEQUENCES); - - tcItem.mask = TCIF_TEXT; - tcItem.pszText = &szText[0]; - tcItem.cchTextMax = sizeof(szText); - - strcpy(szText, "New Label"); - ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n"); - ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n"); - expect_str("New Label", tcItem.pszText); - - ok ( SendMessage(hTab, TCM_GETITEM, 1, (LPARAM) &tcItem), "Getting item failed.\n"); - expect_str("Tab 2", tcItem.pszText); - - ok_sequence(sequences, TAB_SEQ_INDEX, getset_item_seq, "Getset item test sequence", FALSE); - ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset item test parent sequence", FALSE); - - /* TCIS_BUTTONPRESSED doesn't depend on tab style */ - memset(&tcItem, 0, sizeof(tcItem)); - tcItem.mask = TCIF_STATE; - tcItem.dwStateMask = TCIS_BUTTONPRESSED; - tcItem.dwState = TCIS_BUTTONPRESSED; - ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n"); - tcItem.dwState = 0; - ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n"); - if (tcItem.dwState) - { - ok (tcItem.dwState == TCIS_BUTTONPRESSED, "TCIS_BUTTONPRESSED should be set.\n"); - /* next highlight item, test that dwStateMask actually masks */ - tcItem.mask = TCIF_STATE; - tcItem.dwStateMask = TCIS_HIGHLIGHTED; - tcItem.dwState = TCIS_HIGHLIGHTED; - ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n"); - tcItem.dwState = 0; - ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n"); - ok (tcItem.dwState == TCIS_HIGHLIGHTED, "TCIS_HIGHLIGHTED should be set.\n"); - tcItem.mask = TCIF_STATE; - tcItem.dwStateMask = TCIS_BUTTONPRESSED; - tcItem.dwState = 0; - ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n"); - ok (tcItem.dwState == TCIS_BUTTONPRESSED, "TCIS_BUTTONPRESSED should be set.\n"); - } - else win_skip( "Item state mask not supported\n" ); - } - - /* Testing GetSet ToolTip */ - { - HWND toolTip; - char toolTipText[32] = "ToolTip Text Test"; - - flush_sequences(sequences, NUM_MSG_SEQUENCES); - - toolTip = create_tooltip(hTab, toolTipText); - SendMessage(hTab, TCM_SETTOOLTIPS, (LPARAM) toolTip, 0); - ok (toolTip == (HWND) SendMessage(hTab,TCM_GETTOOLTIPS,0,0), "ToolTip was set incorrectly.\n"); - - SendMessage(hTab, TCM_SETTOOLTIPS, 0, 0); - ok (NULL == (HWND) SendMessage(hTab,TCM_GETTOOLTIPS,0,0), "ToolTip was set incorrectly.\n"); - - ok_sequence(sequences, TAB_SEQ_INDEX, getset_tooltip_seq, "Getset tooltip test sequence", TRUE); - ok_sequence(sequences, PARENT_SEQ_INDEX, getset_tooltip_parent_seq, "Getset tooltip test parent sequence", TRUE); - } - DestroyWindow(hTab); } @@ -965,6 +998,7 @@ static void test_adjustrect(HWND parent_wnd) r = SendMessage(hTab, TCM_ADJUSTRECT, TRUE, 0); expect(-1, r); } + static void test_insert_focus(HWND parent_wnd) { HWND hTab; @@ -1023,7 +1057,7 @@ static void test_insert_focus(HWND parent_wnd) expect(2, r); ok_sequence(sequences, TAB_SEQ_INDEX, insert_focus_seq, "insert_focus test sequence", FALSE); - ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "insert_focus parent test sequence", FALSE); + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "insert_focus parent test sequence", TRUE); DestroyWindow(hTab); } @@ -1072,7 +1106,7 @@ static void test_delete_focus(HWND parent_wnd) expect(-1, r); ok_sequence(sequences, TAB_SEQ_INDEX, delete_focus_seq, "delete_focus test sequence", FALSE); - ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "delete_focus parent test sequence", FALSE); + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "delete_focus parent test sequence", TRUE); DestroyWindow(hTab); } @@ -1140,6 +1174,28 @@ static void test_removeimage(HWND parent_wnd) DestroyIcon(hicon); } +static void test_delete_selection(HWND parent_wnd) +{ + HWND hTab; + DWORD ret; + + hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, 4); + ok(hTab != NULL, "Failed to create tab control\n"); + + ret = SendMessage(hTab, TCM_SETCURSEL, 3, 0); + expect(0, ret); + ret = SendMessage(hTab, TCM_GETCURSEL, 0, 0); + expect(3, ret); + /* delete selected item - selection goes to -1 */ + ret = SendMessage(hTab, TCM_DELETEITEM, 3, 0); + expect(TRUE, ret); + + ret = SendMessage(hTab, TCM_GETCURSEL, 0, 0); + expect(-1, ret); + + DestroyWindow(hTab); +} + START_TEST(tab) { HWND parent_wnd; @@ -1170,13 +1226,19 @@ START_TEST(tab) parent_wnd = createParentWindow(); ok(parent_wnd != NULL, "Failed to create parent window!\n"); - /* Testing getters and setters with 5 tabs */ - test_getters_setters(parent_wnd, 5); + test_curfocus(parent_wnd, 5); + test_cursel(parent_wnd, 5); + test_extendedstyle(parent_wnd, 5); + test_unicodeformat(parent_wnd, 5); + test_getset_item(parent_wnd, 5); + test_getset_tooltips(parent_wnd, 5); + test_misc(parent_wnd, 5); test_adjustrect(parent_wnd); test_insert_focus(parent_wnd); test_delete_focus(parent_wnd); + test_delete_selection(parent_wnd); test_removeimage(parent_wnd); DestroyWindow(parent_wnd); diff --git a/dlls/comctl32/toolbar.c b/dlls/comctl32/toolbar.c index 9481840f9d0..1cbdd6ff2a4 100644 --- a/dlls/comctl32/toolbar.c +++ b/dlls/comctl32/toolbar.c @@ -3230,8 +3230,8 @@ TOOLBAR_DeleteButton (TOOLBAR_INFO *infoPtr, INT nIndex) (infoPtr->nNumButtons - nIndex) * sizeof(TBUTTON_INFO)); } - if (TOOLBAR_ButtonHasString(oldButtons)) - Free((LPWSTR)oldButtons->iString); + if (TOOLBAR_ButtonHasString(&oldButtons[nIndex])) + Free((LPWSTR)oldButtons[nIndex].iString); Free (oldButtons); } diff --git a/dlls/comctl32/updown.c b/dlls/comctl32/updown.c index a212073b1bb..773d359824f 100644 --- a/dlls/comctl32/updown.c +++ b/dlls/comctl32/updown.c @@ -550,7 +550,7 @@ UPDOWN_Buddy_SubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) * * Sets bud as a new Buddy. * Then, it should subclass the buddy - * If window has the UDS_ARROWKEYS, it subcalsses the buddy window to + * If window has the UDS_ARROWKEYS, it subclasses the buddy window to * process the UP/DOWN arrow keys. * If window has the UDS_ALIGNLEFT or UDS_ALIGNRIGHT style * the size/pos of the buddy and the control are adjusted accordingly. @@ -659,7 +659,7 @@ static HWND UPDOWN_SetBuddy (UPDOWN_INFO* infoPtr, HWND bud) * 'delta' amount according to the 'action' flag which can be a * combination of FLAG_INCR and FLAG_DECR * It notifies the parent as required. - * It handles wraping and non-wraping correctly. + * It handles wrapping and non-wrapping correctly. * It is assumed that delta>0 */ static void UPDOWN_DoAction (UPDOWN_INFO *infoPtr, int delta, int action) diff --git a/dlls/comdlg32/colordlg.c b/dlls/comdlg32/colordlg.c index e134d4543b8..2a61706d09b 100644 --- a/dlls/comdlg32/colordlg.c +++ b/dlls/comdlg32/colordlg.c @@ -1081,7 +1081,7 @@ static LRESULT CC_WMCommand( HWND hDlg, WPARAM wParam, LPARAM lParam, WORD notif /*********************************************************************** * CC_WMPaint [internal] */ -static LRESULT CC_WMPaint( HWND hDlg, WPARAM wParam, LPARAM lParam ) +static LRESULT CC_WMPaint( HWND hDlg ) { PAINTSTRUCT ps; LPCCPRIV lpp = GetPropW( hDlg, szColourDialogProp ); @@ -1103,7 +1103,7 @@ static LRESULT CC_WMPaint( HWND hDlg, WPARAM wParam, LPARAM lParam ) /*********************************************************************** * CC_WMLButtonUp [internal] */ -static LRESULT CC_WMLButtonUp( HWND hDlg, WPARAM wParam, LPARAM lParam ) +static LRESULT CC_WMLButtonUp( HWND hDlg ) { LPCCPRIV lpp = GetPropW( hDlg, szColourDialogProp ); @@ -1158,7 +1158,7 @@ static LRESULT CC_WMMouseMove( HWND hDlg, LPARAM lParam ) /*********************************************************************** * CC_WMLButtonDown [internal] */ -static LRESULT CC_WMLButtonDown( HWND hDlg, WPARAM wParam, LPARAM lParam ) +static LRESULT CC_WMLButtonDown( HWND hDlg, LPARAM lParam ) { LPCCPRIV lpp = GetPropW( hDlg, szColourDialogProp ); int r, g, b, i; @@ -1252,7 +1252,7 @@ static INT_PTR CALLBACK ColorDlgProc( HWND hDlg, UINT message, return TRUE; break; case WM_PAINT: - if ( CC_WMPaint(hDlg, wParam, lParam)) + if (CC_WMPaint(hDlg)) return TRUE; break; case WM_LBUTTONDBLCLK: @@ -1264,11 +1264,11 @@ static INT_PTR CALLBACK ColorDlgProc( HWND hDlg, UINT message, return TRUE; break; case WM_LBUTTONUP: /* FIXME: ClipCursor off (if in color graph)*/ - if (CC_WMLButtonUp(hDlg, wParam, lParam)) + if (CC_WMLButtonUp(hDlg)) return TRUE; break; case WM_LBUTTONDOWN:/* FIXME: ClipCursor on (if in color graph)*/ - if (CC_WMLButtonDown(hDlg, wParam, lParam)) + if (CC_WMLButtonDown(hDlg, lParam)) return TRUE; break; } diff --git a/dlls/comdlg32/tests/filedlg.c b/dlls/comdlg32/tests/filedlg.c index aca28417e7e..71f7d2a2595 100644 --- a/dlls/comdlg32/tests/filedlg.c +++ b/dlls/comdlg32/tests/filedlg.c @@ -876,7 +876,7 @@ static void test_arrange(void) } } -static CHAR WINDIR[MAX_PATH]; +static CHAR SYSDIR[MAX_PATH]; static UINT_PTR CALLBACK path_hook_proc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { @@ -896,8 +896,8 @@ static UINT_PTR CALLBACK path_hook_proc( HWND hDlg, UINT msg, WPARAM wParam, LPA memset(buf, 0x66, sizeof(buf)); ret = SendMessageA( GetParent(hDlg), CDM_GETFOLDERPATH, sizeof(buf), (LPARAM)buf); - ok(!lstrcmpA(WINDIR, buf), "Expected '%s', got '%s'\n", WINDIR, buf); - ok(lstrlenA(WINDIR) + 1 == ret, "Expected %d, got %d\n", lstrlenA(WINDIR) + 1, ret); + ok(!lstrcmpiA(SYSDIR, buf), "Expected '%s', got '%s'\n", SYSDIR, buf); + ok(lstrlenA(SYSDIR) + 1 == ret, "Expected %d, got %d\n", lstrlenA(SYSDIR) + 1, ret); } } @@ -911,8 +911,11 @@ static void test_getfolderpath(void) char szFileName[MAX_PATH] = ""; char szInitialDir[MAX_PATH]; - GetWindowsDirectory(szInitialDir, MAX_PATH); - lstrcpyA(WINDIR, szInitialDir); + /* We need to pick a different directory as the other tests because of new + * Windows 7 behavior. + */ + GetSystemDirectory(szInitialDir, MAX_PATH); + lstrcpyA(SYSDIR, szInitialDir); ZeroMemory(&ofn, sizeof(ofn)); diff --git a/dlls/commdlg.dll16/finddlg.c b/dlls/commdlg.dll16/finddlg.c index e2438680a74..abd30d546be 100644 --- a/dlls/commdlg.dll16/finddlg.c +++ b/dlls/commdlg.dll16/finddlg.c @@ -30,11 +30,9 @@ #include "wingdi.h" #include "winuser.h" #include "commdlg.h" -#include "wine/debug.h" #include "cderr.h" #include "cdlg16.h" -WINE_DEFAULT_DEBUG_CHANNEL(commdlg); /*********************************************************************** diff --git a/dlls/commdlg.dll16/printdlg.c b/dlls/commdlg.dll16/printdlg.c index a01411fd384..64bb3952351 100644 --- a/dlls/commdlg.dll16/printdlg.c +++ b/dlls/commdlg.dll16/printdlg.c @@ -126,7 +126,7 @@ BOOL16 WINAPI PrintDlg16( LPPRINTDLG16 lppd ) if (lppd->Flags & PD_ENABLEPRINTHOOK) FIXME( "custom print hook %p no longer supported\n", lppd->lpfnPrintHook ); if (lppd->Flags & PD_ENABLESETUPHOOK) - FIXME( "custom print hook %p no longer supported\n", lppd->lpfnSetupHook ); + FIXME( "custom setup hook %p no longer supported\n", lppd->lpfnSetupHook ); if ((ret = PrintDlgA( &pd32 ))) { diff --git a/dlls/crypt32/Makefile.in b/dlls/crypt32/Makefile.in index c2284b743f7..2daa01a1737 100644 --- a/dlls/crypt32/Makefile.in +++ b/dlls/crypt32/Makefile.in @@ -6,6 +6,7 @@ VPATH = @srcdir@ MODULE = crypt32.dll IMPORTLIB = crypt32 IMPORTS = user32 advapi32 kernel32 ntdll +EXTRALIBS = @SECURITYLIB@ C_SRCS = \ base64.c \ diff --git a/dlls/crypt32/cert.c b/dlls/crypt32/cert.c index 4f3df326943..a24757019cb 100644 --- a/dlls/crypt32/cert.c +++ b/dlls/crypt32/cert.c @@ -1832,6 +1832,92 @@ PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName) return ret; } +static BOOL find_matching_rdn_attr(DWORD dwFlags, const CERT_NAME_INFO *name, + const CERT_RDN_ATTR *attr) +{ + DWORD i, j; + BOOL match = FALSE; + + for (i = 0; !match && i < name->cRDN; i++) + { + for (j = 0; j < name->rgRDN[i].cRDNAttr; j++) + { + if (!strcmp(name->rgRDN[i].rgRDNAttr[j].pszObjId, + attr->pszObjId) && + name->rgRDN[i].rgRDNAttr[j].dwValueType == + attr->dwValueType) + { + if (dwFlags & CERT_UNICODE_IS_RDN_ATTRS_FLAG) + { + LPCWSTR nameStr = + (LPCWSTR)name->rgRDN[i].rgRDNAttr[j].Value.pbData; + LPCWSTR attrStr = (LPCWSTR)attr->Value.pbData; + + if (attr->Value.cbData != + name->rgRDN[i].rgRDNAttr[j].Value.cbData) + match = FALSE; + else if (dwFlags & CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG) + match = !strncmpiW(nameStr, attrStr, + attr->Value.cbData / sizeof(WCHAR)); + else + match = !strncmpW(nameStr, attrStr, + attr->Value.cbData / sizeof(WCHAR)); + TRACE("%s : %s => %d\n", + debugstr_wn(nameStr, attr->Value.cbData / sizeof(WCHAR)), + debugstr_wn(attrStr, attr->Value.cbData / sizeof(WCHAR)), + match); + } + else + { + LPCSTR nameStr = + (LPCSTR)name->rgRDN[i].rgRDNAttr[j].Value.pbData; + LPCSTR attrStr = (LPCSTR)attr->Value.pbData; + + if (attr->Value.cbData != + name->rgRDN[i].rgRDNAttr[j].Value.cbData) + match = FALSE; + else if (dwFlags & CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG) + match = !strncasecmp(nameStr, attrStr, + attr->Value.cbData); + else + match = !strncmp(nameStr, attrStr, attr->Value.cbData); + TRACE("%s : %s => %d\n", + debugstr_an(nameStr, attr->Value.cbData), + debugstr_an(attrStr, attr->Value.cbData), match); + } + } + } + } + return match; +} + +BOOL WINAPI CertIsRDNAttrsInCertificateName(DWORD dwCertEncodingType, + DWORD dwFlags, PCERT_NAME_BLOB pCertName, PCERT_RDN pRDN) +{ + CERT_NAME_INFO *name; + LPCSTR type; + DWORD size; + BOOL ret; + + TRACE("(%08x, %08x, %p, %p)\n", dwCertEncodingType, dwFlags, pCertName, + pRDN); + + type = dwFlags & CERT_UNICODE_IS_RDN_ATTRS_FLAG ? X509_UNICODE_NAME : + X509_NAME; + if ((ret = CryptDecodeObjectEx(dwCertEncodingType, type, pCertName->pbData, + pCertName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &name, &size))) + { + DWORD i; + + for (i = 0; ret && i < pRDN->cRDNAttr; i++) + ret = find_matching_rdn_attr(dwFlags, name, &pRDN->rgRDNAttr[i]); + if (!ret) + SetLastError(CRYPT_E_NO_MATCH); + LocalFree(name); + } + return ret; +} + LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify, PCERT_INFO pCertInfo) { diff --git a/dlls/crypt32/chain.c b/dlls/crypt32/chain.c index eb6d757ce7f..de482ae91cb 100644 --- a/dlls/crypt32/chain.c +++ b/dlls/crypt32/chain.c @@ -506,6 +506,41 @@ static BOOL CRYPT_CheckBasicConstraintsForCA(PCertificateChainEngine engine, return validBasicConstraints; } +static BOOL domain_name_matches(LPCWSTR constraint, LPCWSTR name) +{ + BOOL match; + + /* RFC 5280, section 4.2.1.10: + * "For URIs, the constraint applies to the host part of the name... + * When the constraint begins with a period, it MAY be expanded with one + * or more labels. That is, the constraint ".example.com" is satisfied by + * both host.example.com and my.host.example.com. However, the constraint + * ".example.com" is not satisfied by "example.com". When the constraint + * does not begin with a period, it specifies a host." + * and for email addresses, + * "To indicate all Internet mail addresses on a particular host, the + * constraint is specified as the host name. For example, the constraint + * "example.com" is satisfied by any mail address at the host + * "example.com". To specify any address within a domain, the constraint + * is specified with a leading period (as with URIs)." + */ + if (constraint[0] == '.') + { + /* Must be strictly greater than, a name can't begin with '.' */ + if (lstrlenW(name) > lstrlenW(constraint)) + match = !lstrcmpiW(name + lstrlenW(name) - lstrlenW(constraint), + constraint); + else + { + /* name is too short, no match */ + match = FALSE; + } + } + else + match = !lstrcmpiW(name, constraint); + return match; +} + static BOOL url_matches(LPCWSTR constraint, LPCWSTR name, DWORD *trustErrorStatus) { @@ -517,14 +552,58 @@ static BOOL url_matches(LPCWSTR constraint, LPCWSTR name, *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS; else if (!name) ; /* no match */ - else if (constraint[0] == '.') + else { - if (lstrlenW(name) > lstrlenW(constraint)) - match = !lstrcmpiW(name + lstrlenW(name) - lstrlenW(constraint), - constraint); + LPCWSTR colon, authority_end, at, hostname = NULL; + /* The maximum length for a hostname is 254 in the DNS, see RFC 1034 */ + WCHAR hostname_buf[255]; + + /* RFC 5280: only the hostname portion of the URL is compared. From + * section 4.2.1.10: + * "For URIs, the constraint applies to the host part of the name. + * The constraint MUST be specified as a fully qualified domain name + * and MAY specify a host or a domain." + * The format for URIs is in RFC 2396. + * + * First, remove any scheme that's present. */ + colon = strchrW(name, ':'); + if (colon && *(colon + 1) == '/' && *(colon + 2) == '/') + name = colon + 3; + /* Next, find the end of the authority component. (The authority is + * generally just the hostname, but it may contain a username or a port. + * Those are removed next.) + */ + authority_end = strchrW(name, '/'); + if (!authority_end) + authority_end = strchrW(name, '?'); + if (!authority_end) + authority_end = name + strlenW(name); + /* Remove any port number from the authority */ + for (colon = authority_end; colon >= name && *colon != ':'; colon--) + ; + if (*colon == ':') + authority_end = colon; + /* Remove any username from the authority */ + if ((at = strchrW(name, '@'))) + name = at; + /* Ignore any path or query portion of the URL. */ + if (*authority_end) + { + if (authority_end - name < sizeof(hostname_buf) / + sizeof(hostname_buf[0])) + { + memcpy(hostname_buf, name, + (authority_end - name) * sizeof(WCHAR)); + hostname_buf[authority_end - name] = 0; + hostname = hostname_buf; + } + /* else: Hostname is too long, not a match */ + } + else + hostname = name; + if (hostname) + match = domain_name_matches(constraint, hostname); } - else - match = !lstrcmpiW(constraint, name); return match; } @@ -545,7 +624,7 @@ static BOOL rfc822_name_matches(LPCWSTR constraint, LPCWSTR name, else { if ((at = strchrW(name, '@'))) - match = url_matches(constraint, at + 1, trustErrorStatus); + match = domain_name_matches(constraint, at + 1); else match = !lstrcmpiW(constraint, name); } @@ -563,9 +642,35 @@ static BOOL dns_name_matches(LPCWSTR constraint, LPCWSTR name, *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS; else if (!name) ; /* no match */ - else if (lstrlenW(name) >= lstrlenW(constraint)) + /* RFC 5280, section 4.2.1.10: + * "DNS name restrictions are expressed as host.example.com. Any DNS name + * that can be constructed by simply adding zero or more labels to the + * left-hand side of the name satisfies the name constraint. For example, + * www.host.example.com would satisfy the constraint but host1.example.com + * would not." + */ + else if (lstrlenW(name) == lstrlenW(constraint)) + match = !lstrcmpiW(name, constraint); + else if (lstrlenW(name) > lstrlenW(constraint)) + { match = !lstrcmpiW(name + lstrlenW(name) - lstrlenW(constraint), constraint); + if (match) + { + BOOL dot = FALSE; + LPCWSTR ptr; + + /* This only matches if name is a subdomain of constraint, i.e. + * there's a '.' between the beginning of the name and the + * matching portion of the name. + */ + for (ptr = name + lstrlenW(name) - lstrlenW(constraint); + !dot && ptr >= name; ptr--) + if (*ptr == '.') + dot = TRUE; + match = dot; + } + } /* else: name is too short, no match */ return match; @@ -615,46 +720,95 @@ static BOOL ip_address_matches(const CRYPT_DATA_BLOB *constraint, return match; } -static void CRYPT_FindMatchingNameEntry(const CERT_ALT_NAME_ENTRY *constraint, - const CERT_ALT_NAME_INFO *subjectName, DWORD *trustErrorStatus, - DWORD errorIfFound, DWORD errorIfNotFound) +static BOOL directory_name_matches(const CERT_NAME_BLOB *constraint, + const CERT_NAME_BLOB *name) +{ + CERT_NAME_INFO *constraintName; + DWORD size; + BOOL match = FALSE; + + if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME, constraint->pbData, + constraint->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &constraintName, &size)) + { + DWORD i; + + match = TRUE; + for (i = 0; match && i < constraintName->cRDN; i++) + match = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, + CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG, + (CERT_NAME_BLOB *)name, &constraintName->rgRDN[i]); + LocalFree(constraintName); + } + return match; +} + +static BOOL alt_name_matches(const CERT_ALT_NAME_ENTRY *name, + const CERT_ALT_NAME_ENTRY *constraint, DWORD *trustErrorStatus, BOOL *present) { - DWORD i; BOOL match = FALSE; - for (i = 0; i < subjectName->cAltEntry; i++) + if (name->dwAltNameChoice == constraint->dwAltNameChoice) { - if (subjectName->rgAltEntry[i].dwAltNameChoice == - constraint->dwAltNameChoice) + if (present) + *present = TRUE; + switch (constraint->dwAltNameChoice) { - switch (constraint->dwAltNameChoice) - { - case CERT_ALT_NAME_RFC822_NAME: - match = rfc822_name_matches(constraint->u.pwszURL, - subjectName->rgAltEntry[i].u.pwszURL, trustErrorStatus); - break; - case CERT_ALT_NAME_DNS_NAME: - match = dns_name_matches(constraint->u.pwszURL, - subjectName->rgAltEntry[i].u.pwszURL, trustErrorStatus); - break; - case CERT_ALT_NAME_URL: - match = url_matches(constraint->u.pwszURL, - subjectName->rgAltEntry[i].u.pwszURL, trustErrorStatus); - break; - case CERT_ALT_NAME_IP_ADDRESS: - match = ip_address_matches(&constraint->u.IPAddress, - &subjectName->rgAltEntry[i].u.IPAddress, trustErrorStatus); - break; - case CERT_ALT_NAME_DIRECTORY_NAME: - default: - ERR("name choice %d unsupported in this context\n", - constraint->dwAltNameChoice); - *trustErrorStatus |= - CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT; - } + case CERT_ALT_NAME_RFC822_NAME: + match = rfc822_name_matches(constraint->u.pwszURL, + name->u.pwszURL, trustErrorStatus); + break; + case CERT_ALT_NAME_DNS_NAME: + match = dns_name_matches(constraint->u.pwszURL, + name->u.pwszURL, trustErrorStatus); + break; + case CERT_ALT_NAME_URL: + match = url_matches(constraint->u.pwszURL, + name->u.pwszURL, trustErrorStatus); + break; + case CERT_ALT_NAME_IP_ADDRESS: + match = ip_address_matches(&constraint->u.IPAddress, + &name->u.IPAddress, trustErrorStatus); + break; + case CERT_ALT_NAME_DIRECTORY_NAME: + match = directory_name_matches(&constraint->u.DirectoryName, + &name->u.DirectoryName); + break; + default: + ERR("name choice %d unsupported in this context\n", + constraint->dwAltNameChoice); + *trustErrorStatus |= + CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT; } } - *trustErrorStatus |= match ? errorIfFound : errorIfNotFound; + else if (present) + *present = FALSE; + return match; +} + +static BOOL alt_name_matches_excluded_name(const CERT_ALT_NAME_ENTRY *name, + const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus) +{ + DWORD i; + BOOL match = FALSE; + + for (i = 0; !match && i < nameConstraints->cExcludedSubtree; i++) + match = alt_name_matches(name, + &nameConstraints->rgExcludedSubtree[i].Base, trustErrorStatus, NULL); + return match; +} + +static BOOL alt_name_matches_permitted_name(const CERT_ALT_NAME_ENTRY *name, + const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus, + BOOL *present) +{ + DWORD i; + BOOL match = FALSE; + + for (i = 0; !match && i < nameConstraints->cPermittedSubtree; i++) + match = alt_name_matches(name, + &nameConstraints->rgPermittedSubtree[i].Base, trustErrorStatus, + present); + return match; } static inline PCERT_EXTENSION get_subject_alt_name_ext(const CERT_INFO *cert) @@ -669,57 +823,253 @@ static inline PCERT_EXTENSION get_subject_alt_name_ext(const CERT_INFO *cert) return ext; } -static void CRYPT_CheckNameConstraints( - const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, const CERT_INFO *cert, - DWORD *trustErrorStatus) +static void compare_alt_name_with_constraints(const CERT_EXTENSION *altNameExt, + const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus) { - /* If there aren't any existing constraints, don't bother checking */ - if (nameConstraints->cPermittedSubtree || nameConstraints->cExcludedSubtree) + CERT_ALT_NAME_INFO *subjectAltName; + DWORD size; + + if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME, + altNameExt->Value.pbData, altNameExt->Value.cbData, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, + &subjectAltName, &size)) { - CERT_EXTENSION *ext = get_subject_alt_name_ext(cert); + DWORD i; - if (ext) + for (i = 0; i < subjectAltName->cAltEntry; i++) { - CERT_ALT_NAME_INFO *subjectName; - DWORD size; - - if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME, - ext->Value.pbData, ext->Value.cbData, - CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, - &subjectName, &size)) + BOOL nameFormPresent; + + /* A name constraint only applies if the name form is present. + * From RFC 5280, section 4.2.1.10: + * "Restrictions apply only when the specified name form is + * present. If no name of the type is in the certificate, + * the certificate is acceptable." + */ + if (alt_name_matches_excluded_name( + &subjectAltName->rgAltEntry[i], nameConstraints, + trustErrorStatus)) { - DWORD i; - - for (i = 0; i < nameConstraints->cExcludedSubtree; i++) - CRYPT_FindMatchingNameEntry( - &nameConstraints->rgExcludedSubtree[i].Base, subjectName, - trustErrorStatus, - CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT, 0); - for (i = 0; i < nameConstraints->cPermittedSubtree; i++) - CRYPT_FindMatchingNameEntry( - &nameConstraints->rgPermittedSubtree[i].Base, subjectName, - trustErrorStatus, 0, - CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT); - LocalFree(subjectName); + TRACE_(chain)("subject alternate name form %d excluded\n", + subjectAltName->rgAltEntry[i].dwAltNameChoice); + *trustErrorStatus |= + CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT; } - else + nameFormPresent = FALSE; + if (!alt_name_matches_permitted_name( + &subjectAltName->rgAltEntry[i], nameConstraints, + trustErrorStatus, &nameFormPresent) && nameFormPresent) + { + TRACE_(chain)("subject alternate name form %d not permitted\n", + subjectAltName->rgAltEntry[i].dwAltNameChoice); *trustErrorStatus |= - CERT_TRUST_INVALID_EXTENSION | - CERT_TRUST_INVALID_NAME_CONSTRAINTS; + CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT; + } } - else + LocalFree(subjectAltName); + } + else + *trustErrorStatus |= + CERT_TRUST_INVALID_EXTENSION | CERT_TRUST_INVALID_NAME_CONSTRAINTS; +} + +static BOOL rfc822_attr_matches_excluded_name(const CERT_RDN_ATTR *attr, + const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus) +{ + DWORD i; + BOOL match = FALSE; + + for (i = 0; !match && i < nameConstraints->cExcludedSubtree; i++) + { + const CERT_ALT_NAME_ENTRY *constraint = + &nameConstraints->rgExcludedSubtree[i].Base; + + if (constraint->dwAltNameChoice == CERT_ALT_NAME_RFC822_NAME) + match = rfc822_name_matches(constraint->u.pwszRfc822Name, + (LPCWSTR)attr->Value.pbData, trustErrorStatus); + } + return match; +} + +static BOOL rfc822_attr_matches_permitted_name(const CERT_RDN_ATTR *attr, + const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus, + BOOL *present) +{ + DWORD i; + BOOL match = FALSE; + + for (i = 0; !match && i < nameConstraints->cPermittedSubtree; i++) + { + const CERT_ALT_NAME_ENTRY *constraint = + &nameConstraints->rgPermittedSubtree[i].Base; + + if (constraint->dwAltNameChoice == CERT_ALT_NAME_RFC822_NAME) { - if (nameConstraints->cPermittedSubtree) - *trustErrorStatus |= - CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT | - CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT; - if (nameConstraints->cExcludedSubtree) - *trustErrorStatus |= - CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT; + *present = TRUE; + match = rfc822_name_matches(constraint->u.pwszRfc822Name, + (LPCWSTR)attr->Value.pbData, trustErrorStatus); + } + } + return match; +} + +static void compare_subject_with_email_constraints( + const CERT_NAME_BLOB *subjectName, + const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus) +{ + CERT_NAME_INFO *name; + DWORD size; + + if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_UNICODE_NAME, + subjectName->pbData, subjectName->cbData, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &name, &size)) + { + DWORD i, j; + + for (i = 0; i < name->cRDN; i++) + for (j = 0; j < name->rgRDN[i].cRDNAttr; j++) + if (!strcmp(name->rgRDN[i].rgRDNAttr[j].pszObjId, + szOID_RSA_emailAddr)) + { + BOOL nameFormPresent; + + /* A name constraint only applies if the name form is + * present. From RFC 5280, section 4.2.1.10: + * "Restrictions apply only when the specified name form is + * present. If no name of the type is in the certificate, + * the certificate is acceptable." + */ + if (rfc822_attr_matches_excluded_name( + &name->rgRDN[i].rgRDNAttr[j], nameConstraints, + trustErrorStatus)) + { + TRACE_(chain)( + "email address in subject name is excluded\n"); + *trustErrorStatus |= + CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT; + } + nameFormPresent = FALSE; + if (!rfc822_attr_matches_permitted_name( + &name->rgRDN[i].rgRDNAttr[j], nameConstraints, + trustErrorStatus, &nameFormPresent) && nameFormPresent) + { + TRACE_(chain)( + "email address in subject name is not permitted\n"); + *trustErrorStatus |= + CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT; + } + } + LocalFree(name); + } + else + *trustErrorStatus |= + CERT_TRUST_INVALID_EXTENSION | CERT_TRUST_INVALID_NAME_CONSTRAINTS; +} + +static BOOL CRYPT_IsEmptyName(const CERT_NAME_BLOB *name) +{ + BOOL empty; + + if (!name->cbData) + empty = TRUE; + else if (name->cbData == 2 && name->pbData[1] == 0) + { + /* An empty sequence is also empty */ + empty = TRUE; + } + else + empty = FALSE; + return empty; +} + +static void compare_subject_with_constraints(const CERT_NAME_BLOB *subjectName, + const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus) +{ + BOOL hasEmailConstraint = FALSE; + DWORD i; + + /* In general, a subject distinguished name only matches a directory name + * constraint. However, an exception exists for email addresses. + * From RFC 5280, section 4.2.1.6: + * "Legacy implementations exist where an electronic mail address is + * embedded in the subject distinguished name as an emailAddress + * attribute [RFC2985]." + * If an email address constraint exists, check that constraint separately. + */ + for (i = 0; !hasEmailConstraint && i < nameConstraints->cExcludedSubtree; + i++) + if (nameConstraints->rgExcludedSubtree[i].Base.dwAltNameChoice == + CERT_ALT_NAME_RFC822_NAME) + hasEmailConstraint = TRUE; + for (i = 0; !hasEmailConstraint && i < nameConstraints->cPermittedSubtree; + i++) + if (nameConstraints->rgPermittedSubtree[i].Base.dwAltNameChoice == + CERT_ALT_NAME_RFC822_NAME) + hasEmailConstraint = TRUE; + if (hasEmailConstraint) + compare_subject_with_email_constraints(subjectName, nameConstraints, + trustErrorStatus); + for (i = 0; i < nameConstraints->cExcludedSubtree; i++) + { + CERT_ALT_NAME_ENTRY *constraint = + &nameConstraints->rgExcludedSubtree[i].Base; + + if (constraint->dwAltNameChoice == CERT_ALT_NAME_DIRECTORY_NAME && + directory_name_matches(&constraint->u.DirectoryName, subjectName)) + { + TRACE_(chain)("subject name is excluded\n"); + *trustErrorStatus |= + CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT; + } + } + /* RFC 5280, section 4.2.1.10: + * "Restrictions apply only when the specified name form is present. + * If no name of the type is in the certificate, the certificate is + * acceptable." + * An empty name can't have the name form present, so don't check it. + */ + if (nameConstraints->cPermittedSubtree && !CRYPT_IsEmptyName(subjectName)) + { + BOOL match = FALSE, hasDirectoryConstraint = FALSE; + + for (i = 0; !match && i < nameConstraints->cPermittedSubtree; i++) + { + CERT_ALT_NAME_ENTRY *constraint = + &nameConstraints->rgPermittedSubtree[i].Base; + + if (constraint->dwAltNameChoice == CERT_ALT_NAME_DIRECTORY_NAME) + { + hasDirectoryConstraint = TRUE; + match = directory_name_matches(&constraint->u.DirectoryName, + subjectName); + } + } + if (hasDirectoryConstraint && !match) + { + TRACE_(chain)("subject name is not permitted\n"); + *trustErrorStatus |= CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT; } } } +static void CRYPT_CheckNameConstraints( + const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, const CERT_INFO *cert, + DWORD *trustErrorStatus) +{ + CERT_EXTENSION *ext = get_subject_alt_name_ext(cert); + + if (ext) + compare_alt_name_with_constraints(ext, nameConstraints, + trustErrorStatus); + /* Name constraints apply to the subject alternative name as well as the + * subject name. From RFC 5280, section 4.2.1.10: + * "Restrictions apply to the subject distinguished name and apply to + * subject alternative names." + */ + compare_subject_with_constraints(&cert->Subject, nameConstraints, + trustErrorStatus); +} + /* Gets cert's name constraints, if any. Free with LocalFree. */ static CERT_NAME_CONSTRAINTS_INFO *CRYPT_GetNameConstraints(CERT_INFO *cert) { @@ -745,6 +1095,17 @@ static BOOL CRYPT_IsValidNameConstraint(const CERT_NAME_CONSTRAINTS_INFO *info) DWORD i; BOOL ret = TRUE; + /* Make sure at least one permitted or excluded subtree is present. From + * RFC 5280, section 4.2.1.10: + * "Conforming CAs MUST NOT issue certificates where name constraints is an + * empty sequence. That is, either the permittedSubtrees field or the + * excludedSubtrees MUST be present." + */ + if (!info->cPermittedSubtree && !info->cExcludedSubtree) + { + WARN_(chain)("constraints contain no permitted nor excluded subtree\n"); + ret = FALSE; + } /* Check that none of the constraints specifies a minimum or a maximum. * See RFC 5280, section 4.2.1.10: * "Within this profile, the minimum and maximum fields are not used with @@ -815,8 +1176,16 @@ static void CRYPT_CheckChainNameConstraints(PCERT_SIMPLE_CHAIN chain) CRYPT_CheckNameConstraints(nameConstraints, chain->rgpElement[j]->pCertContext->pCertInfo, &errorStatus); - chain->rgpElement[i]->TrustStatus.dwErrorStatus |= - errorStatus; + if (errorStatus) + { + chain->rgpElement[i]->TrustStatus.dwErrorStatus |= + errorStatus; + CRYPT_CombineTrustStatus(&chain->TrustStatus, + &chain->rgpElement[i]->TrustStatus); + } + else + chain->rgpElement[i]->TrustStatus.dwInfoStatus |= + CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS; } } } @@ -1235,58 +1604,6 @@ static BOOL CRYPT_KeyUsageValid(PCertificateChainEngine engine, return ret; } -static BOOL CRYPT_ExtendedKeyUsageValidForCA(PCCERT_CONTEXT cert) -{ - PCERT_EXTENSION ext; - BOOL ret; - - /* RFC 5280, section 4.2.1.12: "In general, this extension will only - * appear in end entity certificates." And, "If a certificate contains - * both a key usage extension and an extended key usage extension, then - * both extensions MUST be processed independently and the certificate MUST - * only be used for a purpose consistent with both extensions." This seems - * to imply that it should be checked if present, and ignored if not. - * Unfortunately some CAs, e.g. the Thawte SGC CA, don't include the code - * signing extended key usage, whereas they do include the keyCertSign - * key usage. Thus, when checking for a CA, we only require the - * code signing extended key usage if the extended key usage is critical. - */ - ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE, - cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension); - if (ext && ext->fCritical) - { - CERT_ENHKEY_USAGE *usage; - DWORD size; - - ret = CryptDecodeObjectEx(cert->dwCertEncodingType, - X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData, - CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size); - if (ret) - { - DWORD i; - - /* Explicitly require the code signing extended key usage for a CA - * with an extended key usage extension. That is, don't assume - * a cert is allowed to be a CA if it specifies the - * anyExtendedKeyUsage usage oid. See again RFC 5280, section - * 4.2.1.12: "Applications that require the presence of a - * particular purpose MAY reject certificates that include the - * anyExtendedKeyUsage OID but not the particular OID expected for - * the application." - */ - ret = FALSE; - for (i = 0; !ret && i < usage->cUsageIdentifier; i++) - if (!strcmp(usage->rgpszUsageIdentifier[i], - szOID_PKIX_KP_CODE_SIGNING)) - ret = TRUE; - LocalFree(usage); - } - } - else - ret = TRUE; - return ret; -} - static BOOL CRYPT_CriticalExtensionsSupported(PCCERT_CONTEXT cert) { BOOL ret = TRUE; @@ -1435,11 +1752,6 @@ static void CRYPT_CheckSimpleChain(PCertificateChainEngine engine, isRoot, constraints.fCA, i)) chain->rgpElement[i]->TrustStatus.dwErrorStatus |= CERT_TRUST_IS_NOT_VALID_FOR_USAGE; - if (i != 0) - if (!CRYPT_ExtendedKeyUsageValidForCA( - chain->rgpElement[i]->pCertContext)) - chain->rgpElement[i]->TrustStatus.dwErrorStatus |= - CERT_TRUST_IS_NOT_VALID_FOR_USAGE; if (CRYPT_IsSimpleChainCyclic(chain)) { /* If the chain is cyclic, then the path length constraints @@ -1501,7 +1813,10 @@ static PCCERT_CONTEXT CRYPT_GetIssuer(HCERTSTORE store, PCCERT_CONTEXT subject, subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id, prevIssuer); if (issuer) + { + TRACE_(chain)("issuer found by issuer/serial number\n"); *infoStatus = CERT_TRUST_HAS_EXACT_MATCH_ISSUER; + } } else if (info->KeyId.cbData) { @@ -1511,7 +1826,10 @@ static PCCERT_CONTEXT CRYPT_GetIssuer(HCERTSTORE store, PCCERT_CONTEXT subject, subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id, prevIssuer); if (issuer) + { + TRACE_(chain)("issuer found by key id\n"); *infoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER; + } } LocalFree(info); } @@ -1554,7 +1872,10 @@ static PCCERT_CONTEXT CRYPT_GetIssuer(HCERTSTORE store, PCCERT_CONTEXT subject, subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id, prevIssuer); if (issuer) + { + TRACE_(chain)("issuer found by directory name\n"); *infoStatus = CERT_TRUST_HAS_EXACT_MATCH_ISSUER; + } } else FIXME("no supported name type in authority key id2\n"); @@ -1567,7 +1888,10 @@ static PCCERT_CONTEXT CRYPT_GetIssuer(HCERTSTORE store, PCCERT_CONTEXT subject, subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id, prevIssuer); if (issuer) + { + TRACE_(chain)("issuer found by key id\n"); *infoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER; + } } LocalFree(info); } @@ -1577,6 +1901,7 @@ static PCCERT_CONTEXT CRYPT_GetIssuer(HCERTSTORE store, PCCERT_CONTEXT subject, issuer = CertFindCertificateInStore(store, subject->dwCertEncodingType, 0, CERT_FIND_SUBJECT_NAME, &subject->pCertInfo->Issuer, prevIssuer); + TRACE_(chain)("issuer found by name\n"); *infoStatus = CERT_TRUST_HAS_NAME_MATCH_ISSUER; } return issuer; @@ -2054,7 +2379,7 @@ static void CRYPT_VerifyChainRevocation(PCERT_CHAIN_CONTEXT chain, if (cContext) { PCCERT_CONTEXT *contexts = - CryptMemAlloc(cContext * sizeof(PCCERT_CONTEXT *)); + CryptMemAlloc(cContext * sizeof(PCCERT_CONTEXT)); if (contexts) { @@ -2101,7 +2426,11 @@ static void CRYPT_VerifyChainRevocation(PCERT_CHAIN_CONTEXT chain, case CRYPT_E_NO_REVOCATION_CHECK: case CRYPT_E_NO_REVOCATION_DLL: case CRYPT_E_NOT_IN_REVOCATION_DATABASE: - error = CERT_TRUST_REVOCATION_STATUS_UNKNOWN; + /* If the revocation status is unknown, it's assumed to be + * offline too. + */ + error = CERT_TRUST_REVOCATION_STATUS_UNKNOWN | + CERT_TRUST_IS_OFFLINE_REVOCATION; break; case CRYPT_E_REVOCATION_OFFLINE: error = CERT_TRUST_IS_OFFLINE_REVOCATION; @@ -2125,14 +2454,122 @@ static void CRYPT_VerifyChainRevocation(PCERT_CHAIN_CONTEXT chain, } } +static void CRYPT_CheckUsages(PCERT_CHAIN_CONTEXT chain, + const CERT_CHAIN_PARA *pChainPara) +{ + if (pChainPara->cbSize >= sizeof(CERT_CHAIN_PARA_NO_EXTRA_FIELDS) && + pChainPara->RequestedUsage.Usage.cUsageIdentifier) + { + PCCERT_CONTEXT endCert; + PCERT_EXTENSION ext; + BOOL validForUsage; + + /* A chain, if created, always includes the end certificate */ + endCert = chain->rgpChain[0]->rgpElement[0]->pCertContext; + /* The extended key usage extension specifies how a certificate's + * public key may be used. From RFC 5280, section 4.2.1.12: + * "This extension indicates one or more purposes for which the + * certified public key may be used, in addition to or in place of the + * basic purposes indicated in the key usage extension." + * If the extension is present, it only satisfies the requested usage + * if that usage is included in the extension: + * "If the extension is present, then the certificate MUST only be used + * for one of the purposes indicated." + * There is also the special anyExtendedKeyUsage OID, but it doesn't + * have to be respected: + * "Applications that require the presence of a particular purpose + * MAY reject certificates that include the anyExtendedKeyUsage OID + * but not the particular OID expected for the application." + * For now, I'm being more conservative and ignoring the presence of + * the anyExtendedKeyUsage OID. + */ + if ((ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE, + endCert->pCertInfo->cExtension, endCert->pCertInfo->rgExtension))) + { + const CERT_ENHKEY_USAGE *requestedUsage = + &pChainPara->RequestedUsage.Usage; + CERT_ENHKEY_USAGE *usage; + DWORD size; + + if (CryptDecodeObjectEx(X509_ASN_ENCODING, + X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData, + CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size)) + { + if (pChainPara->RequestedUsage.dwType == USAGE_MATCH_TYPE_AND) + { + DWORD i, j; + + /* For AND matches, all usages must be present */ + validForUsage = TRUE; + for (i = 0; validForUsage && + i < requestedUsage->cUsageIdentifier; i++) + { + BOOL match = FALSE; + + for (j = 0; !match && j < usage->cUsageIdentifier; j++) + match = !strcmp(usage->rgpszUsageIdentifier[j], + requestedUsage->rgpszUsageIdentifier[i]); + if (!match) + validForUsage = FALSE; + } + } + else + { + DWORD i, j; + + /* For OR matches, any matching usage suffices */ + validForUsage = FALSE; + for (i = 0; !validForUsage && + i < requestedUsage->cUsageIdentifier; i++) + { + for (j = 0; !validForUsage && + j < usage->cUsageIdentifier; j++) + validForUsage = + !strcmp(usage->rgpszUsageIdentifier[j], + requestedUsage->rgpszUsageIdentifier[i]); + } + } + LocalFree(usage); + } + else + validForUsage = FALSE; + } + else + { + /* If the extension isn't present, any interpretation is valid: + * "Certificate using applications MAY require that the extended + * key usage extension be present and that a particular purpose + * be indicated in order for the certificate to be acceptable to + * that application." + * For now I'm being more conservative and disallowing it. + */ + WARN_(chain)("requested usage from a certificate with no usages\n"); + validForUsage = FALSE; + } + if (!validForUsage) + { + chain->TrustStatus.dwErrorStatus |= + CERT_TRUST_IS_NOT_VALID_FOR_USAGE; + chain->rgpChain[0]->rgpElement[0]->TrustStatus.dwErrorStatus |= + CERT_TRUST_IS_NOT_VALID_FOR_USAGE; + } + } + if (pChainPara->cbSize >= sizeof(CERT_CHAIN_PARA) && + pChainPara->RequestedIssuancePolicy.Usage.cUsageIdentifier) + FIXME("unimplemented for RequestedIssuancePolicy\n"); +} + static void dump_usage_match(LPCSTR name, const CERT_USAGE_MATCH *usageMatch) { - DWORD i; + if (usageMatch->Usage.cUsageIdentifier) + { + DWORD i; - TRACE_(chain)("%s: %s\n", name, - usageMatch->dwType == USAGE_MATCH_TYPE_AND ? "AND" : "OR"); - for (i = 0; i < usageMatch->Usage.cUsageIdentifier; i++) - TRACE_(chain)("%s\n", usageMatch->Usage.rgpszUsageIdentifier[i]); + TRACE_(chain)("%s: %s\n", name, + usageMatch->dwType == USAGE_MATCH_TYPE_AND ? "AND" : "OR"); + for (i = 0; i < usageMatch->Usage.cUsageIdentifier; i++) + TRACE_(chain)("%s\n", usageMatch->Usage.rgpszUsageIdentifier[i]); + } } static void dump_chain_para(const CERT_CHAIN_PARA *pChainPara) @@ -2202,6 +2639,7 @@ BOOL WINAPI CertGetCertificateChain(HCERTCHAINENGINE hChainEngine, CRYPT_FreeLowerQualityChains(chain); pChain = (PCERT_CHAIN_CONTEXT)chain; CRYPT_VerifyChainRevocation(pChain, pTime, pChainPara, dwFlags); + CRYPT_CheckUsages(pChain, pChainPara); if (ppChainContext) *ppChainContext = pChain; else @@ -2378,8 +2816,8 @@ static BOOL match_dns_to_subject_alt_name(PCERT_EXTENSION ext, * in section 4.2.1.6: * "Multiple name forms, and multiple instances of each name form, * MAY be included." - * It doesn't specify the behavior in such cases, but common usage is - * to accept a certificate if any name matches. + * It doesn't specify the behavior in such cases, but both RFC 2818 + * and RFC 2595 explicitly accept a certificate if any name matches. */ for (i = 0; !matches && i < subjectName->cAltEntry; i++) { diff --git a/dlls/crypt32/crl.c b/dlls/crypt32/crl.c index 522aadf616e..a24e6adf887 100644 --- a/dlls/crypt32/crl.c +++ b/dlls/crypt32/crl.c @@ -19,10 +19,12 @@ #include #include +#define NONAMELESSUNION #include "windef.h" #include "winbase.h" #include "wincrypt.h" #include "wine/debug.h" +#include "wine/unicode.h" #include "crypt32_private.h" WINE_DEFAULT_DEBUG_CHANNEL(crypt); @@ -113,7 +115,82 @@ static BOOL compare_crl_issued_by(PCCRL_CONTEXT pCrlContext, DWORD dwType, PCCERT_CONTEXT issuer = pvPara; ret = CertCompareCertificateName(issuer->dwCertEncodingType, - &issuer->pCertInfo->Issuer, &pCrlContext->pCrlInfo->Issuer); + &issuer->pCertInfo->Subject, &pCrlContext->pCrlInfo->Issuer); + if (ret && (dwFlags & CRL_FIND_ISSUED_BY_SIGNATURE_FLAG)) + ret = CryptVerifyCertificateSignatureEx(0, + issuer->dwCertEncodingType, + CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL, (void *)pCrlContext, + CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)issuer, 0, NULL); + if (ret && (dwFlags & CRL_FIND_ISSUED_BY_AKI_FLAG)) + { + PCERT_EXTENSION ext = CertFindExtension( + szOID_AUTHORITY_KEY_IDENTIFIER2, pCrlContext->pCrlInfo->cExtension, + pCrlContext->pCrlInfo->rgExtension); + + if (ext) + { + CERT_AUTHORITY_KEY_ID2_INFO *info; + DWORD size; + + if ((ret = CryptDecodeObjectEx(X509_ASN_ENCODING, + X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData, + CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size))) + { + if (info->AuthorityCertIssuer.cAltEntry && + info->AuthorityCertSerialNumber.cbData) + { + PCERT_ALT_NAME_ENTRY directoryName = NULL; + DWORD i; + + for (i = 0; !directoryName && + i < info->AuthorityCertIssuer.cAltEntry; i++) + if (info->AuthorityCertIssuer.rgAltEntry[i]. + dwAltNameChoice == CERT_ALT_NAME_DIRECTORY_NAME) + directoryName = + &info->AuthorityCertIssuer.rgAltEntry[i]; + if (directoryName) + { + ret = CertCompareCertificateName( + issuer->dwCertEncodingType, + &issuer->pCertInfo->Subject, + &directoryName->u.DirectoryName); + if (ret) + ret = CertCompareIntegerBlob( + &issuer->pCertInfo->SerialNumber, + &info->AuthorityCertSerialNumber); + } + else + { + FIXME("no supported name type in authority key id2\n"); + ret = FALSE; + } + } + else if (info->KeyId.cbData) + { + if ((ext = CertFindExtension( + szOID_SUBJECT_KEY_IDENTIFIER, + issuer->pCertInfo->cExtension, + issuer->pCertInfo->rgExtension))) + { + if (info->KeyId.cbData == ext->Value.cbData) + ret = !memcmp(info->KeyId.pbData, + ext->Value.pbData, info->KeyId.cbData); + else + ret = FALSE; + } + else + ret = FALSE; + } + else + { + FIXME("unsupported value for AKI extension\n"); + ret = FALSE; + } + LocalFree(info); + } + } + /* else: a CRL without an AKI matches any cert */ + } } else ret = TRUE; @@ -137,6 +214,17 @@ static BOOL compare_crl_existing(PCCRL_CONTEXT pCrlContext, DWORD dwType, return ret; } +static BOOL compare_crl_issued_for(PCCRL_CONTEXT pCrlContext, DWORD dwType, + DWORD dwFlags, const void *pvPara) +{ + const CRL_FIND_ISSUED_FOR_PARA *para = pvPara; + BOOL ret; + + ret = CertCompareCertificateName(para->pIssuerCert->dwCertEncodingType, + ¶->pIssuerCert->pCertInfo->Issuer, &pCrlContext->pCrlInfo->Issuer); + return ret; +} + PCCRL_CONTEXT WINAPI CertFindCRLInStore(HCERTSTORE hCertStore, DWORD dwCertEncodingType, DWORD dwFindFlags, DWORD dwFindType, const void *pvFindPara, PCCRL_CONTEXT pPrevCrlContext) @@ -158,6 +246,9 @@ PCCRL_CONTEXT WINAPI CertFindCRLInStore(HCERTSTORE hCertStore, case CRL_FIND_EXISTING: compare = compare_crl_existing; break; + case CRL_FIND_ISSUED_FOR: + compare = compare_crl_issued_for; + break; default: FIXME("find type %08x unimplemented\n", dwFindType); compare = NULL; @@ -467,11 +558,151 @@ BOOL WINAPI CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext, return ret; } +static BOOL compare_dist_point_name(const CRL_DIST_POINT_NAME *name1, + const CRL_DIST_POINT_NAME *name2) +{ + BOOL match; + + if (name1->dwDistPointNameChoice == name2->dwDistPointNameChoice) + { + match = TRUE; + if (name1->dwDistPointNameChoice == CRL_DIST_POINT_FULL_NAME) + { + if (name1->u.FullName.cAltEntry == name2->u.FullName.cAltEntry) + { + DWORD i; + + for (i = 0; match && i < name1->u.FullName.cAltEntry; i++) + { + const CERT_ALT_NAME_ENTRY *entry1 = + &name1->u.FullName.rgAltEntry[i]; + const CERT_ALT_NAME_ENTRY *entry2 = + &name2->u.FullName.rgAltEntry[i]; + + if (entry1->dwAltNameChoice == entry2->dwAltNameChoice) + { + switch (entry1->dwAltNameChoice) + { + case CERT_ALT_NAME_URL: + match = !strcmpiW(entry1->u.pwszURL, + entry2->u.pwszURL); + break; + case CERT_ALT_NAME_DIRECTORY_NAME: + match = (entry1->u.DirectoryName.cbData == + entry2->u.DirectoryName.cbData) && + !memcmp(entry1->u.DirectoryName.pbData, + entry2->u.DirectoryName.pbData, + entry1->u.DirectoryName.cbData); + break; + default: + FIXME("unimplemented for type %d\n", + entry1->dwAltNameChoice); + match = FALSE; + } + } + else + match = FALSE; + } + } + else + match = FALSE; + } + } + else + match = FALSE; + return match; +} + +static BOOL match_dist_point_with_issuing_dist_point( + const CRL_DIST_POINT *distPoint, const CRL_ISSUING_DIST_POINT *idp) +{ + BOOL match; + + /* While RFC 5280, section 4.2.1.13 recommends against segmenting + * CRL distribution points by reasons, it doesn't preclude doing so. + * "This profile RECOMMENDS against segmenting CRLs by reason code." + * If the issuing distribution point for this CRL is only valid for + * some reasons, only match if the reasons covered also match the + * reasons in the CRL distribution point. + */ + if (idp->OnlySomeReasonFlags.cbData) + { + if (idp->OnlySomeReasonFlags.cbData == distPoint->ReasonFlags.cbData) + { + DWORD i; + + match = TRUE; + for (i = 0; match && i < distPoint->ReasonFlags.cbData; i++) + if (idp->OnlySomeReasonFlags.pbData[i] != + distPoint->ReasonFlags.pbData[i]) + match = FALSE; + } + else + match = FALSE; + } + else + match = TRUE; + if (match) + match = compare_dist_point_name(&idp->DistPointName, + &distPoint->DistPointName); + return match; +} + BOOL WINAPI CertIsValidCRLForCertificate(PCCERT_CONTEXT pCert, PCCRL_CONTEXT pCrl, DWORD dwFlags, void *pvReserved) { + PCERT_EXTENSION ext; + BOOL ret; + TRACE("(%p, %p, %08x, %p)\n", pCert, pCrl, dwFlags, pvReserved); - return TRUE; + + if (!pCert) + return TRUE; + + if ((ext = CertFindExtension(szOID_ISSUING_DIST_POINT, + pCrl->pCrlInfo->cExtension, pCrl->pCrlInfo->rgExtension))) + { + CRL_ISSUING_DIST_POINT *idp; + DWORD size; + + if ((ret = CryptDecodeObjectEx(pCrl->dwCertEncodingType, + X509_ISSUING_DIST_POINT, ext->Value.pbData, ext->Value.cbData, + CRYPT_DECODE_ALLOC_FLAG, NULL, &idp, &size))) + { + if ((ext = CertFindExtension(szOID_CRL_DIST_POINTS, + pCert->pCertInfo->cExtension, pCert->pCertInfo->rgExtension))) + { + CRL_DIST_POINTS_INFO *distPoints; + + if ((ret = CryptDecodeObjectEx(pCert->dwCertEncodingType, + X509_CRL_DIST_POINTS, ext->Value.pbData, ext->Value.cbData, + CRYPT_DECODE_ALLOC_FLAG, NULL, &distPoints, &size))) + { + DWORD i; + + ret = FALSE; + for (i = 0; !ret && i < distPoints->cDistPoint; i++) + ret = match_dist_point_with_issuing_dist_point( + &distPoints->rgDistPoint[i], idp); + if (!ret) + SetLastError(CRYPT_E_NO_MATCH); + LocalFree(distPoints); + } + } + else + { + /* no CRL dist points extension in cert, can't match the CRL + * (which has an issuing dist point extension) + */ + ret = FALSE; + SetLastError(CRYPT_E_NO_MATCH); + } + LocalFree(idp); + } + } + else + ret = TRUE; + return ret; } static PCRL_ENTRY CRYPT_FindCertificateInCRL(PCERT_INFO cert, const CRL_INFO *crl) diff --git a/dlls/crypt32/crypt32.spec b/dlls/crypt32/crypt32.spec index b096c090c11..61e4d3d5db7 100644 --- a/dlls/crypt32/crypt32.spec +++ b/dlls/crypt32/crypt32.spec @@ -66,7 +66,7 @@ @ stdcall CertGetStoreProperty(ptr long ptr ptr) @ stdcall CertGetSubjectCertificateFromStore(ptr long ptr) @ stdcall CertGetValidUsages(long ptr ptr ptr ptr) -@ stub CertIsRDNAttrsInCertificateName +@ stdcall CertIsRDNAttrsInCertificateName(long long ptr ptr) @ stdcall CertIsValidCRLForCertificate(ptr ptr long ptr) @ stdcall CertNameToStrA(long ptr long ptr long) @ stdcall CertNameToStrW(long ptr long ptr long) diff --git a/dlls/crypt32/rootstore.c b/dlls/crypt32/rootstore.c index a55b281601c..70b5ef80a3a 100644 --- a/dlls/crypt32/rootstore.c +++ b/dlls/crypt32/rootstore.c @@ -40,6 +40,9 @@ #include "winternl.h" #include "wine/debug.h" #include "crypt32_private.h" +#ifdef __APPLE__ +#include +#endif WINE_DEFAULT_DEBUG_CHANNEL(crypt); @@ -713,6 +716,35 @@ static void read_trusted_roots_from_known_locations(HCERTSTORE store) DWORD i; BOOL ret = FALSE; +#ifdef __APPLE__ + OSStatus status; + CFArrayRef rootCerts; + + status = SecTrustCopyAnchorCertificates(&rootCerts); + if (status == noErr) + { + int i; + for (i = 0; i < CFArrayGetCount(rootCerts); i++) + { + SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(rootCerts, i); + CFDataRef certData; + if ((status = SecKeychainItemExport(cert, kSecFormatX509Cert, 0, NULL, &certData)) == noErr) + { + if (CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + CFDataGetBytePtr(certData), CFDataGetLength(certData), + CERT_STORE_ADD_NEW, NULL)) + ret = TRUE; + else + WARN("adding root cert %d failed: %08x\n", i, GetLastError()); + CFRelease(certData); + } + else + WARN("could not export certificate %d to X509 format: 0x%08x\n", i, (unsigned int)status); + } + CFRelease(rootCerts); + } +#endif + for (i = 0; !ret && i < sizeof(CRYPT_knownLocations) / sizeof(CRYPT_knownLocations[0]); i++) diff --git a/dlls/crypt32/tests/cert.c b/dlls/crypt32/tests/cert.c index e1c826254ac..89268c0bb39 100644 --- a/dlls/crypt32/tests/cert.c +++ b/dlls/crypt32/tests/cert.c @@ -2541,6 +2541,29 @@ static void testGetValidUsages(void) CertFreeCertificateContext(contexts[2]); } +static BYTE cn[] = { +0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x4a,0x75, +0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67 }; +static BYTE cnWithLeadingSpace[] = { +0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x20,0x4a, +0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67 }; +static BYTE cnWithTrailingSpace[] = { +0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75, +0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x20 }; +static BYTE cnWithIntermediateSpace[] = { +0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75, +0x61,0x6e,0x20,0x20,0x4c,0x61,0x6e,0x67 }; +static BYTE cnThenO[] = { +0x30,0x2d,0x31,0x2b,0x30,0x10,0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x4a,0x75, +0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x30,0x17,0x06,0x03,0x55,0x04,0x0a,0x13, +0x10,0x54,0x68,0x65,0x20,0x57,0x69,0x6e,0x65,0x20,0x50,0x72,0x6f,0x6a,0x65, +0x63,0x74 }; +static BYTE oThenCN[] = { +0x30,0x2d,0x31,0x2b,0x30,0x10,0x06,0x03,0x55,0x04,0x0a,0x13,0x09,0x4a,0x75, +0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x30,0x17,0x06,0x03,0x55,0x04,0x03,0x13, +0x10,0x54,0x68,0x65,0x20,0x57,0x69,0x6e,0x65,0x20,0x50,0x72,0x6f,0x6a,0x65, +0x63,0x74 }; + static void testCompareCertName(void) { static BYTE bogus[] = { 1, 2, 3, 4 }; @@ -2572,6 +2595,167 @@ static void testCompareCertName(void) blob2.cbData = sizeof(emptyPrime); ret = CertCompareCertificateName(0, &blob1, &blob2); ok(!ret, "Expected failure\n"); + /* Tests to show that CertCompareCertificateName doesn't decode the name + * to remove spaces, or to do an order-independent comparison. + */ + /* Compare CN="Juan Lang" with CN=" Juan Lang" */ + blob1.pbData = cn; + blob1.cbData = sizeof(cn); + blob2.pbData = cnWithLeadingSpace; + blob2.cbData = sizeof(cnWithLeadingSpace); + ret = CertCompareCertificateName(0, &blob1, &blob2); + ok(!ret, "Expected failure\n"); + ret = CertCompareCertificateName(X509_ASN_ENCODING, &blob1, &blob2); + ok(!ret, "Expected failure\n"); + /* Compare CN="Juan Lang" with CN="Juan Lang " */ + blob2.pbData = cnWithTrailingSpace; + blob2.cbData = sizeof(cnWithTrailingSpace); + ret = CertCompareCertificateName(0, &blob1, &blob2); + ok(!ret, "Expected failure\n"); + ret = CertCompareCertificateName(X509_ASN_ENCODING, &blob1, &blob2); + ok(!ret, "Expected failure\n"); + /* Compare CN="Juan Lang" with CN="Juan Lang" */ + blob2.pbData = cnWithIntermediateSpace; + blob2.cbData = sizeof(cnWithIntermediateSpace); + ret = CertCompareCertificateName(0, &blob1, &blob2); + ok(!ret, "Expected failure\n"); + ret = CertCompareCertificateName(X509_ASN_ENCODING, &blob1, &blob2); + ok(!ret, "Expected failure\n"); + /* Compare 'CN="Juan Lang", O="The Wine Project"' with + * 'O="The Wine Project", CN="Juan Lang"' + */ + blob1.pbData = cnThenO; + blob1.cbData = sizeof(cnThenO); + blob2.pbData = oThenCN; + blob2.cbData = sizeof(oThenCN); + ret = CertCompareCertificateName(0, &blob1, &blob2); + ok(!ret, "Expected failure\n"); + ret = CertCompareCertificateName(X509_ASN_ENCODING, &blob1, &blob2); + ok(!ret, "Expected failure\n"); +} + +static void testIsRDNAttrsInCertificateName(void) +{ + static char oid_1_2_3[] = "1.2.3"; + static char oid_common_name[] = szOID_COMMON_NAME; + static char oid_organization[] = szOID_ORGANIZATION_NAME; + static char juan[] = "Juan Lang"; + static char juan_with_leading_space[] = " Juan Lang"; + static char juan_with_intermediate_space[] = "Juan Lang"; + static char juan_with_trailing_space[] = "Juan Lang "; + static char juan_lower_case[] = "juan lang"; + static WCHAR juanW[] = { 'J','u','a','n',' ','L','a','n','g',0 }; + static char the_wine_project[] = "The Wine Project"; + BOOL ret; + CERT_NAME_BLOB name; + CERT_RDN_ATTR attr[2]; + CERT_RDN rdn = { 0, NULL }; + + name.cbData = sizeof(cn); + name.pbData = cn; + if (0) + { + /* Crash */ + ret = CertIsRDNAttrsInCertificateName(0, 0, NULL, NULL); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, + NULL); + } + SetLastError(0xdeadbeef); + ret = CertIsRDNAttrsInCertificateName(0, 0, &name, NULL); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, &rdn); + ok(ret, "CertIsRDNAttrsInCertificateName failed: %08x\n", GetLastError()); + attr[0].pszObjId = oid_1_2_3; + rdn.rgRDNAttr = attr; + rdn.cRDNAttr = 1; + SetLastError(0xdeadbeef); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, &rdn); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); + attr[0].pszObjId = oid_common_name; + attr[0].dwValueType = CERT_RDN_PRINTABLE_STRING; + attr[0].Value.cbData = strlen(juan); + attr[0].Value.pbData = (BYTE *)juan; + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, &rdn); + ok(ret, "CertIsRDNAttrsInCertificateName failed: %08x\n", GetLastError()); + /* Again, spaces are not removed for name comparison. */ + attr[0].Value.cbData = strlen(juan_with_leading_space); + attr[0].Value.pbData = (BYTE *)juan_with_leading_space; + SetLastError(0xdeadbeef); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, &rdn); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); + attr[0].Value.cbData = strlen(juan_with_intermediate_space); + attr[0].Value.pbData = (BYTE *)juan_with_intermediate_space; + SetLastError(0xdeadbeef); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, &rdn); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); + attr[0].Value.cbData = strlen(juan_with_trailing_space); + attr[0].Value.pbData = (BYTE *)juan_with_trailing_space; + SetLastError(0xdeadbeef); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, &rdn); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); + /* The lower case name isn't matched unless a case insensitive match is + * specified. + */ + attr[0].Value.cbData = strlen(juan_lower_case); + attr[0].Value.pbData = (BYTE *)juan_lower_case; + SetLastError(0xdeadbeef); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, &rdn); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, + CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG, &name, &rdn); + ok(ret || + broken(!ret && GetLastError() == CRYPT_E_NO_MATCH), /* Older crypt32 */ + "CertIsRDNAttrsInCertificateName failed: %08x\n", GetLastError()); + /* The values don't match unless they have the same RDN type */ + attr[0].dwValueType = CERT_RDN_UNICODE_STRING; + attr[0].Value.cbData = lstrlenW(juanW) * sizeof(WCHAR); + attr[0].Value.pbData = (BYTE *)juanW; + SetLastError(0xdeadbeef); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, &rdn); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, + CERT_UNICODE_IS_RDN_ATTRS_FLAG, &name, &rdn); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); + attr[0].dwValueType = CERT_RDN_IA5_STRING; + attr[0].Value.cbData = strlen(juan); + attr[0].Value.pbData = (BYTE *)juan; + SetLastError(0xdeadbeef); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, &rdn); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); + /* All attributes must be present */ + attr[0].dwValueType = CERT_RDN_PRINTABLE_STRING; + attr[0].Value.cbData = strlen(juan); + attr[0].Value.pbData = (BYTE *)juan; + attr[1].pszObjId = oid_organization; + attr[1].dwValueType = CERT_RDN_PRINTABLE_STRING; + attr[1].Value.cbData = strlen(the_wine_project); + attr[1].Value.pbData = (BYTE *)the_wine_project; + rdn.cRDNAttr = 2; + SetLastError(0xdeadbeef); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, &rdn); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); + /* Order also matters */ + name.pbData = cnThenO; + name.cbData = sizeof(cnThenO); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, &rdn); + ok(ret, "CertIsRDNAttrsInCertificateName failed: %08x\n", GetLastError()); + name.pbData = oThenCN; + name.cbData = sizeof(oThenCN); + SetLastError(0xdeadbeef); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, &rdn); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); } static BYTE int1[] = { 0x88, 0xff, 0xff, 0xff }; @@ -2880,12 +3064,97 @@ static void testVerifySubjectCert(void) CertFreeCertificateContext(context1); } +static const BYTE rootWithKeySignAndCRLSign[] = { +0x30,0x82,0x01,0xdf,0x30,0x82,0x01,0x4c,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x5b,0xc7,0x0b,0x27,0x99,0xbb,0x2e,0x99,0x47,0x9d,0x45,0x4e,0x7c,0x1a,0xca, +0xe8,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x30,0x10,0x31, +0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31, +0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05, +0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x42,0x30,0x40,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x06,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x1d,0x06,0x03,0x55,0x1d, +0x0e,0x04,0x16,0x04,0x14,0x14,0x8c,0x16,0xbb,0xbe,0x70,0xa2,0x28,0x89,0xa0, +0x58,0xff,0x98,0xbd,0xa8,0x24,0x2b,0x8a,0xe9,0x9a,0x30,0x09,0x06,0x05,0x2b, +0x0e,0x03,0x02,0x1d,0x05,0x00,0x03,0x81,0x81,0x00,0x74,0xcb,0x21,0xfd,0x2d, +0x25,0xdc,0xa5,0xaa,0xa1,0x26,0xdc,0x8b,0x40,0x11,0x64,0xae,0x5c,0x71,0x3c, +0x28,0xbc,0xf9,0xb3,0xcb,0xa5,0x94,0xb2,0x8d,0x4c,0x23,0x2b,0x9b,0xde,0x2c, +0x4c,0x30,0x04,0xc6,0x88,0x10,0x2f,0x53,0xfd,0x6c,0x82,0xf1,0x13,0xfb,0xda, +0x27,0x75,0x25,0x48,0xe4,0x72,0x09,0x2a,0xee,0xb4,0x1e,0xc9,0x55,0xf5,0xf7, +0x82,0x91,0xd8,0x4b,0xe4,0x3a,0xfe,0x97,0x87,0xdf,0xfb,0x15,0x5a,0x12,0x3e, +0x12,0xe6,0xad,0x40,0x0b,0xcf,0xee,0x1a,0x44,0xe0,0x83,0xb2,0x67,0x94,0xd4, +0x2e,0x7c,0xf2,0x06,0x9d,0xb3,0x3b,0x7e,0x2f,0xda,0x25,0x66,0x7e,0xa7,0x1f, +0x45,0xd4,0xf5,0xe3,0xdf,0x2a,0xf1,0x18,0x28,0x20,0xb5,0xf8,0xf5,0x8d,0x7a, +0x2e,0x84,0xee }; +static const BYTE eeCert[] = { +0x30,0x82,0x01,0x93,0x30,0x81,0xfd,0xa0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00, +0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65, +0x72,0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x35,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x30,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04, +0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09, +0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00, +0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5,0x33, +0x0e,0x67,0x5f,0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6,0xdc, +0xb6,0x17,0x8e,0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7,0x48, +0x9f,0x6e,0xfe,0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b,0x47, +0xd1,0x57,0x71,0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b,0x05, +0x72,0xa7,0x87,0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc,0x6a, +0x80,0x83,0x68,0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85,0x85, +0xb5,0x46,0x36,0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2,0xd3, +0x51,0x9a,0x22,0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72,0xa3, +0x02,0x03,0x01,0x00,0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x22,0xf1,0x66,0x00,0x79,0xd2, +0xe6,0xb2,0xb2,0xf7,0x2f,0x98,0x92,0x7d,0x73,0xc3,0x6c,0x5c,0x77,0x20,0xe3, +0xbf,0x3e,0xe0,0xb3,0x5c,0x68,0xb4,0x9b,0x3a,0x41,0xae,0x94,0xa0,0x80,0x3a, +0xfe,0x5d,0x7a,0x56,0x87,0x85,0x44,0x45,0xcf,0xa6,0xd3,0x10,0xe7,0x73,0x41, +0xf2,0x7f,0x88,0x85,0x91,0x8e,0xe6,0xec,0xe2,0xce,0x08,0xbc,0xa5,0x76,0xe5, +0x4d,0x1d,0xb7,0x70,0x31,0xdd,0xc9,0x9a,0x15,0x32,0x11,0x5a,0x4e,0x62,0xc8, +0xd1,0xf8,0xec,0x46,0x39,0x5b,0xe7,0x67,0x1f,0x58,0xe8,0xa1,0xa0,0x5b,0xf7, +0x8a,0x6d,0x5f,0x91,0x18,0xd4,0x90,0x85,0xff,0x30,0xc7,0xca,0x9c,0xc6,0x92, +0xb0,0xca,0x16,0xc4,0xa4,0xc0,0xd6,0xe8,0xff,0x15,0x19,0xd1,0x30,0x61,0xf3, +0xef,0x9f }; +static const BYTE rootSignedCRL[] = { +0x30,0x82,0x01,0x1d,0x30,0x81,0x87,0x02,0x01,0x01,0x30,0x0d,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x10,0x31,0x0e,0x30, +0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31,0x17,0x0d, +0x30,0x37,0x30,0x39,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d, +0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x14, +0x30,0x12,0x02,0x01,0x01,0x17,0x0d,0x30,0x37,0x30,0x39,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0xa0,0x2d,0x30,0x2b,0x30,0x0a,0x06,0x03,0x55,0x1d, +0x14,0x04,0x03,0x02,0x01,0x01,0x30,0x1d,0x06,0x03,0x55,0x1d,0x23,0x04,0x16, +0x04,0x14,0x14,0x8c,0x16,0xbb,0xbe,0x70,0xa2,0x28,0x89,0xa0,0x58,0xff,0x98, +0xbd,0xa8,0x24,0x2b,0x8a,0xe9,0x9a,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86, +0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x9b,0x2b,0x99,0x0d, +0x16,0x83,0x93,0x54,0x29,0x3a,0xa6,0x53,0x5d,0xf8,0xa6,0x73,0x9f,0x2a,0x45, +0x39,0x91,0xff,0x91,0x1c,0x27,0x06,0xe8,0xdb,0x72,0x3f,0x66,0x89,0x15,0x68, +0x55,0xd5,0x49,0x63,0xa6,0x00,0xe9,0x66,0x9c,0x97,0xf9,0xb3,0xb3,0x2b,0x1b, +0xc7,0x79,0x46,0xa8,0xd8,0x2b,0x78,0x27,0xa0,0x70,0x02,0x81,0xc6,0x40,0xb3, +0x76,0x32,0x65,0x4c,0xf8,0xff,0x1d,0x41,0x6e,0x16,0x09,0xa2,0x8a,0x7b,0x0c, +0xd0,0xa6,0x9b,0x61,0xa3,0x7c,0x02,0x91,0x79,0xdf,0x6a,0x5e,0x88,0x95,0x66, +0x33,0x17,0xcb,0x5a,0xd2,0xdc,0x89,0x05,0x62,0x97,0x60,0x73,0x7b,0x2c,0x1a, +0x90,0x20,0x73,0x24,0x9f,0x45,0x22,0x4b,0xc1,0x33,0xd1,0xda,0xd8,0x7e,0x1b, +0x3d,0x74,0xd6,0x3b }; + static void testVerifyRevocation(void) { BOOL ret; CERT_REVOCATION_STATUS status = { 0 }; - PCCERT_CONTEXT cert = CertCreateCertificateContext(X509_ASN_ENCODING, - bigCert, sizeof(bigCert)); + PCCERT_CONTEXT certs[2]; + CERT_REVOCATION_PARA revPara = { sizeof(revPara), 0 }; /* Crash ret = CertVerifyRevocation(0, 0, 0, NULL, 0, NULL, NULL); @@ -2901,16 +3170,98 @@ static void testVerifyRevocation(void) ok(ret, "CertVerifyRevocation failed: %08x\n", GetLastError()); ret = CertVerifyRevocation(2, 0, 0, NULL, 0, NULL, &status); ok(ret, "CertVerifyRevocation failed: %08x\n", GetLastError()); + certs[0] = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert, + sizeof(bigCert)); SetLastError(0xdeadbeef); - ret = CertVerifyRevocation(0, 0, 1, (void **)&cert, 0, NULL, &status); + ret = CertVerifyRevocation(0, 0, 1, (void **)certs, 0, NULL, &status); ok(!ret && GetLastError() == CRYPT_E_NO_REVOCATION_DLL, "Expected CRYPT_E_NO_REVOCATION_DLL, got %08x\n", GetLastError()); SetLastError(0xdeadbeef); - ret = CertVerifyRevocation(0, 2, 1, (void **)&cert, 0, NULL, &status); + ret = CertVerifyRevocation(0, 2, 1, (void **)certs, 0, NULL, &status); ok(!ret && GetLastError() == CRYPT_E_NO_REVOCATION_DLL, "Expected CRYPT_E_NO_REVOCATION_DLL, got %08x\n", GetLastError()); - CertFreeCertificateContext(cert); + CertFreeCertificateContext(certs[0]); + + certs[0] = CertCreateCertificateContext(X509_ASN_ENCODING, + rootWithKeySignAndCRLSign, sizeof(rootWithKeySignAndCRLSign)); + certs[1] = CertCreateCertificateContext(X509_ASN_ENCODING, + eeCert, sizeof(eeCert)); + /* The root cert itself can't be checked for revocation */ + SetLastError(0xdeadbeef); + ret = CertVerifyRevocation(X509_ASN_ENCODING, CERT_CONTEXT_REVOCATION_TYPE, + 1, (void **)certs, 0, NULL, &status); + ok(!ret && GetLastError() == CRYPT_E_NO_REVOCATION_CHECK, + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", GetLastError()); + ok(status.dwError == CRYPT_E_NO_REVOCATION_CHECK, + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", status.dwError); + ok(status.dwIndex == 0, "expected index 0, got %d\n", status.dwIndex); + /* Neither can the end cert */ + SetLastError(0xdeadbeef); + ret = CertVerifyRevocation(X509_ASN_ENCODING, CERT_CONTEXT_REVOCATION_TYPE, + 1, (void **)&certs[1], 0, NULL, &status); + ok(!ret && (GetLastError() == CRYPT_E_NO_REVOCATION_CHECK /* Win9x */ || + GetLastError() == CRYPT_E_REVOCATION_OFFLINE), + "expected CRYPT_E_NO_REVOCATION_CHECK or CRYPT_E_REVOCATION_OFFLINE, got %08x\n", + GetLastError()); + ok(status.dwError == CRYPT_E_NO_REVOCATION_CHECK /* Win9x */ || + status.dwError == CRYPT_E_REVOCATION_OFFLINE, + "expected CRYPT_E_NO_REVOCATION_CHECK or CRYPT_E_REVOCATION_OFFLINE, got %08x\n", + status.dwError); + ok(status.dwIndex == 0, "expected index 0, got %d\n", status.dwIndex); + /* Both certs together can't, either (they're not CRLs) */ + SetLastError(0xdeadbeef); + ret = CertVerifyRevocation(X509_ASN_ENCODING, CERT_CONTEXT_REVOCATION_TYPE, + 2, (void **)certs, 0, NULL, &status); + ok(!ret && (GetLastError() == CRYPT_E_NO_REVOCATION_CHECK || + GetLastError() == CRYPT_E_REVOCATION_OFFLINE /* WinME */), + "expected CRYPT_E_NO_REVOCATION_CHECK or CRYPT_E_REVOCATION_OFFLINE, got %08x\n", + GetLastError()); + ok(status.dwError == CRYPT_E_NO_REVOCATION_CHECK || + status.dwError == CRYPT_E_REVOCATION_OFFLINE /* WinME */, + "expected CRYPT_E_NO_REVOCATION_CHECK or CRYPT_E_REVOCATION_OFFLINE, got %08x\n", + status.dwError); + ok(status.dwIndex == 0, "expected index 0, got %d\n", status.dwIndex); + ok(status.dwIndex == 0, "expected index 0, got %d\n", status.dwIndex); + /* Now add a CRL to the hCrlStore */ + revPara.hCrlStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + CertAddEncodedCRLToStore(revPara.hCrlStore, X509_ASN_ENCODING, + rootSignedCRL, sizeof(rootSignedCRL), CERT_STORE_ADD_ALWAYS, NULL); + SetLastError(0xdeadbeef); + ret = CertVerifyRevocation(X509_ASN_ENCODING, CERT_CONTEXT_REVOCATION_TYPE, + 2, (void **)certs, 0, &revPara, &status); + ok(!ret && (GetLastError() == CRYPT_E_NO_REVOCATION_CHECK || + GetLastError() == CRYPT_E_REVOCATION_OFFLINE /* WinME */), + "expected CRYPT_E_NO_REVOCATION_CHECK or CRYPT_E_REVOCATION_OFFLINE, got %08x\n", + GetLastError()); + ok(status.dwError == CRYPT_E_NO_REVOCATION_CHECK || + status.dwError == CRYPT_E_REVOCATION_OFFLINE /* WinME */, + "expected CRYPT_E_NO_REVOCATION_CHECK or CRYPT_E_REVOCATION_OFFLINE, got %08x\n", + status.dwError); + ok(status.dwIndex == 0, "expected index 0, got %d\n", status.dwIndex); + /* Specifying CERT_VERIFY_REV_CHAIN_FLAG doesn't change things either */ + SetLastError(0xdeadbeef); + ret = CertVerifyRevocation(X509_ASN_ENCODING, CERT_CONTEXT_REVOCATION_TYPE, + 2, (void **)certs, CERT_VERIFY_REV_CHAIN_FLAG, &revPara, &status); + ok(!ret && GetLastError() == CRYPT_E_NO_REVOCATION_CHECK, + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", GetLastError()); + ok(status.dwError == CRYPT_E_NO_REVOCATION_CHECK, + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", status.dwError); + ok(status.dwIndex == 0, "expected index 0, got %d\n", status.dwIndex); + /* Again, specifying the issuer cert: no change */ + revPara.pIssuerCert = certs[0]; + SetLastError(0xdeadbeef); + ret = CertVerifyRevocation(X509_ASN_ENCODING, CERT_CONTEXT_REVOCATION_TYPE, + 1, (void **)&certs[1], 0, &revPara, &status); + ok(!ret && GetLastError() == CRYPT_E_NO_REVOCATION_CHECK, + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", GetLastError()); + ok(status.dwError == CRYPT_E_NO_REVOCATION_CHECK, + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", status.dwError); + ok(status.dwIndex == 0, "expected index 0, got %d\n", status.dwIndex); + CertCloseStore(revPara.hCrlStore, 0); + CertFreeCertificateContext(certs[1]); + CertFreeCertificateContext(certs[0]); } static BYTE privKey[] = { @@ -3283,4 +3634,5 @@ START_TEST(cert) testVerifyRevocation(); testAcquireCertPrivateKey(); testGetPublicKeyLength(); + testIsRDNAttrsInCertificateName(); } diff --git a/dlls/crypt32/tests/chain.c b/dlls/crypt32/tests/chain.c index be3a0bddc3b..d41a8ca3a5c 100644 --- a/dlls/crypt32/tests/chain.c +++ b/dlls/crypt32/tests/chain.c @@ -51,6 +51,20 @@ static const BYTE selfSignedCert[] = { 0x22, 0x0d, 0x03, 0x69, 0x32, 0x1a, 0x6d, 0xcb, 0x0c, 0x15, 0xb3, 0x6b, 0xc7, 0x0a, 0x8c, 0xb4, 0x5c, 0x34, 0x78, 0xe0, 0x3c, 0x9c, 0xe9, 0xf3, 0x30, 0x9f, 0xa8, 0x76, 0x57, 0x92, 0x36 }; +static const BYTE v1CRLWithIssuerAndEntry[] = { 0x30, 0x44, 0x30, 0x02, 0x06, + 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, + 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x5a, 0x30, 0x16, 0x30, 0x14, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31, 0x36, + 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a }; +static const BYTE timeValidV1CRLWithIssuerAndEntry[] = { +0x30,0x60,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55, +0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x17, +0x0d,0x30,0x36,0x30,0x36,0x32,0x39,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17, +0x0d,0x30,0x37,0x30,0x36,0x32,0x39,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30, +0x25,0x30,0x23,0x02,0x10,0xeb,0x0d,0x57,0x2a,0x9c,0x09,0xba,0xa4,0x4a,0xb7, +0x25,0x49,0xd9,0x3e,0xb5,0x73,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30, +0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a }; static BOOL (WINAPI *pCertCreateCertificateChainEngine)(PCERT_CHAIN_ENGINE_CONFIG,HCERTCHAINENGINE*); static BOOL (WINAPI *pCertGetCertificateChain)(HCERTCHAINENGINE,PCCERT_CONTEXT,LPFILETIME,HCERTSTORE,PCERT_CHAIN_PARA,DWORD,LPVOID,PCCERT_CHAIN_CONTEXT*); @@ -332,6 +346,80 @@ static const BYTE verisignCA[] = { 0xbb,0x10,0xa4,0x3d,0xf0,0x32,0x03,0x0e,0xf1,0xce,0xf8,0xe8,0xc9,0x51,0x8c, 0xe6,0x62,0x9f,0xe6,0x9f,0xc0,0x7d,0xb7,0x72,0x9c,0xc9,0x36,0x3a,0x6b,0x9f, 0x4e,0xa8,0xff,0x64,0x0d,0x64 }; +static const BYTE verisignCommercialSoftPubCA[] = { +0x30,0x82,0x02,0x40,0x30,0x82,0x01,0xa9,0x02,0x10,0x03,0xc7,0x8f,0x37,0xdb,0x92, +0x28,0xdf,0x3c,0xbb,0x1a,0xad,0x82,0xfa,0x67,0x10,0x30,0x0d,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x01,0x02,0x05,0x00,0x30,0x61,0x31,0x11,0x30,0x0f,0x06, +0x03,0x55,0x04,0x07,0x13,0x08,0x49,0x6e,0x74,0x65,0x72,0x6e,0x65,0x74,0x31,0x17, +0x30,0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65,0x72,0x69,0x53,0x69,0x67, +0x6e,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x33,0x30,0x31,0x06,0x03,0x55,0x04,0x0b, +0x13,0x2a,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e,0x20,0x43,0x6f,0x6d,0x6d,0x65, +0x72,0x63,0x69,0x61,0x6c,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x20,0x50, +0x75,0x62,0x6c,0x69,0x73,0x68,0x65,0x72,0x73,0x20,0x43,0x41,0x30,0x1e,0x17,0x0d, +0x39,0x36,0x30,0x34,0x30,0x39,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30, +0x34,0x30,0x31,0x30,0x37,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x61,0x31,0x11, +0x30,0x0f,0x06,0x03,0x55,0x04,0x07,0x13,0x08,0x49,0x6e,0x74,0x65,0x72,0x6e,0x65, +0x74,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65,0x72,0x69, +0x53,0x69,0x67,0x6e,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x33,0x30,0x31,0x06,0x03, +0x55,0x04,0x0b,0x13,0x2a,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e,0x20,0x43,0x6f, +0x6d,0x6d,0x65,0x72,0x63,0x69,0x61,0x6c,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72, +0x65,0x20,0x50,0x75,0x62,0x6c,0x69,0x73,0x68,0x65,0x72,0x73,0x20,0x43,0x41,0x30, +0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05, +0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xc3,0xd3,0x69,0x65, +0x52,0x01,0x94,0x54,0xab,0x28,0xc6,0x62,0x18,0xb3,0x54,0x55,0xc5,0x44,0x87,0x45, +0x4a,0x3b,0xc2,0x7e,0xd8,0xd3,0xd7,0xc8,0x80,0x86,0x8d,0xd8,0x0c,0xf1,0x16,0x9c, +0xcc,0x6b,0xa9,0x29,0xb2,0x8f,0x76,0x73,0x92,0xc8,0xc5,0x62,0xa6,0x3c,0xed,0x1e, +0x05,0x75,0xf0,0x13,0x00,0x6c,0x14,0x4d,0xd4,0x98,0x90,0x07,0xbe,0x69,0x73,0x81, +0xb8,0x62,0x4e,0x31,0x1e,0xd1,0xfc,0xc9,0x0c,0xeb,0x7d,0x90,0xbf,0xae,0xb4,0x47, +0x51,0xec,0x6f,0xce,0x64,0x35,0x02,0xd6,0x7d,0x67,0x05,0x77,0xe2,0x8f,0xd9,0x51, +0xd7,0xfb,0x97,0x19,0xbc,0x3e,0xd7,0x77,0x81,0xc6,0x43,0xdd,0xf2,0xdd,0xdf,0xca, +0xa3,0x83,0x8b,0xcb,0x41,0xc1,0x3d,0x22,0x48,0x48,0xa6,0x19,0x02,0x03,0x01,0x00, +0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x02,0x05,0x00, +0x03,0x81,0x81,0x00,0xb5,0xbc,0xb0,0x75,0x6a,0x89,0xa2,0x86,0xbd,0x64,0x78,0xc3, +0xa7,0x32,0x75,0x72,0x11,0xaa,0x26,0x02,0x17,0x60,0x30,0x4c,0xe3,0x48,0x34,0x19, +0xb9,0x52,0x4a,0x51,0x18,0x80,0xfe,0x53,0x2d,0x7b,0xd5,0x31,0x8c,0xc5,0x65,0x99, +0x41,0x41,0x2f,0xf2,0xae,0x63,0x7a,0xe8,0x73,0x99,0x15,0x90,0x1a,0x1f,0x7a,0x8b, +0x41,0xd0,0x8e,0x3a,0xd0,0xcd,0x38,0x34,0x44,0xd0,0x75,0xf8,0xea,0x71,0xc4,0x81, +0x19,0x38,0x17,0x35,0x4a,0xae,0xc5,0x3e,0x32,0xe6,0x21,0xb8,0x05,0xc0,0x93,0xe1, +0xc7,0x38,0x5c,0xd8,0xf7,0x93,0x38,0x64,0x90,0xed,0x54,0xce,0xca,0xd3,0xd3,0xd0, +0x5f,0xef,0x04,0x9b,0xde,0x02,0x82,0xdd,0x88,0x29,0xb1,0xc3,0x4f,0xa5,0xcd,0x71, +0x64,0x31,0x3c,0x3c +}; +static const BYTE verisignCRL[] = { 0x30, 0x82, 0x01, 0xb1, 0x30, 0x82, 0x01, + 0x1a, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x02, 0x05, 0x00, 0x30, 0x61, 0x31, 0x11, 0x30, 0x0f, 0x06, + 0x03, 0x55, 0x04, 0x07, 0x13, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, + 0x74, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56, + 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x56, 0x65, + 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x72, + 0x63, 0x69, 0x61, 0x6c, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, + 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x72, 0x73, 0x20, 0x43, + 0x41, 0x17, 0x0d, 0x30, 0x31, 0x30, 0x33, 0x32, 0x34, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x30, 0x34, 0x30, 0x31, 0x30, 0x37, 0x32, 0x33, + 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x69, 0x30, 0x21, 0x02, 0x10, 0x1b, 0x51, + 0x90, 0xf7, 0x37, 0x24, 0x39, 0x9c, 0x92, 0x54, 0xcd, 0x42, 0x46, 0x37, 0x99, + 0x6a, 0x17, 0x0d, 0x30, 0x31, 0x30, 0x31, 0x33, 0x30, 0x30, 0x30, 0x30, 0x31, + 0x32, 0x34, 0x5a, 0x30, 0x21, 0x02, 0x10, 0x75, 0x0e, 0x40, 0xff, 0x97, 0xf0, + 0x47, 0xed, 0xf5, 0x56, 0xc7, 0x08, 0x4e, 0xb1, 0xab, 0xfd, 0x17, 0x0d, 0x30, + 0x31, 0x30, 0x31, 0x33, 0x31, 0x30, 0x30, 0x30, 0x30, 0x34, 0x39, 0x5a, 0x30, + 0x21, 0x02, 0x10, 0x77, 0xe6, 0x5a, 0x43, 0x59, 0x93, 0x5d, 0x5f, 0x7a, 0x75, + 0x80, 0x1a, 0xcd, 0xad, 0xc2, 0x22, 0x17, 0x0d, 0x30, 0x30, 0x30, 0x38, 0x33, + 0x31, 0x30, 0x30, 0x30, 0x30, 0x35, 0x36, 0x5a, 0xa0, 0x1a, 0x30, 0x18, 0x30, + 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0b, 0x06, + 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x02, 0x05, 0x00, 0x03, + 0x81, 0x81, 0x00, 0x18, 0x2c, 0xe8, 0xfc, 0x16, 0x6d, 0x91, 0x4a, 0x3d, 0x88, + 0x54, 0x48, 0x5d, 0xb8, 0x11, 0xbf, 0x64, 0xbb, 0xf9, 0xda, 0x59, 0x19, 0xdd, + 0x0e, 0x65, 0xab, 0xc0, 0x0c, 0xfa, 0x67, 0x7e, 0x21, 0x1e, 0x83, 0x0e, 0xcf, + 0x9b, 0x89, 0x8a, 0xcf, 0x0c, 0x4b, 0xc1, 0x39, 0x9d, 0xe7, 0x6a, 0xac, 0x46, + 0x74, 0x6a, 0x91, 0x62, 0x22, 0x0d, 0xc4, 0x08, 0xbd, 0xf5, 0x0a, 0x90, 0x7f, + 0x06, 0x21, 0x3d, 0x7e, 0xa7, 0xaa, 0x5e, 0xcd, 0x22, 0x15, 0xe6, 0x0c, 0x75, + 0x8e, 0x6e, 0xad, 0xf1, 0x84, 0xe4, 0x22, 0xb4, 0x30, 0x6f, 0xfb, 0x64, 0x8f, + 0xd7, 0x80, 0x43, 0xf5, 0x19, 0x18, 0x66, 0x1d, 0x72, 0xa3, 0xe3, 0x94, 0x82, + 0x28, 0x52, 0xa0, 0x06, 0x4e, 0xb1, 0xc8, 0x92, 0x0c, 0x97, 0xbe, 0x15, 0x07, + 0xab, 0x7a, 0xc9, 0xea, 0x08, 0x67, 0x43, 0x4d, 0x51, 0x63, 0x3b, 0x9c, 0x9c, + 0xcd }; /* www.google.com's cert */ static const BYTE google[] = { 0x30,0x82,0x03,0x21,0x30,0x82,0x02,0x8a,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, @@ -2456,6 +2544,91 @@ static const BYTE chain28_1[] = { 0x44,0x76,0x66,0x26,0xa7,0x05,0x3c,0x68,0x66,0x1c,0x07,0x4d,0xcf,0x54,0xaa, 0x5d,0xba,0x7a,0x8f,0x06,0xa7,0x1e,0x86,0xf1,0x5a,0x4b,0x50,0x16,0xad,0x9f, 0x89 }; +/* chain29_0 -> chain29_1: a chain with a CRL issued for chain29_1 */ +static const BYTE chain29_0[] = { +0x30,0x82,0x01,0xdf,0x30,0x82,0x01,0x4c,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x5b,0xc7,0x0b,0x27,0x99,0xbb,0x2e,0x99,0x47,0x9d,0x45,0x4e,0x7c,0x1a,0xca, +0xe8,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x30,0x10,0x31, +0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31, +0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05, +0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x42,0x30,0x40,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x06,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x1d,0x06,0x03,0x55,0x1d, +0x0e,0x04,0x16,0x04,0x14,0x14,0x8c,0x16,0xbb,0xbe,0x70,0xa2,0x28,0x89,0xa0, +0x58,0xff,0x98,0xbd,0xa8,0x24,0x2b,0x8a,0xe9,0x9a,0x30,0x09,0x06,0x05,0x2b, +0x0e,0x03,0x02,0x1d,0x05,0x00,0x03,0x81,0x81,0x00,0x74,0xcb,0x21,0xfd,0x2d, +0x25,0xdc,0xa5,0xaa,0xa1,0x26,0xdc,0x8b,0x40,0x11,0x64,0xae,0x5c,0x71,0x3c, +0x28,0xbc,0xf9,0xb3,0xcb,0xa5,0x94,0xb2,0x8d,0x4c,0x23,0x2b,0x9b,0xde,0x2c, +0x4c,0x30,0x04,0xc6,0x88,0x10,0x2f,0x53,0xfd,0x6c,0x82,0xf1,0x13,0xfb,0xda, +0x27,0x75,0x25,0x48,0xe4,0x72,0x09,0x2a,0xee,0xb4,0x1e,0xc9,0x55,0xf5,0xf7, +0x82,0x91,0xd8,0x4b,0xe4,0x3a,0xfe,0x97,0x87,0xdf,0xfb,0x15,0x5a,0x12,0x3e, +0x12,0xe6,0xad,0x40,0x0b,0xcf,0xee,0x1a,0x44,0xe0,0x83,0xb2,0x67,0x94,0xd4, +0x2e,0x7c,0xf2,0x06,0x9d,0xb3,0x3b,0x7e,0x2f,0xda,0x25,0x66,0x7e,0xa7,0x1f, +0x45,0xd4,0xf5,0xe3,0xdf,0x2a,0xf1,0x18,0x28,0x20,0xb5,0xf8,0xf5,0x8d,0x7a, +0x2e,0x84,0xee }; +static const BYTE chain29_1[] = { +0x30,0x82,0x01,0x93,0x30,0x81,0xfd,0xa0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00, +0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65, +0x72,0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x35,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x30,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04, +0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09, +0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00, +0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5,0x33, +0x0e,0x67,0x5f,0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6,0xdc, +0xb6,0x17,0x8e,0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7,0x48, +0x9f,0x6e,0xfe,0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b,0x47, +0xd1,0x57,0x71,0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b,0x05, +0x72,0xa7,0x87,0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc,0x6a, +0x80,0x83,0x68,0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85,0x85, +0xb5,0x46,0x36,0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2,0xd3, +0x51,0x9a,0x22,0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72,0xa3, +0x02,0x03,0x01,0x00,0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x22,0xf1,0x66,0x00,0x79,0xd2, +0xe6,0xb2,0xb2,0xf7,0x2f,0x98,0x92,0x7d,0x73,0xc3,0x6c,0x5c,0x77,0x20,0xe3, +0xbf,0x3e,0xe0,0xb3,0x5c,0x68,0xb4,0x9b,0x3a,0x41,0xae,0x94,0xa0,0x80,0x3a, +0xfe,0x5d,0x7a,0x56,0x87,0x85,0x44,0x45,0xcf,0xa6,0xd3,0x10,0xe7,0x73,0x41, +0xf2,0x7f,0x88,0x85,0x91,0x8e,0xe6,0xec,0xe2,0xce,0x08,0xbc,0xa5,0x76,0xe5, +0x4d,0x1d,0xb7,0x70,0x31,0xdd,0xc9,0x9a,0x15,0x32,0x11,0x5a,0x4e,0x62,0xc8, +0xd1,0xf8,0xec,0x46,0x39,0x5b,0xe7,0x67,0x1f,0x58,0xe8,0xa1,0xa0,0x5b,0xf7, +0x8a,0x6d,0x5f,0x91,0x18,0xd4,0x90,0x85,0xff,0x30,0xc7,0xca,0x9c,0xc6,0x92, +0xb0,0xca,0x16,0xc4,0xa4,0xc0,0xd6,0xe8,0xff,0x15,0x19,0xd1,0x30,0x61,0xf3, +0xef,0x9f }; +static const BYTE chain29_0_crl[] = { +0x30,0x82,0x01,0x1d,0x30,0x81,0x87,0x02,0x01,0x01,0x30,0x0d,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x10,0x31,0x0e,0x30, +0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31,0x17,0x0d, +0x30,0x37,0x30,0x39,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d, +0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x14, +0x30,0x12,0x02,0x01,0x01,0x17,0x0d,0x30,0x37,0x30,0x39,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0xa0,0x2d,0x30,0x2b,0x30,0x0a,0x06,0x03,0x55,0x1d, +0x14,0x04,0x03,0x02,0x01,0x01,0x30,0x1d,0x06,0x03,0x55,0x1d,0x23,0x04,0x16, +0x04,0x14,0x14,0x8c,0x16,0xbb,0xbe,0x70,0xa2,0x28,0x89,0xa0,0x58,0xff,0x98, +0xbd,0xa8,0x24,0x2b,0x8a,0xe9,0x9a,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86, +0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x9b,0x2b,0x99,0x0d, +0x16,0x83,0x93,0x54,0x29,0x3a,0xa6,0x53,0x5d,0xf8,0xa6,0x73,0x9f,0x2a,0x45, +0x39,0x91,0xff,0x91,0x1c,0x27,0x06,0xe8,0xdb,0x72,0x3f,0x66,0x89,0x15,0x68, +0x55,0xd5,0x49,0x63,0xa6,0x00,0xe9,0x66,0x9c,0x97,0xf9,0xb3,0xb3,0x2b,0x1b, +0xc7,0x79,0x46,0xa8,0xd8,0x2b,0x78,0x27,0xa0,0x70,0x02,0x81,0xc6,0x40,0xb3, +0x76,0x32,0x65,0x4c,0xf8,0xff,0x1d,0x41,0x6e,0x16,0x09,0xa2,0x8a,0x7b,0x0c, +0xd0,0xa6,0x9b,0x61,0xa3,0x7c,0x02,0x91,0x79,0xdf,0x6a,0x5e,0x88,0x95,0x66, +0x33,0x17,0xcb,0x5a,0xd2,0xdc,0x89,0x05,0x62,0x97,0x60,0x73,0x7b,0x2c,0x1a, +0x90,0x20,0x73,0x24,0x9f,0x45,0x22,0x4b,0xc1,0x33,0xd1,0xda,0xd8,0x7e,0x1b, +0x3d,0x74,0xd6,0x3b }; typedef struct _CONST_DATA_BLOB { @@ -2927,7 +3100,8 @@ static CONST_DATA_BLOB chain19[] = { static const CERT_TRUST_STATUS elementStatus19[] = { { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, { CERT_TRUST_IS_UNTRUSTED_ROOT, - CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER | + CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS }, }; static const SimpleChainStatusCheck simpleStatus19[] = { { sizeof(elementStatus19) / sizeof(elementStatus19[0]), elementStatus19 }, @@ -2951,7 +3125,8 @@ static CONST_DATA_BLOB chain21[] = { static const CERT_TRUST_STATUS elementStatus21[] = { { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, { CERT_TRUST_IS_UNTRUSTED_ROOT, - CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER | + CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS }, }; static const SimpleChainStatusCheck simpleStatus21[] = { { sizeof(elementStatus21) / sizeof(elementStatus21[0]), elementStatus21 }, @@ -3032,8 +3207,7 @@ static const SimpleChainStatusCheck simpleStatus27[] = { static const CERT_TRUST_STATUS elementStatus27Broken[] = { { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, { CERT_TRUST_IS_UNTRUSTED_ROOT, - CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER | - CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS }, + CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER }, }; static const SimpleChainStatusCheck simpleStatus27Broken[] = { { sizeof(elementStatus27Broken) / sizeof(elementStatus27Broken[0]), @@ -3257,7 +3431,7 @@ static ChainCheck chainCheck[] = { CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT, CERT_TRUST_HAS_PREFERRED_ISSUER | CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS }, - { CERT_TRUST_IS_UNTRUSTED_ROOT, 0 }, + { CERT_TRUST_IS_UNTRUSTED_ROOT, CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS }, 1, simpleStatus19 }, 0 }, /* Older versions of crypt32 do not set @@ -3278,7 +3452,7 @@ static ChainCheck chainCheck[] = { CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT, CERT_TRUST_HAS_PREFERRED_ISSUER | CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS }, - { CERT_TRUST_IS_UNTRUSTED_ROOT, 0 }, + { CERT_TRUST_IS_UNTRUSTED_ROOT, CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS }, 1, simpleStatus21 }, 0 }, { { sizeof(chain22) / sizeof(chain22[0]), chain22 }, @@ -3406,10 +3580,15 @@ static ChainCheck chainCheckEmbeddedNullBroken = { { { CERT_TRUST_IS_NOT_TIME_NESTED | CERT_TRUST_IS_NOT_VALID_FOR_USAGE | CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT, CERT_TRUST_HAS_PREFERRED_ISSUER }, - { CERT_TRUST_IS_UNTRUSTED_ROOT, CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT, + 0 }, 1, simpleStatus27Broken }, 0 }; +/* Thursday, Jan 1, 2004 */ +static SYSTEMTIME jan2004 = { 2004, 1, 4, 1, 0, 0, 0, 0 }; +/* Sunday, Oct 1, 2006 */ +static SYSTEMTIME oct2006 = { 2006, 10, 0, 1, 0, 0, 0, 0 }; /* Wednesday, Oct 1, 2007 */ static SYSTEMTIME oct2007 = { 2007, 10, 1, 1, 0, 0, 0, 0 }; /* Wednesday, Oct 28, 2009 */ @@ -3421,7 +3600,15 @@ static void testGetCertChain(void) PCCERT_CONTEXT cert; CERT_CHAIN_PARA para = { 0 }; PCCERT_CHAIN_CONTEXT chain; + FILETIME fileTime; DWORD i; + DWORD revocationFlags = + CERT_TRUST_IS_REVOKED | CERT_TRUST_REVOCATION_STATUS_UNKNOWN | + CERT_TRUST_IS_OFFLINE_REVOCATION; + HCERTSTORE store; + static char one_two_three[] = "1.2.3"; + static char oid_server_auth[] = szOID_PKIX_KP_SERVER_AUTH; + LPSTR oids[2]; /* Basic parameter checks */ if (0) @@ -3481,6 +3668,232 @@ static void testGetCertChain(void) CertFreeCertificateContext(cert); + /* Check revocation flags */ + cert = CertCreateCertificateContext(X509_ASN_ENCODING, + verisignCommercialSoftPubCA, sizeof(verisignCommercialSoftPubCA)); + SystemTimeToFileTime(&jan2004, &fileTime); + ret = pCertGetCertificateChain(NULL, cert, &fileTime, NULL, ¶, 0, NULL, + &chain); + ok(ret, "CertGetCertificateChain failed: %08x\n", GetLastError()); + if (ret) + { + /* When no revocation check is asked for, none is received */ + ok(!(chain->TrustStatus.dwErrorStatus & revocationFlags), + "unexpected revocation status %08x\n", + chain->TrustStatus.dwErrorStatus & revocationFlags); + CertFreeCertificateChain(chain); + } + ret = pCertGetCertificateChain(NULL, cert, &fileTime, NULL, ¶, + CERT_CHAIN_REVOCATION_CHECK_CHAIN, NULL, &chain); + ok(ret, "CertGetCertificateChain failed: %08x\n", GetLastError()); + if (ret) + { + /* The cert is rather old, so its revocation list can't be retrieved, + * and its revocation status should be both offline and unknown. + */ + ok((chain->TrustStatus.dwErrorStatus & revocationFlags) == + (CERT_TRUST_REVOCATION_STATUS_UNKNOWN | + CERT_TRUST_IS_OFFLINE_REVOCATION), + "unexpected revocation status %08x\n", + chain->TrustStatus.dwErrorStatus & revocationFlags); + CertFreeCertificateChain(chain); + } + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + verisignCommercialSoftPubCA, sizeof(verisignCommercialSoftPubCA), + CERT_STORE_ADD_ALWAYS, NULL); + CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, verisignCRL, + sizeof(verisignCRL), CERT_STORE_ADD_ALWAYS, NULL); + ret = pCertGetCertificateChain(NULL, cert, &fileTime, store, ¶, + CERT_CHAIN_REVOCATION_CHECK_CHAIN, NULL, &chain); + ok(ret, "CertGetCertificateChain failed: %08x\n", GetLastError()); + if (ret) + { + /* Even with a CRL in the store, the revocation status doesn't change */ + ok((chain->TrustStatus.dwErrorStatus & revocationFlags) == + (CERT_TRUST_REVOCATION_STATUS_UNKNOWN | + CERT_TRUST_IS_OFFLINE_REVOCATION), + "unexpected revocation status %08x\n", + chain->TrustStatus.dwErrorStatus & revocationFlags); + CertFreeCertificateChain(chain); + } + CertCloseStore(store, 0); + CertFreeCertificateContext(cert); + /* Again, with some hand-made certs that don't contain CRL distribution + * point extensions or the like. + */ + cert = CertCreateCertificateContext(X509_ASN_ENCODING, + selfSignedCert, sizeof(selfSignedCert)); + SystemTimeToFileTime(&oct2007, &fileTime); + ret = pCertGetCertificateChain(NULL, cert, &fileTime, NULL, ¶, 0, NULL, + &chain); + ok(ret, "CertGetCertificateChain failed: %08x\n", GetLastError()); + if (ret) + { + /* When no revocation check is asked for, none is received */ + ok(!(chain->TrustStatus.dwErrorStatus & revocationFlags), + "unexpected revocation status %08x\n", + chain->TrustStatus.dwErrorStatus & revocationFlags); + CertFreeCertificateChain(chain); + } + ret = pCertGetCertificateChain(NULL, cert, &fileTime, NULL, ¶, + CERT_CHAIN_REVOCATION_CHECK_CHAIN, NULL, &chain); + ok(ret, "CertGetCertificateChain failed: %08x\n", GetLastError()); + if (ret) + { + /* The cert doesn't have a way to retrieve its CRL, so its revocation + * status should be both offline and unknown. + */ + ok((chain->TrustStatus.dwErrorStatus & revocationFlags) == + (CERT_TRUST_REVOCATION_STATUS_UNKNOWN | + CERT_TRUST_IS_OFFLINE_REVOCATION), + "unexpected revocation status %08x\n", + chain->TrustStatus.dwErrorStatus & revocationFlags); + CertFreeCertificateChain(chain); + } + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + v1CRLWithIssuerAndEntry, sizeof(v1CRLWithIssuerAndEntry), + CERT_STORE_ADD_ALWAYS, NULL); + CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, verisignCRL, + sizeof(verisignCRL), CERT_STORE_ADD_ALWAYS, NULL); + ret = pCertGetCertificateChain(NULL, cert, &fileTime, store, ¶, + CERT_CHAIN_REVOCATION_CHECK_CHAIN, NULL, &chain); + ok(ret, "CertGetCertificateChain failed: %08x\n", GetLastError()); + if (ret) + { + /* Even with a CRL in the store, the revocation status doesn't change */ + ok((chain->TrustStatus.dwErrorStatus & revocationFlags) == + (CERT_TRUST_REVOCATION_STATUS_UNKNOWN | + CERT_TRUST_IS_OFFLINE_REVOCATION), + "unexpected revocation status %08x\n", + chain->TrustStatus.dwErrorStatus & revocationFlags); + CertFreeCertificateChain(chain); + } + CertCloseStore(store, 0); + CertFreeCertificateContext(cert); + /* Yet again, again with some hand-made certs that don't contain CRL + * distribution point extensions or the like, even though a time-valid + * CRL is in the store. + */ + cert = CertCreateCertificateContext(X509_ASN_ENCODING, + selfSignedCert, sizeof(selfSignedCert)); + SystemTimeToFileTime(&oct2006, &fileTime); + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, selfSignedCert, + sizeof(selfSignedCert), CERT_STORE_ADD_ALWAYS, NULL); + CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, + timeValidV1CRLWithIssuerAndEntry, sizeof(timeValidV1CRLWithIssuerAndEntry), + CERT_STORE_ADD_ALWAYS, NULL); + ret = pCertGetCertificateChain(NULL, cert, &fileTime, store, ¶, + CERT_CHAIN_REVOCATION_CHECK_CHAIN, NULL, &chain); + ok(ret, "CertGetCertificateChain failed: %08x\n", GetLastError()); + if (ret) + { + /* Even with a CRL in the store, the revocation status doesn't change */ + ok((chain->TrustStatus.dwErrorStatus & revocationFlags) == + (CERT_TRUST_REVOCATION_STATUS_UNKNOWN | + CERT_TRUST_IS_OFFLINE_REVOCATION), + "unexpected revocation status %08x\n", + chain->TrustStatus.dwErrorStatus & revocationFlags); + CertFreeCertificateChain(chain); + } + CertCloseStore(store, 0); + CertFreeCertificateContext(cert); + /* Yet again, again with some hand-made certs that don't contain CRL + * distribution point extensions or the like, even though a time-valid + * CRL is in the store. + */ + cert = CertCreateCertificateContext(X509_ASN_ENCODING, + chain29_1, sizeof(chain29_1)); + SystemTimeToFileTime(&oct2007, &fileTime); + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, chain29_0, + sizeof(chain29_0), CERT_STORE_ADD_ALWAYS, NULL); + CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, + chain29_0_crl, sizeof(chain29_0_crl), CERT_STORE_ADD_ALWAYS, NULL); + ret = pCertGetCertificateChain(NULL, cert, &fileTime, store, ¶, + CERT_CHAIN_REVOCATION_CHECK_CHAIN, NULL, &chain); + ok(ret, "CertGetCertificateChain failed: %08x\n", GetLastError()); + if (ret) + { + /* Even with a CRL in the store, the revocation status doesn't change */ + ok((chain->TrustStatus.dwErrorStatus & revocationFlags) == + (CERT_TRUST_REVOCATION_STATUS_UNKNOWN | + CERT_TRUST_IS_OFFLINE_REVOCATION), + "unexpected revocation status %08x\n", + chain->TrustStatus.dwErrorStatus & revocationFlags); + CertFreeCertificateChain(chain); + } + CertCloseStore(store, 0); + CertFreeCertificateContext(cert); + + /* Test usage match with Google's cert */ + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + verisignCA, sizeof(verisignCA), CERT_STORE_ADD_ALWAYS, NULL); + CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + thawte_sgc_ca, sizeof(thawte_sgc_ca), CERT_STORE_ADD_ALWAYS, NULL); + cert = CertCreateCertificateContext(X509_ASN_ENCODING, + google, sizeof(google)); + SystemTimeToFileTime(&oct2009, &fileTime); + memset(¶, 0, sizeof(para)); + para.cbSize = sizeof(para); + oids[0] = one_two_three; + para.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND; + para.RequestedUsage.Usage.rgpszUsageIdentifier = oids; + para.RequestedUsage.Usage.cUsageIdentifier = 1; + ret = pCertGetCertificateChain(NULL, cert, &fileTime, store, ¶, + 0, NULL, &chain); + ok(ret, "CertGetCertificateChain failed: %08x\n", GetLastError()); + if (ret) + { + ok(chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE, + "expected CERT_TRUST_IS_NOT_VALID_FOR_USAGE\n"); + CertFreeCertificateChain(chain); + } + oids[0] = oid_server_auth; + ret = pCertGetCertificateChain(NULL, cert, &fileTime, store, ¶, + 0, NULL, &chain); + ok(ret, "CertGetCertificateChain failed: %08x\n", GetLastError()); + if (ret) + { + ok(!(chain->TrustStatus.dwErrorStatus & + CERT_TRUST_IS_NOT_VALID_FOR_USAGE), + "didn't expect CERT_TRUST_IS_NOT_VALID_FOR_USAGE\n"); + CertFreeCertificateChain(chain); + } + oids[1] = one_two_three; + para.RequestedUsage.Usage.cUsageIdentifier = 2; + para.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND; + ret = pCertGetCertificateChain(NULL, cert, &fileTime, store, ¶, + 0, NULL, &chain); + ok(ret, "CertGetCertificateChain failed: %08x\n", GetLastError()); + if (ret) + { + ok(chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE, + "expected CERT_TRUST_IS_NOT_VALID_FOR_USAGE\n"); + CertFreeCertificateChain(chain); + } + para.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; + ret = pCertGetCertificateChain(NULL, cert, &fileTime, store, ¶, + 0, NULL, &chain); + ok(ret, "CertGetCertificateChain failed: %08x\n", GetLastError()); + if (ret) + { + ok(!(chain->TrustStatus.dwErrorStatus & + CERT_TRUST_IS_NOT_VALID_FOR_USAGE), + "didn't expect CERT_TRUST_IS_NOT_VALID_FOR_USAGE\n"); + CertFreeCertificateChain(chain); + } + CertCloseStore(store, 0); + CertFreeCertificateContext(cert); + for (i = 0; i < sizeof(chainCheck) / sizeof(chainCheck[0]); i++) { chain = getChain(&chainCheck[i].certs, 0, TRUE, &oct2007, @@ -3510,8 +3923,10 @@ static void testGetCertChain(void) { ok(chain->TrustStatus.dwErrorStatus == chainCheckEmbeddedNull.status.status.dwErrorStatus || - broken(chain->TrustStatus.dwErrorStatus == - chainCheckEmbeddedNullBroken.status.status.dwErrorStatus), + broken((chain->TrustStatus.dwErrorStatus & + ~chainCheckEmbeddedNullBroken.status.statusToIgnore.dwErrorStatus) == + (chainCheckEmbeddedNullBroken.status.status.dwErrorStatus & + ~chainCheckEmbeddedNullBroken.status.statusToIgnore.dwErrorStatus)), "unexpected chain error status %08x\n", chain->TrustStatus.dwErrorStatus); if (chainCheckEmbeddedNull.status.status.dwErrorStatus == diff --git a/dlls/crypt32/tests/crl.c b/dlls/crypt32/tests/crl.c index 1b8cb18e4d1..bb622198aa7 100644 --- a/dlls/crypt32/tests/crl.c +++ b/dlls/crypt32/tests/crl.c @@ -223,12 +223,188 @@ static void testAddCRL(void) CertCloseStore(store, 0); } +static const BYTE v1CRLWithIssuerAndEntry[] = { 0x30, 0x44, 0x30, 0x02, 0x06, + 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, + 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x5a, 0x30, 0x16, 0x30, 0x14, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31, 0x36, + 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a }; +static const BYTE v2CRLWithIssuingDistPoint[] = { +0x30,0x70,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30, +0x30,0x30,0x30,0x5a,0x30,0x16,0x30,0x14,0x02,0x01,0x01,0x18,0x0f,0x31,0x36, +0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0xa0,0x27, +0x30,0x25,0x30,0x23,0x06,0x03,0x55,0x1d,0x1c,0x01,0x01,0xff,0x04,0x19,0x30, +0x17,0xa0,0x15,0xa0,0x13,0x86,0x11,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77, +0x69,0x6e,0x65,0x68,0x71,0x2e,0x6f,0x72,0x67 }; +static const BYTE verisignCRL[] = { 0x30, 0x82, 0x01, 0xb1, 0x30, 0x82, 0x01, + 0x1a, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x02, 0x05, 0x00, 0x30, 0x61, 0x31, 0x11, 0x30, 0x0f, 0x06, + 0x03, 0x55, 0x04, 0x07, 0x13, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, + 0x74, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56, + 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x56, 0x65, + 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x72, + 0x63, 0x69, 0x61, 0x6c, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, + 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x72, 0x73, 0x20, 0x43, + 0x41, 0x17, 0x0d, 0x30, 0x31, 0x30, 0x33, 0x32, 0x34, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x30, 0x34, 0x30, 0x31, 0x30, 0x37, 0x32, 0x33, + 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x69, 0x30, 0x21, 0x02, 0x10, 0x1b, 0x51, + 0x90, 0xf7, 0x37, 0x24, 0x39, 0x9c, 0x92, 0x54, 0xcd, 0x42, 0x46, 0x37, 0x99, + 0x6a, 0x17, 0x0d, 0x30, 0x31, 0x30, 0x31, 0x33, 0x30, 0x30, 0x30, 0x30, 0x31, + 0x32, 0x34, 0x5a, 0x30, 0x21, 0x02, 0x10, 0x75, 0x0e, 0x40, 0xff, 0x97, 0xf0, + 0x47, 0xed, 0xf5, 0x56, 0xc7, 0x08, 0x4e, 0xb1, 0xab, 0xfd, 0x17, 0x0d, 0x30, + 0x31, 0x30, 0x31, 0x33, 0x31, 0x30, 0x30, 0x30, 0x30, 0x34, 0x39, 0x5a, 0x30, + 0x21, 0x02, 0x10, 0x77, 0xe6, 0x5a, 0x43, 0x59, 0x93, 0x5d, 0x5f, 0x7a, 0x75, + 0x80, 0x1a, 0xcd, 0xad, 0xc2, 0x22, 0x17, 0x0d, 0x30, 0x30, 0x30, 0x38, 0x33, + 0x31, 0x30, 0x30, 0x30, 0x30, 0x35, 0x36, 0x5a, 0xa0, 0x1a, 0x30, 0x18, 0x30, + 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0b, 0x06, + 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x02, 0x05, 0x00, 0x03, + 0x81, 0x81, 0x00, 0x18, 0x2c, 0xe8, 0xfc, 0x16, 0x6d, 0x91, 0x4a, 0x3d, 0x88, + 0x54, 0x48, 0x5d, 0xb8, 0x11, 0xbf, 0x64, 0xbb, 0xf9, 0xda, 0x59, 0x19, 0xdd, + 0x0e, 0x65, 0xab, 0xc0, 0x0c, 0xfa, 0x67, 0x7e, 0x21, 0x1e, 0x83, 0x0e, 0xcf, + 0x9b, 0x89, 0x8a, 0xcf, 0x0c, 0x4b, 0xc1, 0x39, 0x9d, 0xe7, 0x6a, 0xac, 0x46, + 0x74, 0x6a, 0x91, 0x62, 0x22, 0x0d, 0xc4, 0x08, 0xbd, 0xf5, 0x0a, 0x90, 0x7f, + 0x06, 0x21, 0x3d, 0x7e, 0xa7, 0xaa, 0x5e, 0xcd, 0x22, 0x15, 0xe6, 0x0c, 0x75, + 0x8e, 0x6e, 0xad, 0xf1, 0x84, 0xe4, 0x22, 0xb4, 0x30, 0x6f, 0xfb, 0x64, 0x8f, + 0xd7, 0x80, 0x43, 0xf5, 0x19, 0x18, 0x66, 0x1d, 0x72, 0xa3, 0xe3, 0x94, 0x82, + 0x28, 0x52, 0xa0, 0x06, 0x4e, 0xb1, 0xc8, 0x92, 0x0c, 0x97, 0xbe, 0x15, 0x07, + 0xab, 0x7a, 0xc9, 0xea, 0x08, 0x67, 0x43, 0x4d, 0x51, 0x63, 0x3b, 0x9c, 0x9c, + 0xcd }; +static const BYTE verisignCommercialSoftPubCA[] = { +0x30,0x82,0x02,0x40,0x30,0x82,0x01,0xa9,0x02,0x10,0x03,0xc7,0x8f,0x37,0xdb,0x92, +0x28,0xdf,0x3c,0xbb,0x1a,0xad,0x82,0xfa,0x67,0x10,0x30,0x0d,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x01,0x02,0x05,0x00,0x30,0x61,0x31,0x11,0x30,0x0f,0x06, +0x03,0x55,0x04,0x07,0x13,0x08,0x49,0x6e,0x74,0x65,0x72,0x6e,0x65,0x74,0x31,0x17, +0x30,0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65,0x72,0x69,0x53,0x69,0x67, +0x6e,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x33,0x30,0x31,0x06,0x03,0x55,0x04,0x0b, +0x13,0x2a,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e,0x20,0x43,0x6f,0x6d,0x6d,0x65, +0x72,0x63,0x69,0x61,0x6c,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x20,0x50, +0x75,0x62,0x6c,0x69,0x73,0x68,0x65,0x72,0x73,0x20,0x43,0x41,0x30,0x1e,0x17,0x0d, +0x39,0x36,0x30,0x34,0x30,0x39,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30, +0x34,0x30,0x31,0x30,0x37,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x61,0x31,0x11, +0x30,0x0f,0x06,0x03,0x55,0x04,0x07,0x13,0x08,0x49,0x6e,0x74,0x65,0x72,0x6e,0x65, +0x74,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65,0x72,0x69, +0x53,0x69,0x67,0x6e,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x33,0x30,0x31,0x06,0x03, +0x55,0x04,0x0b,0x13,0x2a,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e,0x20,0x43,0x6f, +0x6d,0x6d,0x65,0x72,0x63,0x69,0x61,0x6c,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72, +0x65,0x20,0x50,0x75,0x62,0x6c,0x69,0x73,0x68,0x65,0x72,0x73,0x20,0x43,0x41,0x30, +0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05, +0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xc3,0xd3,0x69,0x65, +0x52,0x01,0x94,0x54,0xab,0x28,0xc6,0x62,0x18,0xb3,0x54,0x55,0xc5,0x44,0x87,0x45, +0x4a,0x3b,0xc2,0x7e,0xd8,0xd3,0xd7,0xc8,0x80,0x86,0x8d,0xd8,0x0c,0xf1,0x16,0x9c, +0xcc,0x6b,0xa9,0x29,0xb2,0x8f,0x76,0x73,0x92,0xc8,0xc5,0x62,0xa6,0x3c,0xed,0x1e, +0x05,0x75,0xf0,0x13,0x00,0x6c,0x14,0x4d,0xd4,0x98,0x90,0x07,0xbe,0x69,0x73,0x81, +0xb8,0x62,0x4e,0x31,0x1e,0xd1,0xfc,0xc9,0x0c,0xeb,0x7d,0x90,0xbf,0xae,0xb4,0x47, +0x51,0xec,0x6f,0xce,0x64,0x35,0x02,0xd6,0x7d,0x67,0x05,0x77,0xe2,0x8f,0xd9,0x51, +0xd7,0xfb,0x97,0x19,0xbc,0x3e,0xd7,0x77,0x81,0xc6,0x43,0xdd,0xf2,0xdd,0xdf,0xca, +0xa3,0x83,0x8b,0xcb,0x41,0xc1,0x3d,0x22,0x48,0x48,0xa6,0x19,0x02,0x03,0x01,0x00, +0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x02,0x05,0x00, +0x03,0x81,0x81,0x00,0xb5,0xbc,0xb0,0x75,0x6a,0x89,0xa2,0x86,0xbd,0x64,0x78,0xc3, +0xa7,0x32,0x75,0x72,0x11,0xaa,0x26,0x02,0x17,0x60,0x30,0x4c,0xe3,0x48,0x34,0x19, +0xb9,0x52,0x4a,0x51,0x18,0x80,0xfe,0x53,0x2d,0x7b,0xd5,0x31,0x8c,0xc5,0x65,0x99, +0x41,0x41,0x2f,0xf2,0xae,0x63,0x7a,0xe8,0x73,0x99,0x15,0x90,0x1a,0x1f,0x7a,0x8b, +0x41,0xd0,0x8e,0x3a,0xd0,0xcd,0x38,0x34,0x44,0xd0,0x75,0xf8,0xea,0x71,0xc4,0x81, +0x19,0x38,0x17,0x35,0x4a,0xae,0xc5,0x3e,0x32,0xe6,0x21,0xb8,0x05,0xc0,0x93,0xe1, +0xc7,0x38,0x5c,0xd8,0xf7,0x93,0x38,0x64,0x90,0xed,0x54,0xce,0xca,0xd3,0xd3,0xd0, +0x5f,0xef,0x04,0x9b,0xde,0x02,0x82,0xdd,0x88,0x29,0xb1,0xc3,0x4f,0xa5,0xcd,0x71, +0x64,0x31,0x3c,0x3c +}; +static const BYTE rootWithKeySignAndCRLSign[] = { +0x30,0x82,0x01,0xdf,0x30,0x82,0x01,0x4c,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x5b,0xc7,0x0b,0x27,0x99,0xbb,0x2e,0x99,0x47,0x9d,0x45,0x4e,0x7c,0x1a,0xca, +0xe8,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x30,0x10,0x31, +0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31, +0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05, +0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x42,0x30,0x40,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x06,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x1d,0x06,0x03,0x55,0x1d, +0x0e,0x04,0x16,0x04,0x14,0x14,0x8c,0x16,0xbb,0xbe,0x70,0xa2,0x28,0x89,0xa0, +0x58,0xff,0x98,0xbd,0xa8,0x24,0x2b,0x8a,0xe9,0x9a,0x30,0x09,0x06,0x05,0x2b, +0x0e,0x03,0x02,0x1d,0x05,0x00,0x03,0x81,0x81,0x00,0x74,0xcb,0x21,0xfd,0x2d, +0x25,0xdc,0xa5,0xaa,0xa1,0x26,0xdc,0x8b,0x40,0x11,0x64,0xae,0x5c,0x71,0x3c, +0x28,0xbc,0xf9,0xb3,0xcb,0xa5,0x94,0xb2,0x8d,0x4c,0x23,0x2b,0x9b,0xde,0x2c, +0x4c,0x30,0x04,0xc6,0x88,0x10,0x2f,0x53,0xfd,0x6c,0x82,0xf1,0x13,0xfb,0xda, +0x27,0x75,0x25,0x48,0xe4,0x72,0x09,0x2a,0xee,0xb4,0x1e,0xc9,0x55,0xf5,0xf7, +0x82,0x91,0xd8,0x4b,0xe4,0x3a,0xfe,0x97,0x87,0xdf,0xfb,0x15,0x5a,0x12,0x3e, +0x12,0xe6,0xad,0x40,0x0b,0xcf,0xee,0x1a,0x44,0xe0,0x83,0xb2,0x67,0x94,0xd4, +0x2e,0x7c,0xf2,0x06,0x9d,0xb3,0x3b,0x7e,0x2f,0xda,0x25,0x66,0x7e,0xa7,0x1f, +0x45,0xd4,0xf5,0xe3,0xdf,0x2a,0xf1,0x18,0x28,0x20,0xb5,0xf8,0xf5,0x8d,0x7a, +0x2e,0x84,0xee }; +static const BYTE eeCert[] = { +0x30,0x82,0x01,0x93,0x30,0x81,0xfd,0xa0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00, +0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65, +0x72,0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x35,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x30,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04, +0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09, +0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00, +0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5,0x33, +0x0e,0x67,0x5f,0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6,0xdc, +0xb6,0x17,0x8e,0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7,0x48, +0x9f,0x6e,0xfe,0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b,0x47, +0xd1,0x57,0x71,0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b,0x05, +0x72,0xa7,0x87,0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc,0x6a, +0x80,0x83,0x68,0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85,0x85, +0xb5,0x46,0x36,0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2,0xd3, +0x51,0x9a,0x22,0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72,0xa3, +0x02,0x03,0x01,0x00,0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x22,0xf1,0x66,0x00,0x79,0xd2, +0xe6,0xb2,0xb2,0xf7,0x2f,0x98,0x92,0x7d,0x73,0xc3,0x6c,0x5c,0x77,0x20,0xe3, +0xbf,0x3e,0xe0,0xb3,0x5c,0x68,0xb4,0x9b,0x3a,0x41,0xae,0x94,0xa0,0x80,0x3a, +0xfe,0x5d,0x7a,0x56,0x87,0x85,0x44,0x45,0xcf,0xa6,0xd3,0x10,0xe7,0x73,0x41, +0xf2,0x7f,0x88,0x85,0x91,0x8e,0xe6,0xec,0xe2,0xce,0x08,0xbc,0xa5,0x76,0xe5, +0x4d,0x1d,0xb7,0x70,0x31,0xdd,0xc9,0x9a,0x15,0x32,0x11,0x5a,0x4e,0x62,0xc8, +0xd1,0xf8,0xec,0x46,0x39,0x5b,0xe7,0x67,0x1f,0x58,0xe8,0xa1,0xa0,0x5b,0xf7, +0x8a,0x6d,0x5f,0x91,0x18,0xd4,0x90,0x85,0xff,0x30,0xc7,0xca,0x9c,0xc6,0x92, +0xb0,0xca,0x16,0xc4,0xa4,0xc0,0xd6,0xe8,0xff,0x15,0x19,0xd1,0x30,0x61,0xf3, +0xef,0x9f }; +static const BYTE rootSignedCRL[] = { +0x30,0x82,0x01,0x1d,0x30,0x81,0x87,0x02,0x01,0x01,0x30,0x0d,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x10,0x31,0x0e,0x30, +0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31,0x17,0x0d, +0x30,0x37,0x30,0x39,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d, +0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x14, +0x30,0x12,0x02,0x01,0x01,0x17,0x0d,0x30,0x37,0x30,0x39,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0xa0,0x2d,0x30,0x2b,0x30,0x0a,0x06,0x03,0x55,0x1d, +0x14,0x04,0x03,0x02,0x01,0x01,0x30,0x1d,0x06,0x03,0x55,0x1d,0x23,0x04,0x16, +0x04,0x14,0x14,0x8c,0x16,0xbb,0xbe,0x70,0xa2,0x28,0x89,0xa0,0x58,0xff,0x98, +0xbd,0xa8,0x24,0x2b,0x8a,0xe9,0x9a,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86, +0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x9b,0x2b,0x99,0x0d, +0x16,0x83,0x93,0x54,0x29,0x3a,0xa6,0x53,0x5d,0xf8,0xa6,0x73,0x9f,0x2a,0x45, +0x39,0x91,0xff,0x91,0x1c,0x27,0x06,0xe8,0xdb,0x72,0x3f,0x66,0x89,0x15,0x68, +0x55,0xd5,0x49,0x63,0xa6,0x00,0xe9,0x66,0x9c,0x97,0xf9,0xb3,0xb3,0x2b,0x1b, +0xc7,0x79,0x46,0xa8,0xd8,0x2b,0x78,0x27,0xa0,0x70,0x02,0x81,0xc6,0x40,0xb3, +0x76,0x32,0x65,0x4c,0xf8,0xff,0x1d,0x41,0x6e,0x16,0x09,0xa2,0x8a,0x7b,0x0c, +0xd0,0xa6,0x9b,0x61,0xa3,0x7c,0x02,0x91,0x79,0xdf,0x6a,0x5e,0x88,0x95,0x66, +0x33,0x17,0xcb,0x5a,0xd2,0xdc,0x89,0x05,0x62,0x97,0x60,0x73,0x7b,0x2c,0x1a, +0x90,0x20,0x73,0x24,0x9f,0x45,0x22,0x4b,0xc1,0x33,0xd1,0xda,0xd8,0x7e,0x1b, +0x3d,0x74,0xd6,0x3b }; + static void testFindCRL(void) { HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL); PCCRL_CONTEXT context; - PCCERT_CONTEXT cert; + PCCERT_CONTEXT cert, endCert, rootCert; + CRL_FIND_ISSUED_FOR_PARA issuedForPara = { NULL, NULL }; + DWORD count, revoked_count; BOOL ret; if (!store) return; @@ -286,8 +462,289 @@ static void testFindCRL(void) ok(context != NULL, "Expected a context\n"); if (context) CertFreeCRLContext(context); + + /* Try various find flags */ + context = pCertFindCRLInStore(store, 0, CRL_FIND_ISSUED_BY_SIGNATURE_FLAG, + CRL_FIND_ISSUED_BY, cert, NULL); + ok(!context || broken(context != NULL /* Win9x */), "unexpected context\n"); + /* The CRL doesn't have an AKI extension, so it matches any cert */ + context = pCertFindCRLInStore(store, 0, CRL_FIND_ISSUED_BY_AKI_FLAG, + CRL_FIND_ISSUED_BY, cert, NULL); + ok(context != NULL, "Expected a context\n"); + if (context) + CertFreeCRLContext(context); + + if (0) + { + /* Crash or return NULL/STATUS_ACCESS_VIOLATION */ + context = pCertFindCRLInStore(store, 0, 0, CRL_FIND_ISSUED_FOR, NULL, + NULL); + context = pCertFindCRLInStore(store, 0, 0, CRL_FIND_ISSUED_FOR, + &issuedForPara, NULL); + } + /* Test whether the cert matches the CRL in the store */ + issuedForPara.pSubjectCert = cert; + issuedForPara.pIssuerCert = cert; + context = pCertFindCRLInStore(store, 0, 0, CRL_FIND_ISSUED_FOR, + &issuedForPara, NULL); + ok(context != NULL || broken(!context /* Win9x, NT4 */), + "Expected a context\n"); + if (context) + { + ok(context->cbCrlEncoded == sizeof(signedCRL), + "unexpected CRL size %d\n", context->cbCrlEncoded); + ok(!memcmp(context->pbCrlEncoded, signedCRL, context->cbCrlEncoded), + "unexpected CRL data\n"); + CertFreeCRLContext(context); + } + + ret = CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, + v1CRLWithIssuerAndEntry, sizeof(v1CRLWithIssuerAndEntry), + CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCRLToStore failed: %08x\n", GetLastError()); + ret = CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, + v2CRLWithIssuingDistPoint, sizeof(v2CRLWithIssuingDistPoint), + CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCRLToStore failed: %08x\n", GetLastError()); + ret = CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, + verisignCRL, sizeof(verisignCRL), CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCRLToStore failed: %08x\n", GetLastError()); + issuedForPara.pSubjectCert = cert; + issuedForPara.pIssuerCert = cert; + context = NULL; + count = revoked_count = 0; + do { + context = pCertFindCRLInStore(store, 0, 0, CRL_FIND_ISSUED_FOR, + &issuedForPara, context); + if (context) + { + PCRL_ENTRY entry; + + count++; + if (CertFindCertificateInCRL(cert, context, 0, NULL, &entry) && + entry) + revoked_count++; + } + } while (context); + /* signedCRL, v1CRLWithIssuerAndEntry, and v2CRLWithIssuingDistPoint all + * match cert's issuer, but verisignCRL does not, so the expected count + * is 0. + */ + ok(count == 3 || broken(count == 0 /* NT4, Win9x */), + "expected 3 matching CRLs, got %d\n", count); + /* Only v1CRLWithIssuerAndEntry and v2CRLWithIssuingDistPoint contain + * entries, so the count of CRL entries that match cert is 2. + */ + ok(revoked_count == 2 || broken(revoked_count == 0 /* NT4, Win9x */), + "expected 2 matching CRL entries, got %d\n", revoked_count); + CertFreeCertificateContext(cert); + /* Try again with a cert that doesn't match any CRLs in the store */ + cert = CertCreateCertificateContext(X509_ASN_ENCODING, + bigCertWithDifferentIssuer, sizeof(bigCertWithDifferentIssuer)); + ok(cert != NULL, "CertCreateCertificateContext failed: %08x\n", + GetLastError()); + issuedForPara.pSubjectCert = cert; + issuedForPara.pIssuerCert = cert; + context = NULL; + count = revoked_count = 0; + do { + context = pCertFindCRLInStore(store, 0, 0, CRL_FIND_ISSUED_FOR, + &issuedForPara, context); + if (context) + { + PCRL_ENTRY entry; + + count++; + if (CertFindCertificateInCRL(cert, context, 0, NULL, &entry) && + entry) + revoked_count++; + } + } while (context); + ok(count == 0, "expected 0 matching CRLs, got %d\n", count); + ok(revoked_count == 0, "expected 0 matching CRL entries, got %d\n", + revoked_count); + CertFreeCertificateContext(cert); + + /* Test again with a real certificate and CRL. The certificate wasn't + * revoked, but its issuer does have a CRL. + */ + cert = CertCreateCertificateContext(X509_ASN_ENCODING, + verisignCommercialSoftPubCA, sizeof(verisignCommercialSoftPubCA)); + ok(cert != NULL, "CertCreateCertificateContext failed: %08x\n", + GetLastError()); + issuedForPara.pIssuerCert = cert; + issuedForPara.pSubjectCert = cert; + context = NULL; + count = revoked_count = 0; + do { + context = pCertFindCRLInStore(store, 0, 0, CRL_FIND_ISSUED_FOR, + &issuedForPara, context); + if (context) + { + PCRL_ENTRY entry; + + count++; + if (CertFindCertificateInCRL(cert, context, 0, NULL, &entry) && + entry) + revoked_count++; + } + } while (context); + ok(count == 1 || broken(count == 0 /* Win9x, NT4 */), + "expected 1 matching CRLs, got %d\n", count); + ok(revoked_count == 0, "expected 0 matching CRL entries, got %d\n", + revoked_count); + CertFreeCertificateContext(cert); + + CertCloseStore(store, 0); + + /* This test uses a synthesized chain (rootWithKeySignAndCRLSign -> + * eeCert) whose end certificate is in the CRL. + */ + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + /* Add a CRL for the end certificate */ + CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, + rootSignedCRL, sizeof(rootSignedCRL), CERT_STORE_ADD_ALWAYS, NULL); + /* Add another CRL unrelated to the tested chain */ + CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, + verisignCRL, sizeof(verisignCRL), CERT_STORE_ADD_ALWAYS, NULL); + endCert = CertCreateCertificateContext(X509_ASN_ENCODING, + eeCert, sizeof(eeCert)); + rootCert = CertCreateCertificateContext(X509_ASN_ENCODING, + rootWithKeySignAndCRLSign, sizeof(rootWithKeySignAndCRLSign)); + issuedForPara.pSubjectCert = endCert; + issuedForPara.pIssuerCert = rootCert; + context = NULL; + count = revoked_count = 0; + do { + context = pCertFindCRLInStore(store, 0, 0, CRL_FIND_ISSUED_FOR, + &issuedForPara, context); + if (context) + { + PCRL_ENTRY entry; + + count++; + if (CertFindCertificateInCRL(endCert, context, 0, NULL, &entry) && + entry) + revoked_count++; + } + } while (context); + ok(count == 1 || broken(count == 0 /* Win9x, NT4 */), + "expected 1 matching CRLs, got %d\n", count); + ok(revoked_count == 1 || broken(revoked_count == 0 /* Win9x, NT4 */), + "expected 1 matching CRL entries, got %d\n", revoked_count); + + /* Test CRL_FIND_ISSUED_BY flags */ + count = revoked_count = 0; + do { + context = pCertFindCRLInStore(store, 0, 0, CRL_FIND_ISSUED_BY, + endCert, context); + if (context) + { + PCRL_ENTRY entry; + + count++; + if (CertFindCertificateInCRL(endCert, context, 0, NULL, &entry) && + entry) + revoked_count++; + } + } while (context); + ok(count == 0, "expected 0 matching CRLs, got %d\n", count); + ok(revoked_count == 0, "expected 0 matching CRL entries, got %d\n", + revoked_count); + count = revoked_count = 0; + do { + context = pCertFindCRLInStore(store, 0, 0, CRL_FIND_ISSUED_BY, + rootCert, context); + if (context) + { + PCRL_ENTRY entry; + + count++; + if (CertFindCertificateInCRL(endCert, context, 0, NULL, &entry) && + entry) + revoked_count++; + } + } while (context); + ok(count == 1, "expected 1 matching CRLs, got %d\n", count); + ok(revoked_count == 1, "expected 1 matching CRL entries, got %d\n", + revoked_count); + count = revoked_count = 0; + do { + context = pCertFindCRLInStore(store, 0, CRL_FIND_ISSUED_BY_AKI_FLAG, + CRL_FIND_ISSUED_BY, endCert, context); + if (context) + { + PCRL_ENTRY entry; + + count++; + if (CertFindCertificateInCRL(endCert, context, 0, NULL, &entry) && + entry) + revoked_count++; + } + } while (context); + ok(count == 0, "expected 0 matching CRLs, got %d\n", count); + ok(revoked_count == 0, "expected 0 matching CRL entries, got %d\n", + revoked_count); + count = revoked_count = 0; + do { + context = pCertFindCRLInStore(store, 0, CRL_FIND_ISSUED_BY_AKI_FLAG, + CRL_FIND_ISSUED_BY, rootCert, context); + if (context) + { + PCRL_ENTRY entry; + + count++; + if (CertFindCertificateInCRL(rootCert, context, 0, NULL, &entry) && + entry) + revoked_count++; + } + } while (context); + ok(count == 0 || broken(count == 1 /* Win9x */), + "expected 0 matching CRLs, got %d\n", count); + ok(revoked_count == 0, "expected 0 matching CRL entries, got %d\n", + revoked_count); + count = revoked_count = 0; + do { + context = pCertFindCRLInStore(store, 0, + CRL_FIND_ISSUED_BY_SIGNATURE_FLAG, CRL_FIND_ISSUED_BY, endCert, + context); + if (context) + { + PCRL_ENTRY entry; + + count++; + if (CertFindCertificateInCRL(endCert, context, 0, NULL, &entry) && + entry) + revoked_count++; + } + } while (context); + ok(count == 0, "expected 0 matching CRLs, got %d\n", count); + ok(revoked_count == 0, "expected 0 matching CRL entries, got %d\n", + revoked_count); + count = revoked_count = 0; + do { + context = pCertFindCRLInStore(store, 0, + CRL_FIND_ISSUED_BY_SIGNATURE_FLAG, CRL_FIND_ISSUED_BY, rootCert, + context); + if (context) + { + PCRL_ENTRY entry; + + count++; + if (CertFindCertificateInCRL(endCert, context, 0, NULL, &entry) && + entry) + revoked_count++; + } + } while (context); + ok(count == 1, "expected 1 matching CRLs, got %d\n", count); + ok(revoked_count == 1, "expected 1 matching CRL entries, got %d\n", + revoked_count); + CertFreeCertificateContext(rootCert); + CertFreeCertificateContext(endCert); + CertCloseStore(store, 0); } @@ -475,59 +932,24 @@ static void testCRLProperties(void) } } -static const BYTE v1CRLWithIssuerAndEntry[] = { 0x30, 0x44, 0x30, 0x02, 0x06, - 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, - 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, - 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x5a, 0x30, 0x16, 0x30, 0x14, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31, 0x36, - 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a }; -static const BYTE v2CRLWithIssuingDistPoint[] = { 0x30,0x5c,0x02,0x01,0x01, - 0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03, - 0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31, - 0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30, - 0x16,0x30,0x14,0x02,0x01,0x01,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30, - 0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0xa0,0x13,0x30,0x11,0x30,0x0f,0x06, - 0x03,0x55,0x1d,0x13,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 }; -static const BYTE verisignCRL[] = { 0x30, 0x82, 0x01, 0xb1, 0x30, 0x82, 0x01, - 0x1a, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, - 0x0d, 0x01, 0x01, 0x02, 0x05, 0x00, 0x30, 0x61, 0x31, 0x11, 0x30, 0x0f, 0x06, - 0x03, 0x55, 0x04, 0x07, 0x13, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, - 0x74, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56, - 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, - 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x56, 0x65, - 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x72, - 0x63, 0x69, 0x61, 0x6c, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, - 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x72, 0x73, 0x20, 0x43, - 0x41, 0x17, 0x0d, 0x30, 0x31, 0x30, 0x33, 0x32, 0x34, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x30, 0x34, 0x30, 0x31, 0x30, 0x37, 0x32, 0x33, - 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x69, 0x30, 0x21, 0x02, 0x10, 0x1b, 0x51, - 0x90, 0xf7, 0x37, 0x24, 0x39, 0x9c, 0x92, 0x54, 0xcd, 0x42, 0x46, 0x37, 0x99, - 0x6a, 0x17, 0x0d, 0x30, 0x31, 0x30, 0x31, 0x33, 0x30, 0x30, 0x30, 0x30, 0x31, - 0x32, 0x34, 0x5a, 0x30, 0x21, 0x02, 0x10, 0x75, 0x0e, 0x40, 0xff, 0x97, 0xf0, - 0x47, 0xed, 0xf5, 0x56, 0xc7, 0x08, 0x4e, 0xb1, 0xab, 0xfd, 0x17, 0x0d, 0x30, - 0x31, 0x30, 0x31, 0x33, 0x31, 0x30, 0x30, 0x30, 0x30, 0x34, 0x39, 0x5a, 0x30, - 0x21, 0x02, 0x10, 0x77, 0xe6, 0x5a, 0x43, 0x59, 0x93, 0x5d, 0x5f, 0x7a, 0x75, - 0x80, 0x1a, 0xcd, 0xad, 0xc2, 0x22, 0x17, 0x0d, 0x30, 0x30, 0x30, 0x38, 0x33, - 0x31, 0x30, 0x30, 0x30, 0x30, 0x35, 0x36, 0x5a, 0xa0, 0x1a, 0x30, 0x18, 0x30, - 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0b, 0x06, - 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x0d, 0x06, - 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x02, 0x05, 0x00, 0x03, - 0x81, 0x81, 0x00, 0x18, 0x2c, 0xe8, 0xfc, 0x16, 0x6d, 0x91, 0x4a, 0x3d, 0x88, - 0x54, 0x48, 0x5d, 0xb8, 0x11, 0xbf, 0x64, 0xbb, 0xf9, 0xda, 0x59, 0x19, 0xdd, - 0x0e, 0x65, 0xab, 0xc0, 0x0c, 0xfa, 0x67, 0x7e, 0x21, 0x1e, 0x83, 0x0e, 0xcf, - 0x9b, 0x89, 0x8a, 0xcf, 0x0c, 0x4b, 0xc1, 0x39, 0x9d, 0xe7, 0x6a, 0xac, 0x46, - 0x74, 0x6a, 0x91, 0x62, 0x22, 0x0d, 0xc4, 0x08, 0xbd, 0xf5, 0x0a, 0x90, 0x7f, - 0x06, 0x21, 0x3d, 0x7e, 0xa7, 0xaa, 0x5e, 0xcd, 0x22, 0x15, 0xe6, 0x0c, 0x75, - 0x8e, 0x6e, 0xad, 0xf1, 0x84, 0xe4, 0x22, 0xb4, 0x30, 0x6f, 0xfb, 0x64, 0x8f, - 0xd7, 0x80, 0x43, 0xf5, 0x19, 0x18, 0x66, 0x1d, 0x72, 0xa3, 0xe3, 0x94, 0x82, - 0x28, 0x52, 0xa0, 0x06, 0x4e, 0xb1, 0xc8, 0x92, 0x0c, 0x97, 0xbe, 0x15, 0x07, - 0xab, 0x7a, 0xc9, 0xea, 0x08, 0x67, 0x43, 0x4d, 0x51, 0x63, 0x3b, 0x9c, 0x9c, - 0xcd }; +static const BYTE bigCertWithCRLDistPoints[] = { +0x30,0x81,0xa5,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31, +0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31, +0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x30,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x01,0x01,0x05,0x00,0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, +0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xa3,0x26,0x30,0x24,0x30,0x22,0x06, +0x03,0x55,0x1d,0x1f,0x04,0x1b,0x30,0x19,0x30,0x17,0xa0,0x15,0xa0,0x13,0x86, +0x11,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x69,0x6e,0x65,0x68,0x71,0x2e, +0x6f,0x72,0x67 }; static void testIsValidCRLForCert(void) { BOOL ret; - PCCERT_CONTEXT cert1, cert2; + PCCERT_CONTEXT cert1, cert2, cert3; PCCRL_CONTEXT crl; HCERTSTORE store; @@ -568,21 +990,33 @@ static void testIsValidCRLForCert(void) CertFreeCRLContext(crl); - /* Yet with a CRL_ISSUING_DIST_POINT in the CRL, I still can't get this - * to say the CRL is not valid for either cert. + /* With a CRL_ISSUING_DIST_POINT in the CRL, it returns FALSE, since the + * cert doesn't have the same extension in it. */ crl = CertCreateCRLContext(X509_ASN_ENCODING, v2CRLWithIssuingDistPoint, sizeof(v2CRLWithIssuingDistPoint)); ok(crl != NULL, "CertCreateCRLContext failed: %08x\n", GetLastError()); ret = pCertIsValidCRLForCertificate(cert1, crl, 0, NULL); - ok(ret, "CertIsValidCRLForCertificate failed: %08x\n", GetLastError()); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); ret = pCertIsValidCRLForCertificate(cert2, crl, 0, NULL); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); + + /* With a CRL_ISSUING_DIST_POINT in the CRL, it matches the cert containing + * a CRL_DIST_POINTS_INFO extension. + */ + cert3 = CertCreateCertificateContext(X509_ASN_ENCODING, + bigCertWithCRLDistPoints, sizeof(bigCertWithCRLDistPoints)); + ok(cert3 != NULL, "CertCreateCertificateContext failed: %08x\n", + GetLastError()); + ret = pCertIsValidCRLForCertificate(cert3, crl, 0, NULL); ok(ret, "CertIsValidCRLForCertificate failed: %08x\n", GetLastError()); CertFreeCRLContext(crl); - /* And again, with a real CRL, the CRL is valid for both certs. */ + /* And again, with a real CRL, the CRL is valid for all three certs. */ crl = CertCreateCRLContext(X509_ASN_ENCODING, verisignCRL, sizeof(verisignCRL)); ok(crl != NULL, "CertCreateCRLContext failed: %08x\n", GetLastError()); @@ -591,11 +1025,13 @@ static void testIsValidCRLForCert(void) ok(ret, "CertIsValidCRLForCertificate failed: %08x\n", GetLastError()); ret = pCertIsValidCRLForCertificate(cert2, crl, 0, NULL); ok(ret, "CertIsValidCRLForCertificate failed: %08x\n", GetLastError()); + ret = pCertIsValidCRLForCertificate(cert3, crl, 0, NULL); + ok(ret, "CertIsValidCRLForCertificate failed: %08x\n", GetLastError()); CertFreeCRLContext(crl); /* One last test: a CRL in a different store than the cert is also valid - * for the cert, so CertIsValidCRLForCertificate must always return TRUE? + * for the cert. */ store = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, 0, CERT_STORE_CREATE_NEW_FLAG, NULL); @@ -609,11 +1045,14 @@ static void testIsValidCRLForCert(void) ok(ret, "CertIsValidCRLForCertificate failed: %08x\n", GetLastError()); ret = pCertIsValidCRLForCertificate(cert2, crl, 0, NULL); ok(ret, "CertIsValidCRLForCertificate failed: %08x\n", GetLastError()); + ret = pCertIsValidCRLForCertificate(cert3, crl, 0, NULL); + ok(ret, "CertIsValidCRLForCertificate failed: %08x\n", GetLastError()); CertFreeCRLContext(crl); CertCloseStore(store, 0); + CertFreeCertificateContext(cert3); CertFreeCertificateContext(cert2); CertFreeCertificateContext(cert1); } @@ -710,8 +1149,8 @@ static void testVerifyCRLRevocation(void) CertFreeCRLContext(crl); /* Check against CRL with different issuer and entry for the cert */ - crl = CertCreateCRLContext(X509_ASN_ENCODING, v1CRLWithIssuerAndEntry, - sizeof(v1CRLWithIssuerAndEntry)); + crl = CertCreateCRLContext(X509_ASN_ENCODING, crlWithDifferentIssuer, + sizeof(crlWithDifferentIssuer)); ok(crl != NULL, "CertCreateCRLContext failed: %08x\n", GetLastError()); ret = CertVerifyCRLRevocation(X509_ASN_ENCODING, cert->pCertInfo, 1, (PCRL_INFO *)&crl->pCrlInfo); diff --git a/dlls/crypt32/tests/encode.c b/dlls/crypt32/tests/encode.c index f2fc7275a55..316a9f8485d 100644 --- a/dlls/crypt32/tests/encode.c +++ b/dlls/crypt32/tests/encode.c @@ -3851,23 +3851,14 @@ static const BYTE v2CRLWithExt[] = { 0x30,0x5c,0x02,0x01,0x01,0x30,0x02,0x06, 0x02,0x01,0x01,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30, 0x30,0x30,0x30,0x30,0x5a,0xa0,0x13,0x30,0x11,0x30,0x0f,0x06,0x03,0x55,0x1d, 0x13,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 }; -static const BYTE v2CRLWithIssuingDistPoint[] = { 0x30,0x5c,0x02,0x01,0x01, - 0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03, - 0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31, - 0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30, - 0x16,0x30,0x14,0x02,0x01,0x01,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30, - 0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0xa0,0x13,0x30,0x11,0x30,0x0f,0x06, - 0x03,0x55,0x1d,0x13,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 }; static void test_encodeCRLToBeSigned(DWORD dwEncoding) { BOOL ret; BYTE *buf = NULL; - static CHAR oid_issuing_dist_point[] = szOID_ISSUING_DIST_POINT; DWORD size = 0; CRL_INFO info = { 0 }; CRL_ENTRY entry = { { 0 }, { 0 }, 0, 0 }; - CERT_EXTENSION ext; /* Test with a V1 CRL */ ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info, @@ -3978,21 +3969,6 @@ static void test_encodeCRLToBeSigned(DWORD dwEncoding) ok(!memcmp(buf, v2CRLWithExt, size), "Got unexpected value\n"); LocalFree(buf); } - /* a v2 CRL with an issuing dist point extension */ - ext.pszObjId = oid_issuing_dist_point; - ext.fCritical = TRUE; - ext.Value.cbData = sizeof(urlIDP); - ext.Value.pbData = (LPBYTE)urlIDP; - entry.rgExtension = &ext; - ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info, - CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); - ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); - if (buf) - { - ok(size == sizeof(v2CRLWithIssuingDistPoint), "Wrong size %d\n", size); - ok(!memcmp(buf, v2CRLWithIssuingDistPoint, size), "Unexpected value\n"); - LocalFree(buf); - } } static const BYTE verisignCRL[] = { 0x30, 0x82, 0x01, 0xb1, 0x30, 0x82, 0x01, @@ -4686,19 +4662,6 @@ static void test_decodeCRLToBeSigned(DWORD dwEncoding) info->cExtension); LocalFree(buf); } - /* And again, with an issuing dist point */ - ret = pCryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, - v2CRLWithIssuingDistPoint, sizeof(v2CRLWithIssuingDistPoint), - CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); - ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); - if (buf) - { - CRL_INFO *info = (CRL_INFO *)buf; - - ok(info->cExtension == 1, "Expected 1 extensions, got %d\n", - info->cExtension); - LocalFree(buf); - } } static const LPCSTR keyUsages[] = { szOID_PKIX_KP_CODE_SIGNING, diff --git a/dlls/cryptnet/cryptnet_main.c b/dlls/cryptnet/cryptnet_main.c index 9301a56733b..afae942d1d1 100644 --- a/dlls/cryptnet/cryptnet_main.c +++ b/dlls/cryptnet/cryptnet_main.c @@ -120,16 +120,108 @@ static const char *url_oid_to_str(LPCSTR oid) typedef BOOL (WINAPI *UrlDllGetObjectUrlFunc)(LPCSTR, LPVOID, DWORD, PCRYPT_URL_ARRAY, DWORD *, PCRYPT_URL_INFO, DWORD *, LPVOID); +static LPWSTR name_value_to_str(CERT_NAME_BLOB *name) +{ + DWORD len = CertNameToStrW(X509_ASN_ENCODING, name, CERT_SIMPLE_NAME_STR, + NULL, 0); + LPWSTR str = NULL; + + if (len) + { + str = CryptMemAlloc(len * sizeof(WCHAR)); + if (str) + CertNameToStrW(X509_ASN_ENCODING, name, CERT_SIMPLE_NAME_STR, + str, len); + } + return str; +} + +static void dump_alt_name_entry(CERT_ALT_NAME_ENTRY *entry) +{ + LPWSTR str; + + switch (entry->dwAltNameChoice) + { + case CERT_ALT_NAME_OTHER_NAME: + TRACE("CERT_ALT_NAME_OTHER_NAME, oid = %s\n", + debugstr_a(entry->u.pOtherName->pszObjId)); + break; + case CERT_ALT_NAME_RFC822_NAME: + TRACE("CERT_ALT_NAME_RFC822_NAME: %s\n", + debugstr_w(entry->u.pwszRfc822Name)); + break; + case CERT_ALT_NAME_DNS_NAME: + TRACE("CERT_ALT_NAME_DNS_NAME: %s\n", + debugstr_w(entry->u.pwszDNSName)); + break; + case CERT_ALT_NAME_DIRECTORY_NAME: + str = name_value_to_str(&entry->u.DirectoryName); + TRACE("CERT_ALT_NAME_DIRECTORY_NAME: %s\n", debugstr_w(str)); + CryptMemFree(str); + break; + case CERT_ALT_NAME_URL: + TRACE("CERT_ALT_NAME_URL: %s\n", debugstr_w(entry->u.pwszURL)); + break; + case CERT_ALT_NAME_IP_ADDRESS: + TRACE("CERT_ALT_NAME_IP_ADDRESS: %d bytes\n", + entry->u.IPAddress.cbData); + break; + case CERT_ALT_NAME_REGISTERED_ID: + TRACE("CERT_ALT_NAME_REGISTERED_ID: %s\n", + debugstr_a(entry->u.pszRegisteredID)); + break; + default: + TRACE("dwAltNameChoice = %d\n", entry->dwAltNameChoice); + } +} + static BOOL WINAPI CRYPT_GetUrlFromCertificateIssuer(LPCSTR pszUrlOid, LPVOID pvPara, DWORD dwFlags, PCRYPT_URL_ARRAY pUrlArray, DWORD *pcbUrlArray, PCRYPT_URL_INFO pUrlInfo, DWORD *pcbUrlInfo, LPVOID pvReserved) { - /* FIXME: This depends on the AIA (authority info access) extension being - * supported in crypt32. - */ - FIXME("\n"); - SetLastError(CRYPT_E_NOT_FOUND); - return FALSE; + PCCERT_CONTEXT cert = pvPara; + PCERT_EXTENSION ext; + BOOL ret = FALSE; + + /* The only applicable flag is CRYPT_GET_URL_FROM_EXTENSION */ + if (dwFlags && !(dwFlags & CRYPT_GET_URL_FROM_EXTENSION)) + { + SetLastError(CRYPT_E_NOT_FOUND); + return FALSE; + } + if ((ext = CertFindExtension(szOID_AUTHORITY_INFO_ACCESS, + cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension))) + { + CERT_AUTHORITY_INFO_ACCESS *aia; + DWORD size; + + ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_AUTHORITY_INFO_ACCESS, + ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, + &aia, &size); + if (ret) + { + DWORD i; + + TRACE("%d access descriptions:\n", aia->cAccDescr); + for (i = 0; i < aia->cAccDescr; i++) + { + if (!strcmp(aia->rgAccDescr[i].pszAccessMethod, + szOID_PKIX_OCSP)) + TRACE("OCSP:\n"); + else if (!strcmp(aia->rgAccDescr[i].pszAccessMethod, + szOID_PKIX_CA_ISSUERS)) + TRACE("CA issuers:\n"); + dump_alt_name_entry(&aia->rgAccDescr[i].AccessLocation); + } + LocalFree(aia); + FIXME("authority info access unsupported\n"); + SetLastError(CRYPT_E_NOT_FOUND); + ret = FALSE; + } + } + else + SetLastError(CRYPT_E_NOT_FOUND); + return ret; } static BOOL WINAPI CRYPT_GetUrlFromCertificateCRLDistPoint(LPCSTR pszUrlOid, @@ -1246,20 +1338,24 @@ static BOOL WINAPI CRYPT_CreateAny(LPCSTR pszObjectOid, if (!CertAddCertificateContextToStore(store, context, CERT_STORE_ADD_ALWAYS, NULL)) ret = FALSE; + CertFreeCertificateContext(context); break; case CERT_QUERY_CONTENT_CRL: if (!CertAddCRLContextToStore(store, context, CERT_STORE_ADD_ALWAYS, NULL)) ret = FALSE; + CertFreeCRLContext(context); break; case CERT_QUERY_CONTENT_CTL: if (!CertAddCTLContextToStore(store, context, CERT_STORE_ADD_ALWAYS, NULL)) ret = FALSE; + CertFreeCTLContext(context); break; default: CertAddStoreToCollection(store, contextStore, 0, 0); } + CertCloseStore(contextStore, 0); } else ret = FALSE; @@ -1437,6 +1533,15 @@ BOOL WINAPI CryptRetrieveObjectByUrlW(LPCWSTR pszURL, LPCSTR pszObjectOid, return ret; } +typedef struct _CERT_REVOCATION_PARA_NO_EXTRA_FIELDS { + DWORD cbSize; + PCCERT_CONTEXT pIssuerCert; + DWORD cCertStore; + HCERTSTORE *rgCertStore; + HCERTSTORE hCrlStore; + LPFILETIME pftTimeToUse; +} CERT_REVOCATION_PARA_NO_EXTRA_FIELDS, *PCERT_REVOCATION_PARA_NO_EXTRA_FIELDS; + typedef struct _OLD_CERT_REVOCATION_STATUS { DWORD cbSize; DWORD dwIndex; @@ -1453,6 +1558,8 @@ BOOL WINAPI CertDllVerifyRevocation(DWORD dwEncodingType, DWORD dwRevType, { DWORD error = 0, i; BOOL ret; + FILETIME now; + LPFILETIME pTime = NULL; TRACE("(%08x, %d, %d, %p, %08x, %p, %p)\n", dwEncodingType, dwRevType, cContext, rgpvContext, dwFlags, pRevPara, pRevStatus); @@ -1463,6 +1570,19 @@ BOOL WINAPI CertDllVerifyRevocation(DWORD dwEncodingType, DWORD dwRevType, SetLastError(E_INVALIDARG); return FALSE; } + if (!cContext) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + if (pRevPara && pRevPara->cbSize >= + sizeof(CERT_REVOCATION_PARA_NO_EXTRA_FIELDS)) + pTime = pRevPara->pftTimeToUse; + if (!pTime) + { + GetSystemTimeAsFileTime(&now); + pTime = &now; + } memset(&pRevStatus->dwIndex, 0, pRevStatus->cbSize - sizeof(DWORD)); if (dwRevType != CERT_CONTEXT_REVOCATION_TYPE) { @@ -1515,18 +1635,27 @@ BOOL WINAPI CertDllVerifyRevocation(DWORD dwEncodingType, DWORD dwRevType, (void **)&crl, NULL, NULL, NULL, NULL); if (ret) { - PCRL_ENTRY entry = NULL; - - CertFindCertificateInCRL( - rgpvContext[i], crl, 0, NULL, - &entry); - if (entry) + if (CertVerifyCRLTimeValidity(pTime, crl->pCrlInfo)) { - error = CRYPT_E_REVOKED; - pRevStatus->dwIndex = i; + /* The CRL isn't time valid */ + error = CRYPT_E_NO_REVOCATION_CHECK; ret = FALSE; } - else if (timeout) + else + { + PCRL_ENTRY entry = NULL; + + CertFindCertificateInCRL( + rgpvContext[i], crl, 0, NULL, + &entry); + if (entry) + { + error = CRYPT_E_REVOKED; + pRevStatus->dwIndex = i; + ret = FALSE; + } + } + if (ret && timeout) { DWORD time = GetTickCount(); diff --git a/dlls/cryptnet/tests/cryptnet.c b/dlls/cryptnet/tests/cryptnet.c index 618e494a878..490e93ad109 100644 --- a/dlls/cryptnet/tests/cryptnet.c +++ b/dlls/cryptnet/tests/cryptnet.c @@ -376,10 +376,13 @@ static void test_retrieveObjectByUrl(void) skip("no usable CertificateContext\n"); return; } + CertFreeCertificateContext(cert); aux.pLastSyncTime = &ft; ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE, 0, 0, (void **)&cert, NULL, NULL, NULL, &aux); + ok(ret, "CryptRetrieveObjectByUrlA failed: %08x\n", GetLastError()); + CertFreeCertificateContext(cert); ok(ft.dwLowDateTime || ft.dwHighDateTime, "Expected last sync time to be set\n"); DeleteFileA(tmpfile); @@ -393,8 +396,210 @@ static void test_retrieveObjectByUrl(void) GetLastError()); } +static const BYTE rootWithKeySignAndCRLSign[] = { +0x30,0x82,0x01,0xdf,0x30,0x82,0x01,0x4c,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x5b,0xc7,0x0b,0x27,0x99,0xbb,0x2e,0x99,0x47,0x9d,0x45,0x4e,0x7c,0x1a,0xca, +0xe8,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x30,0x10,0x31, +0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31, +0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05, +0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x42,0x30,0x40,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x06,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x1d,0x06,0x03,0x55,0x1d, +0x0e,0x04,0x16,0x04,0x14,0x14,0x8c,0x16,0xbb,0xbe,0x70,0xa2,0x28,0x89,0xa0, +0x58,0xff,0x98,0xbd,0xa8,0x24,0x2b,0x8a,0xe9,0x9a,0x30,0x09,0x06,0x05,0x2b, +0x0e,0x03,0x02,0x1d,0x05,0x00,0x03,0x81,0x81,0x00,0x74,0xcb,0x21,0xfd,0x2d, +0x25,0xdc,0xa5,0xaa,0xa1,0x26,0xdc,0x8b,0x40,0x11,0x64,0xae,0x5c,0x71,0x3c, +0x28,0xbc,0xf9,0xb3,0xcb,0xa5,0x94,0xb2,0x8d,0x4c,0x23,0x2b,0x9b,0xde,0x2c, +0x4c,0x30,0x04,0xc6,0x88,0x10,0x2f,0x53,0xfd,0x6c,0x82,0xf1,0x13,0xfb,0xda, +0x27,0x75,0x25,0x48,0xe4,0x72,0x09,0x2a,0xee,0xb4,0x1e,0xc9,0x55,0xf5,0xf7, +0x82,0x91,0xd8,0x4b,0xe4,0x3a,0xfe,0x97,0x87,0xdf,0xfb,0x15,0x5a,0x12,0x3e, +0x12,0xe6,0xad,0x40,0x0b,0xcf,0xee,0x1a,0x44,0xe0,0x83,0xb2,0x67,0x94,0xd4, +0x2e,0x7c,0xf2,0x06,0x9d,0xb3,0x3b,0x7e,0x2f,0xda,0x25,0x66,0x7e,0xa7,0x1f, +0x45,0xd4,0xf5,0xe3,0xdf,0x2a,0xf1,0x18,0x28,0x20,0xb5,0xf8,0xf5,0x8d,0x7a, +0x2e,0x84,0xee }; +static const BYTE eeCert[] = { +0x30,0x82,0x01,0x93,0x30,0x81,0xfd,0xa0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00, +0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65, +0x72,0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x35,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x30,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04, +0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09, +0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00, +0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5,0x33, +0x0e,0x67,0x5f,0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6,0xdc, +0xb6,0x17,0x8e,0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7,0x48, +0x9f,0x6e,0xfe,0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b,0x47, +0xd1,0x57,0x71,0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b,0x05, +0x72,0xa7,0x87,0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc,0x6a, +0x80,0x83,0x68,0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85,0x85, +0xb5,0x46,0x36,0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2,0xd3, +0x51,0x9a,0x22,0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72,0xa3, +0x02,0x03,0x01,0x00,0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x22,0xf1,0x66,0x00,0x79,0xd2, +0xe6,0xb2,0xb2,0xf7,0x2f,0x98,0x92,0x7d,0x73,0xc3,0x6c,0x5c,0x77,0x20,0xe3, +0xbf,0x3e,0xe0,0xb3,0x5c,0x68,0xb4,0x9b,0x3a,0x41,0xae,0x94,0xa0,0x80,0x3a, +0xfe,0x5d,0x7a,0x56,0x87,0x85,0x44,0x45,0xcf,0xa6,0xd3,0x10,0xe7,0x73,0x41, +0xf2,0x7f,0x88,0x85,0x91,0x8e,0xe6,0xec,0xe2,0xce,0x08,0xbc,0xa5,0x76,0xe5, +0x4d,0x1d,0xb7,0x70,0x31,0xdd,0xc9,0x9a,0x15,0x32,0x11,0x5a,0x4e,0x62,0xc8, +0xd1,0xf8,0xec,0x46,0x39,0x5b,0xe7,0x67,0x1f,0x58,0xe8,0xa1,0xa0,0x5b,0xf7, +0x8a,0x6d,0x5f,0x91,0x18,0xd4,0x90,0x85,0xff,0x30,0xc7,0xca,0x9c,0xc6,0x92, +0xb0,0xca,0x16,0xc4,0xa4,0xc0,0xd6,0xe8,0xff,0x15,0x19,0xd1,0x30,0x61,0xf3, +0xef,0x9f }; +static const BYTE rootSignedCRL[] = { +0x30,0x82,0x01,0x1d,0x30,0x81,0x87,0x02,0x01,0x01,0x30,0x0d,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x10,0x31,0x0e,0x30, +0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31,0x17,0x0d, +0x30,0x37,0x30,0x39,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d, +0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x14, +0x30,0x12,0x02,0x01,0x01,0x17,0x0d,0x30,0x37,0x30,0x39,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0xa0,0x2d,0x30,0x2b,0x30,0x0a,0x06,0x03,0x55,0x1d, +0x14,0x04,0x03,0x02,0x01,0x01,0x30,0x1d,0x06,0x03,0x55,0x1d,0x23,0x04,0x16, +0x04,0x14,0x14,0x8c,0x16,0xbb,0xbe,0x70,0xa2,0x28,0x89,0xa0,0x58,0xff,0x98, +0xbd,0xa8,0x24,0x2b,0x8a,0xe9,0x9a,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86, +0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x9b,0x2b,0x99,0x0d, +0x16,0x83,0x93,0x54,0x29,0x3a,0xa6,0x53,0x5d,0xf8,0xa6,0x73,0x9f,0x2a,0x45, +0x39,0x91,0xff,0x91,0x1c,0x27,0x06,0xe8,0xdb,0x72,0x3f,0x66,0x89,0x15,0x68, +0x55,0xd5,0x49,0x63,0xa6,0x00,0xe9,0x66,0x9c,0x97,0xf9,0xb3,0xb3,0x2b,0x1b, +0xc7,0x79,0x46,0xa8,0xd8,0x2b,0x78,0x27,0xa0,0x70,0x02,0x81,0xc6,0x40,0xb3, +0x76,0x32,0x65,0x4c,0xf8,0xff,0x1d,0x41,0x6e,0x16,0x09,0xa2,0x8a,0x7b,0x0c, +0xd0,0xa6,0x9b,0x61,0xa3,0x7c,0x02,0x91,0x79,0xdf,0x6a,0x5e,0x88,0x95,0x66, +0x33,0x17,0xcb,0x5a,0xd2,0xdc,0x89,0x05,0x62,0x97,0x60,0x73,0x7b,0x2c,0x1a, +0x90,0x20,0x73,0x24,0x9f,0x45,0x22,0x4b,0xc1,0x33,0xd1,0xda,0xd8,0x7e,0x1b, +0x3d,0x74,0xd6,0x3b }; + +BOOL (WINAPI *pCertVerifyRevocation)(DWORD, DWORD, DWORD, void **, DWORD, + PCERT_REVOCATION_PARA, PCERT_REVOCATION_STATUS); + +static void test_verifyRevocation(void) +{ + HMODULE hCryptNet = GetModuleHandleA("cryptnet.dll"); + BOOL ret; + CERT_REVOCATION_STATUS status = { sizeof(status), 0 }; + PCCERT_CONTEXT certs[2]; + CERT_REVOCATION_PARA revPara = { sizeof(revPara), 0 }; + + pCertVerifyRevocation = (void *)GetProcAddress(hCryptNet, + "CertDllVerifyRevocation"); + if (!pCertVerifyRevocation) + { + win_skip("no CertDllVerifyRevocation\n"); + return; + } + if (0) + { + /* Crash */ + ret = pCertVerifyRevocation(0, 0, 0, NULL, 0, NULL, NULL); + } + SetLastError(0xdeadbeef); + ret = pCertVerifyRevocation(0, 0, 0, NULL, 0, NULL, &status); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pCertVerifyRevocation(X509_ASN_ENCODING, 0, 0, NULL, 0, NULL, + &status); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pCertVerifyRevocation(0, CERT_CONTEXT_REVOCATION_TYPE, 0, NULL, 0, + NULL, &status); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + certs[0] = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert, + sizeof(bigCert)); + SetLastError(0xdeadbeef); + ret = pCertVerifyRevocation(0, CERT_CONTEXT_REVOCATION_TYPE, + 1, (void **)certs, 0, NULL, &status); + ok(!ret && GetLastError() == CRYPT_E_NO_REVOCATION_CHECK, + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", GetLastError()); + ok(status.dwError == CRYPT_E_NO_REVOCATION_CHECK, + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", status.dwError); + ok(status.dwIndex == 0, "expected index 0, got %d\n", status.dwIndex); + CertFreeCertificateContext(certs[0]); + certs[0] = CertCreateCertificateContext(X509_ASN_ENCODING, + rootWithKeySignAndCRLSign, sizeof(rootWithKeySignAndCRLSign)); + certs[1] = CertCreateCertificateContext(X509_ASN_ENCODING, + eeCert, sizeof(eeCert)); + /* The root cert itself can't be checked for revocation */ + SetLastError(0xdeadbeef); + ret = pCertVerifyRevocation(0, CERT_CONTEXT_REVOCATION_TYPE, + 1, (void **)certs, 0, NULL, &status); + ok(!ret && GetLastError() == CRYPT_E_NO_REVOCATION_CHECK, + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", GetLastError()); + ok(status.dwError == CRYPT_E_NO_REVOCATION_CHECK, + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", status.dwError); + ok(status.dwIndex == 0, "expected index 0, got %d\n", status.dwIndex); + /* Neither can the end cert */ + SetLastError(0xdeadbeef); + ret = pCertVerifyRevocation(0, CERT_CONTEXT_REVOCATION_TYPE, + 1, (void **)&certs[1], 0, NULL, &status); + ok(!ret && GetLastError() == CRYPT_E_NO_REVOCATION_CHECK, + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", GetLastError()); + ok(status.dwError == CRYPT_E_NO_REVOCATION_CHECK, + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", status.dwError); + ok(status.dwIndex == 0, "expected index 0, got %d\n", status.dwIndex); + /* Both certs together can't, either (they're not CRLs) */ + SetLastError(0xdeadbeef); + ret = pCertVerifyRevocation(0, CERT_CONTEXT_REVOCATION_TYPE, + 2, (void **)certs, 0, NULL, &status); + ok(!ret && GetLastError() == CRYPT_E_NO_REVOCATION_CHECK, + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", GetLastError()); + ok(status.dwError == CRYPT_E_NO_REVOCATION_CHECK, + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", status.dwError); + ok(status.dwIndex == 0, "expected index 0, got %d\n", status.dwIndex); + /* Now add a CRL to the hCrlStore */ + revPara.hCrlStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + CertAddEncodedCRLToStore(revPara.hCrlStore, X509_ASN_ENCODING, + rootSignedCRL, sizeof(rootSignedCRL), CERT_STORE_ADD_ALWAYS, NULL); + SetLastError(0xdeadbeef); + ret = pCertVerifyRevocation(0, CERT_CONTEXT_REVOCATION_TYPE, + 2, (void **)certs, 0, &revPara, &status); + ok(!ret && GetLastError() == CRYPT_E_NO_REVOCATION_CHECK, + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", GetLastError()); + ok(status.dwError == CRYPT_E_NO_REVOCATION_CHECK, + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", status.dwError); + ok(status.dwIndex == 0, "expected index 0, got %d\n", status.dwIndex); + /* Specifying CERT_VERIFY_REV_CHAIN_FLAG doesn't change things either */ + SetLastError(0xdeadbeef); + ret = pCertVerifyRevocation(0, CERT_CONTEXT_REVOCATION_TYPE, + 2, (void **)certs, CERT_VERIFY_REV_CHAIN_FLAG, &revPara, &status); + ok(!ret && GetLastError() == CRYPT_E_NO_REVOCATION_CHECK, + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", GetLastError()); + ok(status.dwError == CRYPT_E_NO_REVOCATION_CHECK, + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", status.dwError); + ok(status.dwIndex == 0, "expected index 0, got %d\n", status.dwIndex); + /* Again, specifying the issuer cert: no change */ + revPara.pIssuerCert = certs[0]; + SetLastError(0xdeadbeef); + ret = CertVerifyRevocation(X509_ASN_ENCODING, CERT_CONTEXT_REVOCATION_TYPE, + 1, (void **)&certs[1], 0, &revPara, &status); + ok(!ret && GetLastError() == CRYPT_E_NO_REVOCATION_CHECK, + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", GetLastError()); + ok(status.dwError == CRYPT_E_NO_REVOCATION_CHECK, + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", status.dwError); + ok(status.dwIndex == 0, "expected index 0, got %d\n", status.dwIndex); + CertCloseStore(revPara.hCrlStore, 0); + CertFreeCertificateContext(certs[1]); + CertFreeCertificateContext(certs[0]); +} + START_TEST(cryptnet) { test_getObjectUrl(); test_retrieveObjectByUrl(); + test_verifyRevocation(); } diff --git a/dlls/d3d10core/d3d10core_main.c b/dlls/d3d10core/d3d10core_main.c index 273f15d6632..4151dd05336 100644 --- a/dlls/d3d10core/d3d10core_main.c +++ b/dlls/d3d10core/d3d10core_main.c @@ -81,13 +81,7 @@ static HRESULT WINAPI layer_create(enum dxgi_device_layer_id id, void **layer_ba } object = *layer_base; - - object->vtbl = &d3d10_device_vtbl; - object->inner_unknown_vtbl = &d3d10_device_inner_unknown_vtbl; - object->device_parent_vtbl = &d3d10_wined3d_device_parent_vtbl; - object->refcount = 1; - - object->outer_unknown = device_object; + d3d10_device_init(object, device_object); *device_layer = &object->inner_unknown_vtbl; TRACE("Created d3d10 device at %p\n", object); diff --git a/dlls/d3d10core/d3d10core_private.h b/dlls/d3d10core/d3d10core_private.h index f4535ce930d..35d5ed3e256 100644 --- a/dlls/d3d10core/d3d10core_private.h +++ b/dlls/d3d10core/d3d10core_private.h @@ -67,9 +67,6 @@ HRESULT parse_dxbc(const char *data, SIZE_T data_size, HRESULT (*chunk_handler)(const char *data, DWORD data_size, DWORD tag, void *ctx), void *ctx) DECLSPEC_HIDDEN; /* IDirect3D10Device */ -extern const struct ID3D10DeviceVtbl d3d10_device_vtbl DECLSPEC_HIDDEN; -extern const struct IUnknownVtbl d3d10_device_inner_unknown_vtbl DECLSPEC_HIDDEN; -extern const struct IWineD3DDeviceParentVtbl d3d10_wined3d_device_parent_vtbl DECLSPEC_HIDDEN; struct d3d10_device { const struct ID3D10DeviceVtbl *vtbl; @@ -81,6 +78,8 @@ struct d3d10_device IWineD3DDevice *wined3d_device; }; +void d3d10_device_init(struct d3d10_device *device, void *outer_unknown) DECLSPEC_HIDDEN; + /* ID3D10Texture2D */ struct d3d10_texture2d { diff --git a/dlls/d3d10core/device.c b/dlls/d3d10core/device.c index b3da2ed4c00..4898a091aa7 100644 --- a/dlls/d3d10core/device.c +++ b/dlls/d3d10core/device.c @@ -1117,7 +1117,7 @@ static void STDMETHODCALLTYPE d3d10_device_GetTextFilterSize(ID3D10Device *iface FIXME("iface %p, width %p, height %p stub!\n", iface, width, height); } -const struct ID3D10DeviceVtbl d3d10_device_vtbl = +static const struct ID3D10DeviceVtbl d3d10_device_vtbl = { /* IUnknown methods */ d3d10_device_QueryInterface, @@ -1221,7 +1221,7 @@ const struct ID3D10DeviceVtbl d3d10_device_vtbl = d3d10_device_GetTextFilterSize, }; -const struct IUnknownVtbl d3d10_device_inner_unknown_vtbl = +static const struct IUnknownVtbl d3d10_device_inner_unknown_vtbl = { /* IUnknown methods */ d3d10_device_inner_QueryInterface, @@ -1425,7 +1425,7 @@ static HRESULT STDMETHODCALLTYPE device_parent_CreateSwapChain(IWineD3DDevicePar return S_OK; } -const struct IWineD3DDeviceParentVtbl d3d10_wined3d_device_parent_vtbl = +static const struct IWineD3DDeviceParentVtbl d3d10_wined3d_device_parent_vtbl = { /* IUnknown methods */ device_parent_QueryInterface, @@ -1439,3 +1439,12 @@ const struct IWineD3DDeviceParentVtbl d3d10_wined3d_device_parent_vtbl = device_parent_CreateVolume, device_parent_CreateSwapChain, }; + +void d3d10_device_init(struct d3d10_device *device, void *outer_unknown) +{ + device->vtbl = &d3d10_device_vtbl; + device->inner_unknown_vtbl = &d3d10_device_inner_unknown_vtbl; + device->device_parent_vtbl = &d3d10_wined3d_device_parent_vtbl; + device->refcount = 1; + device->outer_unknown = outer_unknown; +} diff --git a/dlls/d3d8/d3d8_private.h b/dlls/d3d8/d3d8_private.h index 2218f31ee98..f6ceeed0f4e 100644 --- a/dlls/d3d8/d3d8_private.h +++ b/dlls/d3d8/d3d8_private.h @@ -148,16 +148,6 @@ struct IDirect3D8Impl IWineD3D *WineD3D; }; -/* ---------------- */ -/* IDirect3DDevice8 */ -/* ---------------- */ - -/***************************************************************************** - * Predeclare the interface implementation structures - */ -extern const IDirect3DDevice8Vtbl Direct3DDevice8_Vtbl DECLSPEC_HIDDEN; -extern const IWineD3DDeviceParentVtbl d3d8_wined3d_device_parent_vtbl DECLSPEC_HIDDEN; - /***************************************************************************** * IDirect3DDevice8 implementation structure */ @@ -211,6 +201,9 @@ struct IDirect3DDevice8Impl BOOL inDestruction; }; +HRESULT device_init(IDirect3DDevice8Impl *device, IWineD3D *wined3d, UINT adapter, + D3DDEVTYPE device_type, HWND focus_window, DWORD flags, D3DPRESENT_PARAMETERS *parameters) DECLSPEC_HIDDEN; + /* ---------------- */ /* IDirect3DVolume8 */ /* ---------------- */ @@ -625,11 +618,6 @@ HRESULT pixelshader_init(IDirect3DPixelShader8Impl *shader, IDirect3DDevice8Impl D3DFORMAT d3dformat_from_wined3dformat(WINED3DFORMAT format) DECLSPEC_HIDDEN; WINED3DFORMAT wined3dformat_from_d3dformat(D3DFORMAT format) DECLSPEC_HIDDEN; void load_local_constants(const DWORD *d3d8_elements, IWineD3DVertexShader *wined3d_vertex_shader) DECLSPEC_HIDDEN; -UINT convert_to_wined3d_declaration(const DWORD *d3d8_elements, DWORD *d3d8_elements_size, - WINED3DVERTEXELEMENT **wined3d_elements) DECLSPEC_HIDDEN; size_t parse_token(const DWORD *pToken) DECLSPEC_HIDDEN; -/* Callbacks */ -extern ULONG WINAPI D3D8CB_DestroySwapChain(IWineD3DSwapChain *pSwapChain) DECLSPEC_HIDDEN; - #endif /* __WINE_D3DX8_PRIVATE_H */ diff --git a/dlls/d3d8/device.c b/dlls/d3d8/device.c index 50a257d3427..450a5ffb3ca 100644 --- a/dlls/d3d8/device.c +++ b/dlls/d3d8/device.c @@ -253,6 +253,17 @@ static void *d3d8_get_object(struct d3d8_handle_table *t, DWORD handle, enum d3d return entry->object; } +static ULONG WINAPI D3D8CB_DestroySwapChain(IWineD3DSwapChain *swapchain) +{ + IUnknown *parent; + + TRACE("swapchain %p.\n", swapchain); + + IWineD3DSwapChain_GetParent(swapchain, &parent); + IUnknown_Release(parent); + return IUnknown_Release(parent); +} + /* IDirect3D IUnknown parts follow: */ static HRESULT WINAPI IDirect3DDevice8Impl_QueryInterface(LPDIRECT3DDEVICE8 iface,REFIID riid,LPVOID *ppobj) { @@ -323,17 +334,11 @@ static ULONG WINAPI IDirect3DDevice8Impl_Release(LPDIRECT3DDEVICE8 iface) { } /* IDirect3DDevice Interface follow: */ -static HRESULT WINAPI IDirect3DDevice8Impl_TestCooperativeLevel(LPDIRECT3DDEVICE8 iface) { - IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; - HRESULT hr; - +static HRESULT WINAPI IDirect3DDevice8Impl_TestCooperativeLevel(IDirect3DDevice8 *iface) +{ TRACE("iface %p.\n", iface); - wined3d_mutex_lock(); - hr = IWineD3DDevice_TestCooperativeLevel(This->WineD3DDevice); - wined3d_mutex_unlock(); - - return hr; + return D3D_OK; } static UINT WINAPI IDirect3DDevice8Impl_GetAvailableTextureMem(LPDIRECT3DDEVICE8 iface) { @@ -2469,8 +2474,7 @@ static HRESULT WINAPI IDirect3DDevice8Impl_GetStreamSource(LPDIRECT3DDEVICE8 ifa return rc; } - -const IDirect3DDevice8Vtbl Direct3DDevice8_Vtbl = +static const IDirect3DDevice8Vtbl Direct3DDevice8_Vtbl = { IDirect3DDevice8Impl_QueryInterface, IDirect3DDevice8Impl_AddRef, @@ -2798,7 +2802,7 @@ static HRESULT STDMETHODCALLTYPE device_parent_CreateSwapChain(IWineD3DDevicePar return hr; } -const IWineD3DDeviceParentVtbl d3d8_wined3d_device_parent_vtbl = +static const IWineD3DDeviceParentVtbl d3d8_wined3d_device_parent_vtbl = { /* IUnknown methods */ device_parent_QueryInterface, @@ -2812,3 +2816,102 @@ const IWineD3DDeviceParentVtbl d3d8_wined3d_device_parent_vtbl = device_parent_CreateVolume, device_parent_CreateSwapChain, }; + +HRESULT device_init(IDirect3DDevice8Impl *device, IWineD3D *wined3d, UINT adapter, + D3DDEVTYPE device_type, HWND focus_window, DWORD flags, D3DPRESENT_PARAMETERS *parameters) +{ + WINED3DPRESENT_PARAMETERS wined3d_parameters; + HRESULT hr; + + device->lpVtbl = &Direct3DDevice8_Vtbl; + device->device_parent_vtbl = &d3d8_wined3d_device_parent_vtbl; + device->ref = 1; + device->handle_table.entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + D3D8_INITIAL_HANDLE_TABLE_SIZE * sizeof(*device->handle_table.entries)); + if (!device->handle_table.entries) + { + ERR("Failed to allocate handle table memory.\n"); + return E_OUTOFMEMORY; + } + device->handle_table.table_size = D3D8_INITIAL_HANDLE_TABLE_SIZE; + + wined3d_mutex_lock(); + hr = IWineD3D_CreateDevice(wined3d, adapter, device_type, focus_window, flags, (IUnknown *)device, + (IWineD3DDeviceParent *)&device->device_parent_vtbl, &device->WineD3DDevice); + if (FAILED(hr)) + { + WARN("Failed to create wined3d device, hr %#x.\n", hr); + wined3d_mutex_unlock(); + HeapFree(GetProcessHeap(), 0, device->handle_table.entries); + return hr; + } + + if (flags & D3DCREATE_MULTITHREADED) IWineD3DDevice_SetMultithreaded(device->WineD3DDevice); + + wined3d_parameters.BackBufferWidth = parameters->BackBufferWidth; + wined3d_parameters.BackBufferHeight = parameters->BackBufferHeight; + wined3d_parameters.BackBufferFormat = wined3dformat_from_d3dformat(parameters->BackBufferFormat); + wined3d_parameters.BackBufferCount = parameters->BackBufferCount; + wined3d_parameters.MultiSampleType = parameters->MultiSampleType; + wined3d_parameters.MultiSampleQuality = 0; /* d3d9 only */ + wined3d_parameters.SwapEffect = parameters->SwapEffect; + wined3d_parameters.hDeviceWindow = parameters->hDeviceWindow; + wined3d_parameters.Windowed = parameters->Windowed; + wined3d_parameters.EnableAutoDepthStencil = parameters->EnableAutoDepthStencil; + wined3d_parameters.AutoDepthStencilFormat = wined3dformat_from_d3dformat(parameters->AutoDepthStencilFormat); + wined3d_parameters.Flags = parameters->Flags; + wined3d_parameters.FullScreen_RefreshRateInHz = parameters->FullScreen_RefreshRateInHz; + wined3d_parameters.PresentationInterval = parameters->FullScreen_PresentationInterval; + wined3d_parameters.AutoRestoreDisplayMode = TRUE; + + hr = IWineD3DDevice_Init3D(device->WineD3DDevice, &wined3d_parameters); + if (FAILED(hr)) + { + WARN("Failed to initialize 3D, hr %#x.\n", hr); + IWineD3DDevice_Release(device->WineD3DDevice); + wined3d_mutex_unlock(); + HeapFree(GetProcessHeap(), 0, device->handle_table.entries); + return hr; + } + + hr = IWineD3DDevice_SetRenderState(device->WineD3DDevice, WINED3DRS_POINTSIZE_MIN, 0); + wined3d_mutex_unlock(); + if (FAILED(hr)) + { + ERR("Failed to set minimum pointsize, hr %#x.\n", hr); + goto err; + } + + parameters->BackBufferWidth = wined3d_parameters.BackBufferWidth; + parameters->BackBufferHeight = wined3d_parameters.BackBufferHeight; + parameters->BackBufferFormat = d3dformat_from_wined3dformat(wined3d_parameters.BackBufferFormat); + parameters->BackBufferCount = wined3d_parameters.BackBufferCount; + parameters->MultiSampleType = wined3d_parameters.MultiSampleType; + parameters->SwapEffect = wined3d_parameters.SwapEffect; + parameters->hDeviceWindow = wined3d_parameters.hDeviceWindow; + parameters->Windowed = wined3d_parameters.Windowed; + parameters->EnableAutoDepthStencil = wined3d_parameters.EnableAutoDepthStencil; + parameters->AutoDepthStencilFormat = d3dformat_from_wined3dformat(wined3d_parameters.AutoDepthStencilFormat); + parameters->Flags = wined3d_parameters.Flags; + parameters->FullScreen_RefreshRateInHz = wined3d_parameters.FullScreen_RefreshRateInHz; + parameters->FullScreen_PresentationInterval = wined3d_parameters.PresentationInterval; + + device->declArraySize = 16; + device->decls = HeapAlloc(GetProcessHeap(), 0, device->declArraySize * sizeof(*device->decls)); + if (!device->decls) + { + ERR("Failed to allocate FVF vertex delcaration map memory.\n"); + hr = E_OUTOFMEMORY; + goto err; + } + + return D3D_OK; + +err: + wined3d_mutex_lock(); + IWineD3DDevice_Uninit3D(device->WineD3DDevice, D3D8CB_DestroySwapChain); + IWineD3DDevice_Release(device->WineD3DDevice); + wined3d_mutex_unlock(); + HeapFree(GetProcessHeap(), 0, device->handle_table.entries); + return hr; +} diff --git a/dlls/d3d8/directx.c b/dlls/d3d8/directx.c index e5ecc753c5d..8bcd5abf9c9 100644 --- a/dlls/d3d8/directx.c +++ b/dlls/d3d8/directx.c @@ -331,132 +331,35 @@ static HMONITOR WINAPI IDirect3D8Impl_GetAdapterMonitor(LPDIRECT3D8 iface, UINT return ret; } -ULONG WINAPI D3D8CB_DestroySwapChain(IWineD3DSwapChain *pSwapChain) { - IUnknown* swapChainParent; - - TRACE("swapchain %p.\n", pSwapChain); - - IWineD3DSwapChain_GetParent(pSwapChain, &swapChainParent); - IUnknown_Release(swapChainParent); - return IUnknown_Release(swapChainParent); -} - -static HRESULT WINAPI IDirect3D8Impl_CreateDevice(LPDIRECT3D8 iface, UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, - DWORD BehaviourFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, - IDirect3DDevice8** ppReturnedDeviceInterface) { - - IDirect3D8Impl *This = (IDirect3D8Impl *)iface; - IDirect3DDevice8Impl *object = NULL; - WINED3DPRESENT_PARAMETERS localParameters; +static HRESULT WINAPI IDirect3D8Impl_CreateDevice(IDirect3D8 *iface, UINT adapter, D3DDEVTYPE device_type, + HWND focus_window, DWORD flags, D3DPRESENT_PARAMETERS *parameters, IDirect3DDevice8 **device) +{ + IDirect3D8Impl *This = (IDirect3D8Impl *)iface; + IDirect3DDevice8Impl *object; HRESULT hr; TRACE("iface %p, adapter %u, device_type %#x, focus_window %p, flags %#x, parameters %p, device %p.\n", - iface, Adapter, DeviceType, hFocusWindow, BehaviourFlags, pPresentationParameters, - ppReturnedDeviceInterface); + iface, adapter, device_type, focus_window, flags, parameters, device); - /* Check the validity range of the adapter parameter */ - if (Adapter >= IDirect3D8Impl_GetAdapterCount(iface)) { - *ppReturnedDeviceInterface = NULL; - return D3DERR_INVALIDCALL; - } - - /* Allocate the storage for the device object */ - object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DDevice8Impl)); - if (NULL == object) { - FIXME("Allocation of memory failed\n"); - *ppReturnedDeviceInterface = NULL; - return D3DERR_OUTOFVIDEOMEMORY; + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)); + if (!object) + { + ERR("Failed to allocate device memory.\n"); + return E_OUTOFMEMORY; } - object->lpVtbl = &Direct3DDevice8_Vtbl; - object->device_parent_vtbl = &d3d8_wined3d_device_parent_vtbl; - object->ref = 1; - object->handle_table.entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - D3D8_INITIAL_HANDLE_TABLE_SIZE * sizeof(*object->handle_table.entries)); - object->handle_table.table_size = D3D8_INITIAL_HANDLE_TABLE_SIZE; - *ppReturnedDeviceInterface = (IDirect3DDevice8 *)object; - - /* Allocate an associated WineD3DDevice object */ - wined3d_mutex_lock(); - hr = IWineD3D_CreateDevice(This->WineD3D, Adapter, DeviceType, hFocusWindow, BehaviourFlags, - (IUnknown *)object, (IWineD3DDeviceParent *)&object->device_parent_vtbl, &object->WineD3DDevice); - - if (hr != D3D_OK) { + hr = device_init(object, This->WineD3D, adapter, device_type, focus_window, flags, parameters); + if (FAILED(hr)) + { + WARN("Failed to initialize device, hr %#x.\n", hr); HeapFree(GetProcessHeap(), 0, object); - *ppReturnedDeviceInterface = NULL; - wined3d_mutex_unlock(); - return hr; } - TRACE("(%p) : Created Device %p\n", This, object); - - localParameters.BackBufferWidth = pPresentationParameters->BackBufferWidth; - localParameters.BackBufferHeight = pPresentationParameters->BackBufferHeight; - localParameters.BackBufferFormat = wined3dformat_from_d3dformat(pPresentationParameters->BackBufferFormat); - localParameters.BackBufferCount = pPresentationParameters->BackBufferCount; - localParameters.MultiSampleType = pPresentationParameters->MultiSampleType; - localParameters.MultiSampleQuality = 0; /* d3d9 only */ - localParameters.SwapEffect = pPresentationParameters->SwapEffect; - localParameters.hDeviceWindow = pPresentationParameters->hDeviceWindow; - localParameters.Windowed = pPresentationParameters->Windowed; - localParameters.EnableAutoDepthStencil = pPresentationParameters->EnableAutoDepthStencil; - localParameters.AutoDepthStencilFormat = wined3dformat_from_d3dformat(pPresentationParameters->AutoDepthStencilFormat); - localParameters.Flags = pPresentationParameters->Flags; - localParameters.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz; - localParameters.PresentationInterval = pPresentationParameters->FullScreen_PresentationInterval; - localParameters.AutoRestoreDisplayMode = TRUE; - - if(BehaviourFlags & D3DCREATE_MULTITHREADED) { - IWineD3DDevice_SetMultithreaded(object->WineD3DDevice); - } - - hr = IWineD3DDevice_Init3D(object->WineD3DDevice, &localParameters); - if (hr != D3D_OK) { - wined3d_mutex_unlock(); - FIXME("(%p) D3D Initialization failed for WineD3DDevice %p\n", This, object->WineD3DDevice); - goto err; - } - hr = IWineD3DDevice_SetRenderState(object->WineD3DDevice, WINED3DRS_POINTSIZE_MIN, 0); - wined3d_mutex_unlock(); - if(FAILED(hr)) { - FIXME("(%p) SetRenderState failed\n", This); - goto err; - } + TRACE("Created device %p.\n", object); + *device = (IDirect3DDevice8 *)object; - pPresentationParameters->BackBufferWidth = localParameters.BackBufferWidth; - pPresentationParameters->BackBufferHeight = localParameters.BackBufferHeight; - pPresentationParameters->BackBufferFormat = d3dformat_from_wined3dformat(localParameters.BackBufferFormat); - pPresentationParameters->BackBufferCount = localParameters.BackBufferCount; - pPresentationParameters->MultiSampleType = localParameters.MultiSampleType; - pPresentationParameters->SwapEffect = localParameters.SwapEffect; - pPresentationParameters->hDeviceWindow = localParameters.hDeviceWindow; - pPresentationParameters->Windowed = localParameters.Windowed; - pPresentationParameters->EnableAutoDepthStencil = localParameters.EnableAutoDepthStencil; - pPresentationParameters->AutoDepthStencilFormat = d3dformat_from_wined3dformat(localParameters.AutoDepthStencilFormat); - pPresentationParameters->Flags = localParameters.Flags; - pPresentationParameters->FullScreen_RefreshRateInHz = localParameters.FullScreen_RefreshRateInHz; - pPresentationParameters->FullScreen_PresentationInterval = localParameters.PresentationInterval; - - object->declArraySize = 16; - object->decls = HeapAlloc(GetProcessHeap(), 0, object->declArraySize * sizeof(*object->decls)); - if(!object->decls) { - ERR("Out of memory\n"); - hr = E_OUTOFMEMORY; - goto err; - } return D3D_OK; - -err: - *ppReturnedDeviceInterface = NULL; - - HeapFree(GetProcessHeap(), 0, object->decls); - wined3d_mutex_lock(); - IWineD3DDevice_Uninit3D(object->WineD3DDevice, D3D8CB_DestroySwapChain); - IWineD3DDevice_Release(object->WineD3DDevice); - wined3d_mutex_unlock(); - HeapFree(GetProcessHeap(), 0, object); - return hr; } const IDirect3D8Vtbl Direct3D8_Vtbl = diff --git a/dlls/d3d8/vertexdeclaration.c b/dlls/d3d8/vertexdeclaration.c index bcc9991aead..b876b66c41c 100644 --- a/dlls/d3d8/vertexdeclaration.c +++ b/dlls/d3d8/vertexdeclaration.c @@ -301,7 +301,8 @@ static const wined3d_usage_t wined3d_usage_lookup[] = { }; /* TODO: find out where rhw (or positionT) is for declaration8 */ -UINT convert_to_wined3d_declaration(const DWORD *d3d8_elements, DWORD *d3d8_elements_size, WINED3DVERTEXELEMENT **wined3d_elements) +static UINT convert_to_wined3d_declaration(const DWORD *d3d8_elements, DWORD *d3d8_elements_size, + WINED3DVERTEXELEMENT **wined3d_elements) { const DWORD *token = d3d8_elements; WINED3DVERTEXELEMENT *element; diff --git a/dlls/d3d9/d3d9_private.h b/dlls/d3d9/d3d9_private.h index 6184df29f7a..cbe5d808879 100644 --- a/dlls/d3d9/d3d9_private.h +++ b/dlls/d3d9/d3d9_private.h @@ -158,16 +158,6 @@ typedef struct IDirect3D9Impl void filter_caps(D3DCAPS9* pCaps) DECLSPEC_HIDDEN; -/* ---------------- */ -/* IDirect3DDevice9 */ -/* ---------------- */ - -/***************************************************************************** - * Predeclare the interface implementation structures - */ -extern const IDirect3DDevice9ExVtbl Direct3DDevice9_Vtbl DECLSPEC_HIDDEN; -extern const IWineD3DDeviceParentVtbl d3d9_wined3d_device_parent_vtbl DECLSPEC_HIDDEN; - /***************************************************************************** * IDirect3DDevice9 implementation structure */ @@ -190,6 +180,8 @@ typedef struct IDirect3DDevice9Impl BOOL notreset; } IDirect3DDevice9Impl; +HRESULT device_init(IDirect3DDevice9Impl *device, IWineD3D *wined3d, UINT adapter, D3DDEVTYPE device_type, + HWND focus_window, DWORD flags, D3DPRESENT_PARAMETERS *parameters) DECLSPEC_HIDDEN; /* IDirect3DDevice9: */ extern HRESULT WINAPI IDirect3DDevice9Impl_CreateAdditionalSwapChain(IDirect3DDevice9Ex *iface, @@ -571,8 +563,4 @@ typedef struct IDirect3DQuery9Impl { LPDIRECT3DDEVICE9EX parentDevice; } IDirect3DQuery9Impl; - -/* Callbacks */ -extern ULONG WINAPI D3D9CB_DestroySwapChain (IWineD3DSwapChain *pSwapChain) DECLSPEC_HIDDEN; - #endif /* __WINE_D3D9_PRIVATE_H */ diff --git a/dlls/d3d9/device.c b/dlls/d3d9/device.c index bb6327044f7..dfb6b266279 100644 --- a/dlls/d3d9/device.c +++ b/dlls/d3d9/device.c @@ -181,6 +181,17 @@ static UINT vertex_count_from_primitive_count(D3DPRIMITIVETYPE primitive_type, U } } +static ULONG WINAPI D3D9CB_DestroySwapChain(IWineD3DSwapChain *swapchain) +{ + IDirect3DSwapChain9Impl *parent; + + TRACE("swapchain %p.\n", swapchain); + + IWineD3DSwapChain_GetParent(swapchain, (IUnknown **)&parent); + parent->isImplicit = FALSE; + return IDirect3DSwapChain9_Release((IDirect3DSwapChain9 *)parent); +} + /* IDirect3D IUnknown parts follow: */ static HRESULT WINAPI IDirect3DDevice9Impl_QueryInterface(LPDIRECT3DDEVICE9EX iface, REFIID riid, LPVOID* ppobj) { IDirect3DDevice9Impl *This = (IDirect3DDevice9Impl *)iface; @@ -269,22 +280,19 @@ static ULONG WINAPI DECLSPEC_HOTPATCH IDirect3DDevice9Impl_Release(LPDIRECT3DDEV } /* IDirect3DDevice Interface follow: */ -static HRESULT WINAPI IDirect3DDevice9Impl_TestCooperativeLevel(LPDIRECT3DDEVICE9EX iface) { +static HRESULT WINAPI IDirect3DDevice9Impl_TestCooperativeLevel(IDirect3DDevice9Ex *iface) +{ IDirect3DDevice9Impl *This = (IDirect3DDevice9Impl *)iface; - HRESULT hr; TRACE("iface %p.\n", iface); - wined3d_mutex_lock(); - hr = IWineD3DDevice_TestCooperativeLevel(This->WineD3DDevice); - wined3d_mutex_unlock(); - - if(hr == WINED3D_OK && This->notreset) { - TRACE("D3D9 Device is marked not reset\n"); - hr = D3DERR_DEVICENOTRESET; + if (This->notreset) + { + TRACE("D3D9 device is marked not reset.\n"); + return D3DERR_DEVICENOTRESET; } - return hr; + return D3D_OK; } static UINT WINAPI IDirect3DDevice9Impl_GetAvailableTextureMem(LPDIRECT3DDEVICE9EX iface) { @@ -2273,7 +2281,7 @@ static HRESULT WINAPI IDirect3DDevice9ExImpl_GetDisplayModeEx(IDirect3DDevice9 return WINED3DERR_INVALIDCALL; } -const IDirect3DDevice9ExVtbl Direct3DDevice9_Vtbl = +static const IDirect3DDevice9ExVtbl Direct3DDevice9_Vtbl = { /* IUnknown */ IDirect3DDevice9Impl_QueryInterface, @@ -2645,7 +2653,7 @@ static HRESULT STDMETHODCALLTYPE device_parent_CreateSwapChain(IWineD3DDevicePar return hr; } -const IWineD3DDeviceParentVtbl d3d9_wined3d_device_parent_vtbl = +static const IWineD3DDeviceParentVtbl d3d9_wined3d_device_parent_vtbl = { /* IUnknown methods */ device_parent_QueryInterface, @@ -2659,3 +2667,111 @@ const IWineD3DDeviceParentVtbl d3d9_wined3d_device_parent_vtbl = device_parent_CreateVolume, device_parent_CreateSwapChain, }; + +HRESULT device_init(IDirect3DDevice9Impl *device, IWineD3D *wined3d, UINT adapter, D3DDEVTYPE device_type, + HWND focus_window, DWORD flags, D3DPRESENT_PARAMETERS *parameters) +{ + WINED3DPRESENT_PARAMETERS *wined3d_parameters; + UINT i, count = 1; + HRESULT hr; + + device->lpVtbl = &Direct3DDevice9_Vtbl; + device->device_parent_vtbl = &d3d9_wined3d_device_parent_vtbl; + device->ref = 1; + + wined3d_mutex_lock(); + hr = IWineD3D_CreateDevice(wined3d, adapter, device_type, focus_window, flags, (IUnknown *)device, + (IWineD3DDeviceParent *)&device->device_parent_vtbl, &device->WineD3DDevice); + if (FAILED(hr)) + { + WARN("Failed to create wined3d device, hr %#x.\n", hr); + wined3d_mutex_unlock(); + return hr; + } + + if (flags & D3DCREATE_ADAPTERGROUP_DEVICE) + { + WINED3DCAPS caps; + + IWineD3D_GetDeviceCaps(wined3d, adapter, device_type, &caps); + count = caps.NumberOfAdaptersInGroup; + } + + if (flags & D3DCREATE_MULTITHREADED) IWineD3DDevice_SetMultithreaded(device->WineD3DDevice); + + wined3d_parameters = HeapAlloc(GetProcessHeap(), 0, sizeof(*wined3d_parameters) * count); + if (!wined3d_parameters) + { + ERR("Failed to allocate wined3d parameters.\n"); + IWineD3DDevice_Release(device->WineD3DDevice); + wined3d_mutex_unlock(); + return E_OUTOFMEMORY; + } + + for (i = 0; i < count; ++i) + { + wined3d_parameters[i].BackBufferWidth = parameters[i].BackBufferWidth; + wined3d_parameters[i].BackBufferHeight = parameters[i].BackBufferHeight; + wined3d_parameters[i].BackBufferFormat = wined3dformat_from_d3dformat(parameters[i].BackBufferFormat); + wined3d_parameters[i].BackBufferCount = parameters[i].BackBufferCount; + wined3d_parameters[i].MultiSampleType = parameters[i].MultiSampleType; + wined3d_parameters[i].MultiSampleQuality = parameters[i].MultiSampleQuality; + wined3d_parameters[i].SwapEffect = parameters[i].SwapEffect; + wined3d_parameters[i].hDeviceWindow = parameters[i].hDeviceWindow; + wined3d_parameters[i].Windowed = parameters[i].Windowed; + wined3d_parameters[i].EnableAutoDepthStencil = parameters[i].EnableAutoDepthStencil; + wined3d_parameters[i].AutoDepthStencilFormat = + wined3dformat_from_d3dformat(parameters[i].AutoDepthStencilFormat); + wined3d_parameters[i].Flags = parameters[i].Flags; + wined3d_parameters[i].FullScreen_RefreshRateInHz = parameters[i].FullScreen_RefreshRateInHz; + wined3d_parameters[i].PresentationInterval = parameters[i].PresentationInterval; + wined3d_parameters[i].AutoRestoreDisplayMode = TRUE; + } + + hr = IWineD3DDevice_Init3D(device->WineD3DDevice, wined3d_parameters); + if (FAILED(hr)) + { + WARN("Failed to initialize 3D, hr %#x.\n", hr); + HeapFree(GetProcessHeap(), 0, wined3d_parameters); + IWineD3DDevice_Release(device->WineD3DDevice); + wined3d_mutex_unlock(); + return hr; + } + + wined3d_mutex_unlock(); + + for (i = 0; i < count; ++i) + { + parameters[i].BackBufferWidth = wined3d_parameters[i].BackBufferWidth; + parameters[i].BackBufferHeight = wined3d_parameters[i].BackBufferHeight; + parameters[i].BackBufferFormat = d3dformat_from_wined3dformat(wined3d_parameters[i].BackBufferFormat); + parameters[i].BackBufferCount = wined3d_parameters[i].BackBufferCount; + parameters[i].MultiSampleType = wined3d_parameters[i].MultiSampleType; + parameters[i].MultiSampleQuality = wined3d_parameters[i].MultiSampleQuality; + parameters[i].SwapEffect = wined3d_parameters[i].SwapEffect; + parameters[i].hDeviceWindow = wined3d_parameters[i].hDeviceWindow; + parameters[i].Windowed = wined3d_parameters[i].Windowed; + parameters[i].EnableAutoDepthStencil = wined3d_parameters[i].EnableAutoDepthStencil; + parameters[i].AutoDepthStencilFormat = + d3dformat_from_wined3dformat(wined3d_parameters[i].AutoDepthStencilFormat); + parameters[i].Flags = wined3d_parameters[i].Flags; + parameters[i].FullScreen_RefreshRateInHz = wined3d_parameters[i].FullScreen_RefreshRateInHz; + parameters[i].PresentationInterval = wined3d_parameters[i].PresentationInterval; + } + HeapFree(GetProcessHeap(), 0, wined3d_parameters); + + /* Initialize the converted declaration array. This creates a valid pointer + * and when adding decls HeapReAlloc() can be used without further checking. */ + device->convertedDecls = HeapAlloc(GetProcessHeap(), 0, 0); + if (!device->convertedDecls) + { + ERR("Failed to allocate FVF vertex declaration map memory.\n"); + wined3d_mutex_lock(); + IWineD3DDevice_Uninit3D(device->WineD3DDevice, D3D9CB_DestroySwapChain); + IWineD3DDevice_Release(device->WineD3DDevice); + wined3d_mutex_unlock(); + return E_OUTOFMEMORY; + } + + return D3D_OK; +} diff --git a/dlls/d3d9/directx.c b/dlls/d3d9/directx.c index cb5b85e17bd..939538158a7 100644 --- a/dlls/d3d9/directx.c +++ b/dlls/d3d9/directx.c @@ -407,129 +407,36 @@ static HMONITOR WINAPI IDirect3D9Impl_GetAdapterMonitor(LPDIRECT3D9EX iface, UIN return ret; } -ULONG WINAPI D3D9CB_DestroySwapChain(IWineD3DSwapChain *pSwapChain) { - IDirect3DSwapChain9Impl* swapChainParent; - TRACE("(%p) call back\n", pSwapChain); - - IWineD3DSwapChain_GetParent(pSwapChain,(IUnknown **) &swapChainParent); - swapChainParent->isImplicit = FALSE; - /* Swap chain had refcount of 0 GetParent addrefed to 1, so 1 Release is enough */ - return IDirect3DSwapChain9_Release((IDirect3DSwapChain9*) swapChainParent); -} - -static HRESULT WINAPI DECLSPEC_HOTPATCH IDirect3D9Impl_CreateDevice(LPDIRECT3D9EX iface, UINT Adapter, D3DDEVTYPE DeviceType, - HWND hFocusWindow, DWORD BehaviourFlags, - D3DPRESENT_PARAMETERS* pPresentationParameters, - IDirect3DDevice9** ppReturnedDeviceInterface) { - - IDirect3D9Impl *This = (IDirect3D9Impl *)iface; - IDirect3DDevice9Impl *object = NULL; - WINED3DPRESENT_PARAMETERS *localParameters; - UINT i, count = 1; +static HRESULT WINAPI DECLSPEC_HOTPATCH IDirect3D9Impl_CreateDevice(IDirect3D9Ex *iface, UINT adapter, + D3DDEVTYPE device_type, HWND focus_window, DWORD flags, D3DPRESENT_PARAMETERS *parameters, + IDirect3DDevice9 **device) +{ + IDirect3D9Impl *This = (IDirect3D9Impl *)iface; + IDirect3DDevice9Impl *object; HRESULT hr; TRACE("iface %p, adapter %u, device_type %#x, focus_window %p, flags %#x, parameters %p, device %p.\n", - iface, Adapter, DeviceType, hFocusWindow, BehaviourFlags, pPresentationParameters, - ppReturnedDeviceInterface); - - /* Check the validity range of the adapter parameter */ - if (Adapter >= IDirect3D9Impl_GetAdapterCount(iface)) { - *ppReturnedDeviceInterface = NULL; - return D3DERR_INVALIDCALL; - } + iface, adapter, device_type, focus_window, flags, parameters, device); - /* Allocate the storage for the device object */ - object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DDevice9Impl)); - if (NULL == object) { - FIXME("Allocation of memory failed\n"); - *ppReturnedDeviceInterface = NULL; - return D3DERR_OUTOFVIDEOMEMORY; - } - - object->lpVtbl = &Direct3DDevice9_Vtbl; - object->device_parent_vtbl = &d3d9_wined3d_device_parent_vtbl; - object->ref = 1; - *ppReturnedDeviceInterface = (IDirect3DDevice9 *)object; - - /* Allocate an associated WineD3DDevice object */ - wined3d_mutex_lock(); - hr = IWineD3D_CreateDevice(This->WineD3D, Adapter, DeviceType, hFocusWindow, BehaviourFlags, - (IUnknown *)object, (IWineD3DDeviceParent *)&object->device_parent_vtbl, &object->WineD3DDevice); - if (hr != D3D_OK) { - HeapFree(GetProcessHeap(), 0, object); - *ppReturnedDeviceInterface = NULL; - wined3d_mutex_unlock(); - - return hr; - } - - TRACE("(%p) : Created Device %p\n", This, object); - - if (BehaviourFlags & D3DCREATE_ADAPTERGROUP_DEVICE) + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)); + if (!object) { - WINED3DCAPS caps; - - IWineD3D_GetDeviceCaps(This->WineD3D, Adapter, DeviceType, &caps); - count = caps.NumberOfAdaptersInGroup; + ERR("Failed to allocate device memory.\n"); + return E_OUTOFMEMORY; } - if(BehaviourFlags & D3DCREATE_MULTITHREADED) { - IWineD3DDevice_SetMultithreaded(object->WineD3DDevice); - } - - localParameters = HeapAlloc(GetProcessHeap(), 0, sizeof(*localParameters) * count); - for (i = 0; i < count; ++i) + hr = device_init(object, This->WineD3D, adapter, device_type, focus_window, flags, parameters); + if (FAILED(hr)) { - localParameters[i].BackBufferWidth = pPresentationParameters[i].BackBufferWidth; - localParameters[i].BackBufferHeight = pPresentationParameters[i].BackBufferHeight; - localParameters[i].BackBufferFormat = wined3dformat_from_d3dformat(pPresentationParameters[i].BackBufferFormat); - localParameters[i].BackBufferCount = pPresentationParameters[i].BackBufferCount; - localParameters[i].MultiSampleType = pPresentationParameters[i].MultiSampleType; - localParameters[i].MultiSampleQuality = pPresentationParameters[i].MultiSampleQuality; - localParameters[i].SwapEffect = pPresentationParameters[i].SwapEffect; - localParameters[i].hDeviceWindow = pPresentationParameters[i].hDeviceWindow; - localParameters[i].Windowed = pPresentationParameters[i].Windowed; - localParameters[i].EnableAutoDepthStencil = pPresentationParameters[i].EnableAutoDepthStencil; - localParameters[i].AutoDepthStencilFormat = wined3dformat_from_d3dformat(pPresentationParameters[i].AutoDepthStencilFormat); - localParameters[i].Flags = pPresentationParameters[i].Flags; - localParameters[i].FullScreen_RefreshRateInHz = pPresentationParameters[i].FullScreen_RefreshRateInHz; - localParameters[i].PresentationInterval = pPresentationParameters[i].PresentationInterval; - localParameters[i].AutoRestoreDisplayMode = TRUE; - } - - hr = IWineD3DDevice_Init3D(object->WineD3DDevice, localParameters); - if (hr != D3D_OK) { - FIXME("(%p) D3D Initialization failed for WineD3DDevice %p\n", This, object->WineD3DDevice); + WARN("Failed to initialize device, hr %#x.\n", hr); HeapFree(GetProcessHeap(), 0, object); - *ppReturnedDeviceInterface = NULL; + return hr; } - for (i = 0; i < count; ++i) - { - pPresentationParameters[i].BackBufferWidth = localParameters[i].BackBufferWidth; - pPresentationParameters[i].BackBufferHeight = localParameters[i].BackBufferHeight; - pPresentationParameters[i].BackBufferFormat = d3dformat_from_wined3dformat(localParameters[i].BackBufferFormat); - pPresentationParameters[i].BackBufferCount = localParameters[i].BackBufferCount; - pPresentationParameters[i].MultiSampleType = localParameters[i].MultiSampleType; - pPresentationParameters[i].MultiSampleQuality = localParameters[i].MultiSampleQuality; - pPresentationParameters[i].SwapEffect = localParameters[i].SwapEffect; - pPresentationParameters[i].hDeviceWindow = localParameters[i].hDeviceWindow; - pPresentationParameters[i].Windowed = localParameters[i].Windowed; - pPresentationParameters[i].EnableAutoDepthStencil = localParameters[i].EnableAutoDepthStencil; - pPresentationParameters[i].AutoDepthStencilFormat = d3dformat_from_wined3dformat(localParameters[i].AutoDepthStencilFormat); - pPresentationParameters[i].Flags = localParameters[i].Flags; - pPresentationParameters[i].FullScreen_RefreshRateInHz = localParameters[i].FullScreen_RefreshRateInHz; - pPresentationParameters[i].PresentationInterval = localParameters[i].PresentationInterval; - } - HeapFree(GetProcessHeap(), 0, localParameters); + TRACE("Created device %p.\n", object); + *device = (IDirect3DDevice9 *)object; - /* Initialize the converted declaration array. This creates a valid pointer and when adding decls HeapReAlloc - * can be used without further checking - */ - object->convertedDecls = HeapAlloc(GetProcessHeap(), 0, 0); - wined3d_mutex_unlock(); - - return hr; + return D3D_OK; } static UINT WINAPI IDirect3D9ExImpl_GetAdapterModeCountEx(IDirect3D9Ex *iface, diff --git a/dlls/dbghelp/dbghelp.spec b/dlls/dbghelp/dbghelp.spec index 63a107c46e5..825493ab27c 100644 --- a/dlls/dbghelp/dbghelp.spec +++ b/dlls/dbghelp/dbghelp.spec @@ -144,7 +144,7 @@ @ stub SymNextW @ stub SymPrev @ stub SymPrevW -@ stub SymRefreshModuleList +@ stdcall SymRefreshModuleList(long) @ stdcall SymRegisterCallback(long ptr ptr) @ stdcall SymRegisterCallback64(long ptr double) @ stdcall SymRegisterCallbackW64(long ptr double) diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 0a014095b84..4faae4d0344 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -246,7 +246,7 @@ struct symt_array { struct symt symt; int start; - int end; + int end; /* end index if > 0, or -array_len (in bytes) if < 0 */ struct symt* base_type; struct symt* index_type; }; diff --git a/dlls/dbghelp/module.c b/dlls/dbghelp/module.c index 6199b5827ce..a6778e746a5 100644 --- a/dlls/dbghelp/module.c +++ b/dlls/dbghelp/module.c @@ -455,6 +455,15 @@ enum module_type module_get_type_by_name(const WCHAR* name) return DMT_PE; } +/****************************************************************** + * refresh_module_list + */ +static BOOL refresh_module_list(struct process* pcs) +{ + /* force transparent ELF and Mach-O loading / unloading */ + return elf_synchronize_module_list(pcs) || macho_synchronize_module_list(pcs); +} + /*********************************************************************** * SymLoadModule (DBGHELP.@) */ @@ -536,9 +545,7 @@ DWORD64 WINAPI SymLoadModuleExW(HANDLE hProcess, HANDLE hFile, PCWSTR wImageNam if (Flags & ~(SLMFLAG_VIRTUAL)) FIXME("Unsupported Flags %08x for %s\n", Flags, debugstr_w(wImageName)); - /* force transparent ELF and Mach-O loading / unloading */ - elf_synchronize_module_list(pcs); - macho_synchronize_module_list(pcs); + refresh_module_list(pcs); /* this is a Wine extension to the API just to redo the synchronisation */ if (!wImageName && !hFile) return 0; @@ -1052,3 +1059,17 @@ void module_reset_debug_info(struct module* module) module->sources_used = module->sources_alloc = 0; module->sources = NULL; } + +/****************************************************************** + * SymRefreshModuleList (DBGHELP.@) + */ +BOOL WINAPI SymRefreshModuleList(HANDLE hProcess) +{ + struct process* pcs; + + TRACE("(%p)\n", hProcess); + + if (!(pcs = process_find_by_handle(hProcess))) return FALSE; + + return refresh_module_list(pcs); +} diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c index d31dd712dba..b3146022dd1 100644 --- a/dlls/dbghelp/msc.c +++ b/dlls/dbghelp/msc.c @@ -586,15 +586,8 @@ static struct symt* codeview_add_type_array(struct codeview_type_parse* ctp, { struct symt* elem = codeview_fetch_type(ctp, elemtype, FALSE); struct symt* index = codeview_fetch_type(ctp, indextype, FALSE); - DWORD arr_max = 0; - if (elem) - { - DWORD64 elem_size; - symt_get_info(elem, TI_GET_LENGTH, &elem_size); - if (elem_size) arr_max = arr_len / (DWORD)elem_size; - } - return &symt_new_array(ctp->module, 0, arr_max, elem, index)->symt; + return &symt_new_array(ctp->module, 0, -arr_len, elem, index)->symt; } static int codeview_add_type_enum_field_list(struct module* module, @@ -1417,7 +1410,7 @@ static void codeview_snarf_linetab2(const struct msc_debug_info* msc_dbg, const { symt_add_func_line(msc_dbg->module, func, source, lines_blk->l[i].lineno ^ 0x80000000, - lines_blk->l[i].offset - lines_blk->start); + lines_blk->l[i].offset); } break; case LT2_FILES_BLOCK: /* skip */ diff --git a/dlls/dbghelp/type.c b/dlls/dbghelp/type.c index 947eb49095e..3955815356d 100644 --- a/dlls/dbghelp/type.c +++ b/dlls/dbghelp/type.c @@ -304,6 +304,21 @@ struct symt_array* symt_new_array(struct module* module, int min, int max, return sym; } +static inline DWORD symt_array_count(const struct symt_array* array) +{ + if (array->end < 0) + { + DWORD64 elem_size; + /* One could want to also set the array->end field in array, but we won't do it + * as long as all the get_type() helpers use const objects + */ + if (symt_get_info(array->base_type, TI_GET_LENGTH, &elem_size) && elem_size) + return -array->end / (DWORD)elem_size; + return 0; + } + return array->end - array->start + 1; +} + struct symt_function_signature* symt_new_function_signature(struct module* module, struct symt* ret_type, enum CV_call_e call_conv) @@ -597,8 +612,7 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, switch (type->tag) { case SymTagArrayType: - X(DWORD) = ((const struct symt_array*)type)->end - - ((const struct symt_array*)type)->start + 1; + X(DWORD) = symt_array_count((const struct symt_array*)type); break; case SymTagFunctionType: /* this seems to be wrong for (future) C++ methods, where 'this' parameter @@ -643,8 +657,7 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, if (!symt_get_info(((const struct symt_array*)type)->base_type, TI_GET_LENGTH, pInfo)) return FALSE; - X(DWORD64) *= ((const struct symt_array*)type)->end - - ((const struct symt_array*)type)->start + 1; + X(DWORD64) *= symt_array_count((const struct symt_array*)type); break; case SymTagPublicSymbol: X(DWORD64) = ((const struct symt_public*)type)->size; diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c index 351ebdaa824..aeaffbd6af7 100644 --- a/dlls/ddraw/ddraw.c +++ b/dlls/ddraw/ddraw.c @@ -1187,53 +1187,8 @@ static HRESULT WINAPI IDirectDrawImpl_GetScanLine(IDirectDraw7 *iface, DWORD *Sc static HRESULT WINAPI IDirectDrawImpl_TestCooperativeLevel(IDirectDraw7 *iface) { - IDirectDrawImpl *This = (IDirectDrawImpl *)iface; - HRESULT hr; - TRACE("(%p)\n", This); - - EnterCriticalSection(&ddraw_cs); - /* Description from MSDN: - * For fullscreen apps return DDERR_NOEXCLUSIVEMODE if the user switched - * away from the app with e.g. alt-tab. Windowed apps receive - * DDERR_EXCLUSIVEMODEALREADYSET if another application created a - * DirectDraw object in exclusive mode. DDERR_WRONGMODE is returned, - * when the video mode has changed - */ - - hr = IWineD3DDevice_TestCooperativeLevel(This->wineD3DDevice); + TRACE("iface %p.\n", iface); - /* Fix the result value. These values are mapped from their - * d3d9 counterpart. - */ - switch(hr) - { - case WINED3DERR_DEVICELOST: - if(This->cooperative_level & DDSCL_EXCLUSIVE) - { - LeaveCriticalSection(&ddraw_cs); - return DDERR_NOEXCLUSIVEMODE; - } - else - { - LeaveCriticalSection(&ddraw_cs); - return DDERR_EXCLUSIVEMODEALREADYSET; - } - - case WINED3DERR_DEVICENOTRESET: - LeaveCriticalSection(&ddraw_cs); - return DD_OK; - - case WINED3D_OK: - LeaveCriticalSection(&ddraw_cs); - return DD_OK; - - case WINED3DERR_DRIVERINTERNALERROR: - default: - ERR("(%p) Unexpected return value %08x from wineD3D, " - " returning DD_OK\n", This, hr); - } - - LeaveCriticalSection(&ddraw_cs); return DD_OK; } diff --git a/dlls/ddraw/tests/dsurface.c b/dlls/ddraw/tests/dsurface.c index e05c967a576..f6f1258ad52 100644 --- a/dlls/ddraw/tests/dsurface.c +++ b/dlls/ddraw/tests/dsurface.c @@ -3136,7 +3136,7 @@ static void GetDCFormatTest(void) sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0, {32}, {0xC0000000}, {0x3FF00000}, {0x000FFC00}, {0x000003FF} }, - FALSE + TRUE }, /* * GetDC on a P8 surface fails unless the display mode is 8 bpp. This is not diff --git a/dlls/dsound/capture.c b/dlls/dsound/capture.c index 95b38af5dfc..93c711db567 100644 --- a/dlls/dsound/capture.c +++ b/dlls/dsound/capture.c @@ -254,136 +254,6 @@ HRESULT WINAPI DirectSoundCaptureCreate8( return hr; } -/*************************************************************************** - * DirectSoundCaptureEnumerateA [DSOUND.7] - * - * Enumerate all DirectSound drivers installed in the system. - * - * PARAMS - * lpDSEnumCallback [I] Address of callback function. - * lpContext [I] Address of user defined context passed to callback function. - * - * RETURNS - * Success: DS_OK - * Failure: DSERR_INVALIDPARAM - */ -HRESULT WINAPI -DirectSoundCaptureEnumerateA( - LPDSENUMCALLBACKA lpDSEnumCallback, - LPVOID lpContext) -{ - unsigned devs, wid; - DSDRIVERDESC desc; - GUID guid; - int err; - - TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext ); - - if (lpDSEnumCallback == NULL) { - WARN("invalid parameter: lpDSEnumCallback == NULL\n"); - return DSERR_INVALIDPARAM; - } - - devs = waveInGetNumDevs(); - if (devs > 0) { - if (GetDeviceID(&DSDEVID_DefaultCapture, &guid) == DS_OK) { - for (wid = 0; wid < devs; ++wid) { - if (IsEqualGUID( &guid, &DSOUND_capture_guids[wid] ) ) { - err = mmErr(waveInMessage(UlongToHandle(wid),DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0)); - if (err == DS_OK) { - TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n", - "Primary Sound Capture Driver",desc.szDrvname,lpContext); - if (lpDSEnumCallback(NULL, "Primary Sound Capture Driver", desc.szDrvname, lpContext) == FALSE) - return DS_OK; - } - } - } - } - } - - for (wid = 0; wid < devs; ++wid) { - err = mmErr(waveInMessage(UlongToHandle(wid),DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0)); - if (err == DS_OK) { - TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n", - debugstr_guid(&DSOUND_capture_guids[wid]),desc.szDesc,desc.szDrvname,lpContext); - if (lpDSEnumCallback(&DSOUND_capture_guids[wid], desc.szDesc, desc.szDrvname, lpContext) == FALSE) - return DS_OK; - } - } - - return DS_OK; -} - -/*************************************************************************** - * DirectSoundCaptureEnumerateW [DSOUND.8] - * - * Enumerate all DirectSound drivers installed in the system. - * - * PARAMS - * lpDSEnumCallback [I] Address of callback function. - * lpContext [I] Address of user defined context passed to callback function. - * - * RETURNS - * Success: DS_OK - * Failure: DSERR_INVALIDPARAM - */ -HRESULT WINAPI -DirectSoundCaptureEnumerateW( - LPDSENUMCALLBACKW lpDSEnumCallback, - LPVOID lpContext) -{ - unsigned devs, wid; - DSDRIVERDESC desc; - GUID guid; - int err; - WCHAR wDesc[MAXPNAMELEN]; - WCHAR wName[MAXPNAMELEN]; - - TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext ); - - if (lpDSEnumCallback == NULL) { - WARN("invalid parameter: lpDSEnumCallback == NULL\n"); - return DSERR_INVALIDPARAM; - } - - devs = waveInGetNumDevs(); - if (devs > 0) { - if (GetDeviceID(&DSDEVID_DefaultCapture, &guid) == DS_OK) { - for (wid = 0; wid < devs; ++wid) { - if (IsEqualGUID( &guid, &DSOUND_capture_guids[wid] ) ) { - err = mmErr(waveInMessage(UlongToHandle(wid),DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0)); - if (err == DS_OK) { - TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n", - "Primary Sound Capture Driver",desc.szDrvname,lpContext); - MultiByteToWideChar( CP_ACP, 0, "Primary Sound Capture Driver", -1, - wDesc, sizeof(wDesc)/sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, - wName, sizeof(wName)/sizeof(WCHAR) ); - if (lpDSEnumCallback(NULL, wDesc, wName, lpContext) == FALSE) - return DS_OK; - } - } - } - } - } - - for (wid = 0; wid < devs; ++wid) { - err = mmErr(waveInMessage(UlongToHandle(wid),DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0)); - if (err == DS_OK) { - TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n", - debugstr_guid(&DSOUND_capture_guids[wid]),desc.szDesc,desc.szDrvname,lpContext); - MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, - wDesc, sizeof(wDesc)/sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, - wName, sizeof(wName)/sizeof(WCHAR) ); - if (lpDSEnumCallback(&DSOUND_capture_guids[wid], wDesc, wName, lpContext) == FALSE) - return DS_OK; - } - } - - return DS_OK; -} - static void capture_CheckNotify(IDirectSoundCaptureBufferImpl *This, DWORD from, DWORD len) { int i; diff --git a/dlls/dsound/dsound_main.c b/dlls/dsound/dsound_main.c index 44897bc9946..bfb870857df 100644 --- a/dlls/dsound/dsound_main.c +++ b/dlls/dsound/dsound_main.c @@ -272,6 +272,22 @@ HRESULT WINAPI GetDeviceID(LPCGUID pGuidSrc, LPGUID pGuidDest) return DS_OK; } +struct morecontext +{ + LPDSENUMCALLBACKA callA; + LPVOID data; +}; + +static BOOL CALLBACK a_to_w_callback(LPGUID guid, LPCWSTR descW, LPCWSTR modW, LPVOID data) +{ + struct morecontext *context = data; + char descA[MAXPNAMELEN], modA[MAXPNAMELEN]; + + WideCharToMultiByte(CP_ACP, 0, descW, -1, descA, sizeof(descA), NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, modW, -1, modA, sizeof(modA), NULL, NULL); + + return context->callA(guid, descA, modA, context->data); +} /*************************************************************************** * DirectSoundEnumerateA [DSOUND.2] @@ -290,10 +306,42 @@ HRESULT WINAPI DirectSoundEnumerateA( LPDSENUMCALLBACKA lpDSEnumCallback, LPVOID lpContext) { + struct morecontext context; + + if (lpDSEnumCallback == NULL) { + WARN("invalid parameter: lpDSEnumCallback == NULL\n"); + return DSERR_INVALIDPARAM; + } + + context.callA = lpDSEnumCallback; + context.data = lpContext; + + return DirectSoundEnumerateW(a_to_w_callback, &context); +} + +/*************************************************************************** + * DirectSoundEnumerateW [DSOUND.3] + * + * Enumerate all DirectSound drivers installed in the system + * + * PARAMS + * lpDSEnumCallback [I] Address of callback function. + * lpContext [I] Address of user defined context passed to callback function. + * + * RETURNS + * Success: DS_OK + * Failure: DSERR_INVALIDPARAM + */ +HRESULT WINAPI DirectSoundEnumerateW( + LPDSENUMCALLBACKW lpDSEnumCallback, + LPVOID lpContext ) +{ unsigned devs, wod; DSDRIVERDESC desc; GUID guid; int err; + WCHAR wDesc[MAXPNAMELEN]; + WCHAR wName[MAXPNAMELEN]; TRACE("lpDSEnumCallback = %p, lpContext = %p\n", lpDSEnumCallback, lpContext); @@ -306,13 +354,16 @@ HRESULT WINAPI DirectSoundEnumerateA( devs = waveOutGetNumDevs(); if (devs > 0) { if (GetDeviceID(&DSDEVID_DefaultPlayback, &guid) == DS_OK) { + static const WCHAR empty[] = { 0 }; for (wod = 0; wod < devs; ++wod) { - if (IsEqualGUID( &guid, &DSOUND_renderer_guids[wod]) ) { + if (IsEqualGUID( &guid, &DSOUND_renderer_guids[wod] ) ) { err = mmErr(waveOutMessage(UlongToHandle(wod),DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0)); if (err == DS_OK) { TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n", - "Primary Sound Driver","",lpContext); - if (lpDSEnumCallback(NULL, "Primary Sound Driver", "", lpContext) == FALSE) + "Primary Sound Driver",desc.szDrvname,lpContext); + MultiByteToWideChar( CP_ACP, 0, "Primary Sound Driver", -1, + wDesc, sizeof(wDesc)/sizeof(WCHAR) ); + if (lpDSEnumCallback(NULL, wDesc, empty, lpContext) == FALSE) return DS_OK; } } @@ -325,7 +376,11 @@ HRESULT WINAPI DirectSoundEnumerateA( if (err == DS_OK) { TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n", debugstr_guid(&DSOUND_renderer_guids[wod]),desc.szDesc,desc.szDrvname,lpContext); - if (lpDSEnumCallback(&DSOUND_renderer_guids[wod], desc.szDesc, desc.szDrvname, lpContext) == FALSE) + MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, + wDesc, sizeof(wDesc)/sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, + wName, sizeof(wName)/sizeof(WCHAR) ); + if (lpDSEnumCallback(&DSOUND_renderer_guids[wod], wDesc, wName, lpContext) == FALSE) return DS_OK; } } @@ -333,9 +388,9 @@ HRESULT WINAPI DirectSoundEnumerateA( } /*************************************************************************** - * DirectSoundEnumerateW [DSOUND.3] + * DirectSoundCaptureEnumerateA [DSOUND.7] * - * Enumerate all DirectSound drivers installed in the system + * Enumerate all DirectSound drivers installed in the system. * * PARAMS * lpDSEnumCallback [I] Address of callback function. @@ -345,58 +400,90 @@ HRESULT WINAPI DirectSoundEnumerateA( * Success: DS_OK * Failure: DSERR_INVALIDPARAM */ -HRESULT WINAPI DirectSoundEnumerateW( - LPDSENUMCALLBACKW lpDSEnumCallback, - LPVOID lpContext ) +HRESULT WINAPI DirectSoundCaptureEnumerateA( + LPDSENUMCALLBACKA lpDSEnumCallback, + LPVOID lpContext) { - unsigned devs, wod; + struct morecontext context; + + if (lpDSEnumCallback == NULL) { + WARN("invalid parameter: lpDSEnumCallback == NULL\n"); + return DSERR_INVALIDPARAM; + } + + context.callA = lpDSEnumCallback; + context.data = lpContext; + + return DirectSoundCaptureEnumerateW(a_to_w_callback, &context); +} + +/*************************************************************************** + * DirectSoundCaptureEnumerateW [DSOUND.8] + * + * Enumerate all DirectSound drivers installed in the system. + * + * PARAMS + * lpDSEnumCallback [I] Address of callback function. + * lpContext [I] Address of user defined context passed to callback function. + * + * RETURNS + * Success: DS_OK + * Failure: DSERR_INVALIDPARAM + */ +HRESULT WINAPI +DirectSoundCaptureEnumerateW( + LPDSENUMCALLBACKW lpDSEnumCallback, + LPVOID lpContext) +{ + unsigned devs, wid; DSDRIVERDESC desc; GUID guid; int err; WCHAR wDesc[MAXPNAMELEN]; WCHAR wName[MAXPNAMELEN]; - TRACE("lpDSEnumCallback = %p, lpContext = %p\n", - lpDSEnumCallback, lpContext); + TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext ); if (lpDSEnumCallback == NULL) { WARN("invalid parameter: lpDSEnumCallback == NULL\n"); - return DSERR_INVALIDPARAM; + return DSERR_INVALIDPARAM; } - devs = waveOutGetNumDevs(); + devs = waveInGetNumDevs(); if (devs > 0) { - if (GetDeviceID(&DSDEVID_DefaultPlayback, &guid) == DS_OK) { - static const WCHAR empty[] = { 0 }; - for (wod = 0; wod < devs; ++wod) { - if (IsEqualGUID( &guid, &DSOUND_renderer_guids[wod] ) ) { - err = mmErr(waveOutMessage(UlongToHandle(wod),DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0)); + if (GetDeviceID(&DSDEVID_DefaultCapture, &guid) == DS_OK) { + for (wid = 0; wid < devs; ++wid) { + if (IsEqualGUID( &guid, &DSOUND_capture_guids[wid] ) ) { + err = mmErr(waveInMessage(UlongToHandle(wid),DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0)); if (err == DS_OK) { TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n", - "Primary Sound Driver",desc.szDrvname,lpContext); - MultiByteToWideChar( CP_ACP, 0, "Primary Sound Driver", -1, + "Primary Sound Capture Driver",desc.szDrvname,lpContext); + MultiByteToWideChar( CP_ACP, 0, "Primary Sound Capture Driver", -1, wDesc, sizeof(wDesc)/sizeof(WCHAR) ); - if (lpDSEnumCallback(NULL, wDesc, empty, lpContext) == FALSE) + MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, + wName, sizeof(wName)/sizeof(WCHAR) ); + if (lpDSEnumCallback(NULL, wDesc, wName, lpContext) == FALSE) return DS_OK; - } - } + } + } } } } - for (wod = 0; wod < devs; ++wod) { - err = mmErr(waveOutMessage(UlongToHandle(wod),DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0)); + for (wid = 0; wid < devs; ++wid) { + err = mmErr(waveInMessage(UlongToHandle(wid),DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0)); if (err == DS_OK) { TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n", - debugstr_guid(&DSOUND_renderer_guids[wod]),desc.szDesc,desc.szDrvname,lpContext); + debugstr_guid(&DSOUND_capture_guids[wid]),desc.szDesc,desc.szDrvname,lpContext); MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, wDesc, sizeof(wDesc)/sizeof(WCHAR) ); MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, wName, sizeof(wName)/sizeof(WCHAR) ); - if (lpDSEnumCallback(&DSOUND_renderer_guids[wod], wDesc, wName, lpContext) == FALSE) + if (lpDSEnumCallback(&DSOUND_capture_guids[wid], wDesc, wName, lpContext) == FALSE) return DS_OK; } } + return DS_OK; } diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h index e0283589b86..e1567e54e8d 100644 --- a/dlls/dsound/dsound_private.h +++ b/dlls/dsound/dsound_private.h @@ -52,11 +52,6 @@ typedef struct IDirectSound8_IDirectSound8 IDirectSound8_IDirectSound8; typedef struct IDirectSoundBufferImpl IDirectSoundBufferImpl; typedef struct IDirectSoundCaptureImpl IDirectSoundCaptureImpl; typedef struct IDirectSoundCaptureBufferImpl IDirectSoundCaptureBufferImpl; -typedef struct IDirectSoundFullDuplexImpl IDirectSoundFullDuplexImpl; -typedef struct IDirectSoundFullDuplex_IUnknown IDirectSoundFullDuplex_IUnknown; -typedef struct IDirectSoundFullDuplex_IDirectSound IDirectSoundFullDuplex_IDirectSound; -typedef struct IDirectSoundFullDuplex_IDirectSound8 IDirectSoundFullDuplex_IDirectSound8; -typedef struct IDirectSoundFullDuplex_IDirectSoundCapture IDirectSoundFullDuplex_IDirectSoundCapture; typedef struct IDirectSoundNotifyImpl IDirectSoundNotifyImpl; typedef struct IDirectSoundCaptureNotifyImpl IDirectSoundCaptureNotifyImpl; typedef struct IDirectSound3DListenerImpl IDirectSound3DListenerImpl; @@ -310,52 +305,6 @@ HRESULT IDirectSoundCaptureBufferImpl_Create( LPCDSCBUFFERDESC lpcDSCBufferDesc); /***************************************************************************** - * IDirectSoundFullDuplex implementation structure - */ -struct IDirectSoundFullDuplexImpl -{ - /* IUnknown fields */ - const IDirectSoundFullDuplexVtbl *lpVtbl; - LONG ref; - - /* IDirectSoundFullDuplexImpl fields */ - DirectSoundDevice *renderer_device; - DirectSoundCaptureDevice *capture_device; - - LPUNKNOWN pUnknown; - LPDIRECTSOUND pDS; - LPDIRECTSOUND8 pDS8; - LPDIRECTSOUNDCAPTURE pDSC; -}; - -/***************************************************************************** - * IDirectSoundFullDuplex COM components - */ -struct IDirectSoundFullDuplex_IUnknown { - const IUnknownVtbl *lpVtbl; - LONG ref; - IDirectSoundFullDuplexImpl *pdsfd; -}; - -struct IDirectSoundFullDuplex_IDirectSound { - const IDirectSoundVtbl *lpVtbl; - LONG ref; - IDirectSoundFullDuplexImpl *pdsfd; -}; - -struct IDirectSoundFullDuplex_IDirectSound8 { - const IDirectSound8Vtbl *lpVtbl; - LONG ref; - IDirectSoundFullDuplexImpl *pdsfd; -}; - -struct IDirectSoundFullDuplex_IDirectSoundCapture { - const IDirectSoundCaptureVtbl *lpVtbl; - LONG ref; - IDirectSoundFullDuplexImpl *pdsfd; -}; - -/***************************************************************************** * IDirectSound3DListener implementation structure */ struct IDirectSound3DListenerImpl diff --git a/dlls/dsound/duplex.c b/dlls/dsound/duplex.c index 1fe6bbc67da..8fbf1d622c0 100644 --- a/dlls/dsound/duplex.c +++ b/dlls/dsound/duplex.c @@ -37,6 +37,49 @@ WINE_DEFAULT_DEBUG_CHANNEL(dsound); +/***************************************************************************** + * IDirectSoundFullDuplex implementation structure + */ +typedef struct IDirectSoundFullDuplexImpl +{ + /* IUnknown fields */ + const IDirectSoundFullDuplexVtbl *lpVtbl; + LONG ref; + + /* IDirectSoundFullDuplexImpl fields */ + DirectSoundDevice *renderer_device; + DirectSoundCaptureDevice *capture_device; + + LPUNKNOWN pUnknown; + LPDIRECTSOUND pDS; + LPDIRECTSOUND8 pDS8; + LPDIRECTSOUNDCAPTURE pDSC; +} IDirectSoundFullDuplexImpl; + +typedef struct IDirectSoundFullDuplex_IUnknown { + const IUnknownVtbl *lpVtbl; + LONG ref; + IDirectSoundFullDuplexImpl *pdsfd; +} IDirectSoundFullDuplex_IUnknown; + +typedef struct IDirectSoundFullDuplex_IDirectSound { + const IDirectSoundVtbl *lpVtbl; + LONG ref; + IDirectSoundFullDuplexImpl *pdsfd; +} IDirectSoundFullDuplex_IDirectSound; + +typedef struct IDirectSoundFullDuplex_IDirectSound8 { + const IDirectSound8Vtbl *lpVtbl; + LONG ref; + IDirectSoundFullDuplexImpl *pdsfd; +} IDirectSoundFullDuplex_IDirectSound8; + +typedef struct IDirectSoundFullDuplex_IDirectSoundCapture { + const IDirectSoundCaptureVtbl *lpVtbl; + LONG ref; + IDirectSoundFullDuplexImpl *pdsfd; +} IDirectSoundFullDuplex_IDirectSoundCapture; + /******************************************************************************* * IUnknown */ diff --git a/dlls/dsound/tests/dsound.c b/dlls/dsound/tests/dsound.c index 114dbb6ced2..f059c20e62f 100644 --- a/dlls/dsound/tests/dsound.c +++ b/dlls/dsound/tests/dsound.c @@ -55,7 +55,7 @@ static void IDirectSound_test(LPDIRECTSOUND dso, BOOL initialized, IUnknown * unknown; IDirectSound * ds; IDirectSound8 * ds8; - DWORD speaker_config, new_speaker_config; + DWORD speaker_config, new_speaker_config, ref_speaker_config; /* Try to Query for objects */ rc=IDirectSound_QueryInterface(dso,&IID_IUnknown,(LPVOID*)&unknown); @@ -144,11 +144,17 @@ static void IDirectSound_test(LPDIRECTSOUND dso, BOOL initialized, rc=IDirectSound_GetSpeakerConfig(dso,&speaker_config); ok(rc==DS_OK,"IDirectSound_GetSpeakerConfig() failed: %08x\n", rc); + ref_speaker_config = speaker_config; speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, DSSPEAKER_GEOMETRY_WIDE); - rc=IDirectSound_SetSpeakerConfig(dso,speaker_config); - ok(rc==DS_OK,"IDirectSound_SetSpeakerConfig() failed: %08x\n", rc); + if (speaker_config == ref_speaker_config) + speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, + DSSPEAKER_GEOMETRY_NARROW); + if(rc==DS_OK) { + rc=IDirectSound_SetSpeakerConfig(dso,speaker_config); + ok(rc==DS_OK,"IDirectSound_SetSpeakerConfig() failed: %08x\n", rc); + } if (rc==DS_OK) { rc=IDirectSound_GetSpeakerConfig(dso,&new_speaker_config); ok(rc==DS_OK,"IDirectSound_GetSpeakerConfig() failed: %08x\n", rc); @@ -156,6 +162,7 @@ static void IDirectSound_test(LPDIRECTSOUND dso, BOOL initialized, trace("IDirectSound_GetSpeakerConfig() failed to set speaker " "config: expected 0x%08x, got 0x%08x\n", speaker_config,new_speaker_config); + IDirectSound_SetSpeakerConfig(dso,ref_speaker_config); } EXIT: diff --git a/dlls/dsound/tests/dsound8.c b/dlls/dsound/tests/dsound8.c index a2b16d85bbb..5eb7c059d35 100644 --- a/dlls/dsound/tests/dsound8.c +++ b/dlls/dsound/tests/dsound8.c @@ -54,7 +54,7 @@ static void IDirectSound8_test(LPDIRECTSOUND8 dso, BOOL initialized, IUnknown * unknown; IDirectSound * ds; IDirectSound8 * ds8; - DWORD speaker_config, new_speaker_config; + DWORD speaker_config, new_speaker_config, ref_speaker_config; DWORD certified; /* Try to Query for objects */ @@ -148,11 +148,17 @@ static void IDirectSound8_test(LPDIRECTSOUND8 dso, BOOL initialized, rc=IDirectSound8_GetSpeakerConfig(dso,&speaker_config); ok(rc==DS_OK,"IDirectSound8_GetSpeakerConfig() failed: %08x\n", rc); + ref_speaker_config = speaker_config; speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, DSSPEAKER_GEOMETRY_WIDE); - rc=IDirectSound8_SetSpeakerConfig(dso,speaker_config); - ok(rc==DS_OK,"IDirectSound8_SetSpeakerConfig() failed: %08x\n", rc); + if (speaker_config == ref_speaker_config) + speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, + DSSPEAKER_GEOMETRY_NARROW); + if(rc==DS_OK) { + rc=IDirectSound8_SetSpeakerConfig(dso,speaker_config); + ok(rc==DS_OK,"IDirectSound8_SetSpeakerConfig() failed: %08x\n", rc); + } if (rc==DS_OK) { rc=IDirectSound8_GetSpeakerConfig(dso,&new_speaker_config); ok(rc==DS_OK,"IDirectSound8_GetSpeakerConfig() failed: %08x\n", rc); @@ -160,6 +166,7 @@ static void IDirectSound8_test(LPDIRECTSOUND8 dso, BOOL initialized, trace("IDirectSound8_GetSpeakerConfig() failed to set speaker " "config: expected 0x%08x, got 0x%08x\n", speaker_config,new_speaker_config); + IDirectSound8_SetSpeakerConfig(dso,ref_speaker_config); } rc=IDirectSound8_VerifyCertification(dso, &certified); diff --git a/dlls/dxgi/device.c b/dlls/dxgi/device.c index bf079d5daaf..9741d0eba25 100644 --- a/dlls/dxgi/device.c +++ b/dlls/dxgi/device.c @@ -312,7 +312,7 @@ static HRESULT STDMETHODCALLTYPE dxgi_device_create_swapchain(IWineDXGIDevice *i return S_OK; } -const struct IWineDXGIDeviceVtbl dxgi_device_vtbl = +static const struct IWineDXGIDeviceVtbl dxgi_device_vtbl = { /* IUnknown methods */ dxgi_device_QueryInterface, @@ -334,3 +334,80 @@ const struct IWineDXGIDeviceVtbl dxgi_device_vtbl = dxgi_device_create_surface, dxgi_device_create_swapchain, }; + +HRESULT dxgi_device_init(struct dxgi_device *device, struct dxgi_device_layer *layer, + IDXGIFactory *factory, IDXGIAdapter *adapter) +{ + IWineD3DDeviceParent *wined3d_device_parent; + IWineDXGIAdapter *wine_adapter; + UINT adapter_ordinal; + IWineD3D *wined3d; + void *layer_base; + HRESULT hr; + + device->vtbl = &dxgi_device_vtbl; + device->refcount = 1; + + layer_base = device + 1; + + hr = layer->create(layer->id, &layer_base, 0, + device, &IID_IUnknown, (void **)&device->child_layer); + if (FAILED(hr)) + { + WARN("Failed to create device, returning %#x.\n", hr); + goto fail; + } + + hr = IDXGIFactory_QueryInterface(factory, &IID_IWineDXGIFactory, (void **)&device->factory); + if (FAILED(hr)) + { + WARN("This is not the factory we're looking for, returning %#x.\n", hr); + goto fail; + } + wined3d = IWineDXGIFactory_get_wined3d(device->factory); + + hr = IDXGIAdapter_QueryInterface(adapter, &IID_IWineDXGIAdapter, (void **)&wine_adapter); + if (FAILED(hr)) + { + WARN("This is not the adapter we're looking for, returning %#x.\n", hr); + EnterCriticalSection(&dxgi_cs); + IWineD3D_Release(wined3d); + LeaveCriticalSection(&dxgi_cs); + goto fail; + } + adapter_ordinal = IWineDXGIAdapter_get_ordinal(wine_adapter); + IWineDXGIAdapter_Release(wine_adapter); + + hr = IUnknown_QueryInterface((IUnknown *)device, &IID_IWineD3DDeviceParent, (void **)&wined3d_device_parent); + if (FAILED(hr)) + { + ERR("DXGI device should implement IWineD3DDeviceParent.\n"); + goto fail; + } + + FIXME("Ignoring adapter type.\n"); + EnterCriticalSection(&dxgi_cs); + hr = IWineD3D_CreateDevice(wined3d, adapter_ordinal, WINED3DDEVTYPE_HAL, NULL, 0, + (IUnknown *)device, wined3d_device_parent, &device->wined3d_device); + IWineD3DDeviceParent_Release(wined3d_device_parent); + IWineD3D_Release(wined3d); + LeaveCriticalSection(&dxgi_cs); + if (FAILED(hr)) + { + WARN("Failed to create a wined3d device, returning %#x.\n", hr); + goto fail; + } + + return S_OK; + +fail: + if (device->wined3d_device) + { + EnterCriticalSection(&dxgi_cs); + IWineD3DDevice_Release(device->wined3d_device); + LeaveCriticalSection(&dxgi_cs); + } + if (device->factory) IWineDXGIFactory_Release(device->factory); + if (device->child_layer) IUnknown_Release(device->child_layer); + return hr; +} diff --git a/dlls/dxgi/dxgi_main.c b/dlls/dxgi/dxgi_main.c index fcc6c07b240..3b153ab79be 100644 --- a/dlls/dxgi/dxgi_main.c +++ b/dlls/dxgi/dxgi_main.c @@ -226,14 +226,9 @@ static HRESULT register_d3d10core_layers(HMODULE d3d10core) HRESULT WINAPI DXGID3D10CreateDevice(HMODULE d3d10core, IDXGIFactory *factory, IDXGIAdapter *adapter, UINT flags, DWORD unknown0, void **device) { - IWineD3DDeviceParent *wined3d_device_parent; struct layer_get_size_args get_size_args; struct dxgi_device *dxgi_device; struct dxgi_device_layer d3d10_layer; - IWineDXGIAdapter *wine_adapter; - UINT adapter_ordinal; - IWineD3D *wined3d; - void *layer_base; UINT device_size; DWORD count; HRESULT hr; @@ -282,75 +277,19 @@ HRESULT WINAPI DXGID3D10CreateDevice(HMODULE d3d10core, IDXGIFactory *factory, I return E_OUTOFMEMORY; } - dxgi_device->vtbl = &dxgi_device_vtbl; - dxgi_device->refcount = 1; - - layer_base = dxgi_device + 1; - - hr = d3d10_layer.create(d3d10_layer.id, &layer_base, 0, - dxgi_device, &IID_IUnknown, (void **)&dxgi_device->child_layer); - if (FAILED(hr)) - { - WARN("Failed to create device, returning %#x\n", hr); - goto fail; - } - - hr = IDXGIFactory_QueryInterface(factory, &IID_IWineDXGIFactory, (void **)&dxgi_device->factory); - if (FAILED(hr)) - { - WARN("This is not the factory we're looking for, returning %#x\n", hr); - goto fail; - } - wined3d = IWineDXGIFactory_get_wined3d(dxgi_device->factory); - - hr = IDXGIAdapter_QueryInterface(adapter, &IID_IWineDXGIAdapter, (void **)&wine_adapter); - if (FAILED(hr)) - { - WARN("This is not the adapter we're looking for, returning %#x\n", hr); - EnterCriticalSection(&dxgi_cs); - IWineD3D_Release(wined3d); - LeaveCriticalSection(&dxgi_cs); - goto fail; - } - adapter_ordinal = IWineDXGIAdapter_get_ordinal(wine_adapter); - IWineDXGIAdapter_Release(wine_adapter); - - hr = IUnknown_QueryInterface((IUnknown *)dxgi_device, &IID_IWineD3DDeviceParent, (void **)&wined3d_device_parent); + hr = dxgi_device_init(dxgi_device, &d3d10_layer, factory, adapter); if (FAILED(hr)) { - ERR("DXGI device should implement IWineD3DDeviceParent\n"); - goto fail; - } - - FIXME("Ignoring adapter type\n"); - EnterCriticalSection(&dxgi_cs); - hr = IWineD3D_CreateDevice(wined3d, adapter_ordinal, WINED3DDEVTYPE_HAL, NULL, 0, - (IUnknown *)dxgi_device, wined3d_device_parent, &dxgi_device->wined3d_device); - IWineD3DDeviceParent_Release(wined3d_device_parent); - IWineD3D_Release(wined3d); - LeaveCriticalSection(&dxgi_cs); - if (FAILED(hr)) - { - WARN("Failed to create a WineD3D device, returning %#x\n", hr); - goto fail; + WARN("Failed to initialize device, hr %#x.\n", hr); + HeapFree(GetProcessHeap(), 0, dxgi_device); + *device = NULL; + return hr; } + TRACE("Created device %p.\n", dxgi_device); *device = dxgi_device; - return hr; - -fail: - if (dxgi_device->wined3d_device) - { - EnterCriticalSection(&dxgi_cs); - IWineD3DDevice_Release(dxgi_device->wined3d_device); - LeaveCriticalSection(&dxgi_cs); - } - if (dxgi_device->factory) IWineDXGIFactory_Release(dxgi_device->factory); - if (dxgi_device->child_layer) IUnknown_Release(dxgi_device->child_layer); - HeapFree(GetProcessHeap(), 0, dxgi_device); - *device = NULL; - return hr; + return S_OK; } HRESULT WINAPI DXGID3D10RegisterLayers(const struct dxgi_device_layer *layers, UINT layer_count) diff --git a/dlls/dxgi/dxgi_private.h b/dlls/dxgi/dxgi_private.h index 0e4593d2bb2..46b6f43c9bc 100644 --- a/dlls/dxgi/dxgi_private.h +++ b/dlls/dxgi/dxgi_private.h @@ -36,6 +36,38 @@ extern CRITICAL_SECTION dxgi_cs DECLSPEC_HIDDEN; +/* Layered device */ +enum dxgi_device_layer_id +{ + DXGI_DEVICE_LAYER_DEBUG1 = 0x8, + DXGI_DEVICE_LAYER_THREAD_SAFE = 0x10, + DXGI_DEVICE_LAYER_DEBUG2 = 0x20, + DXGI_DEVICE_LAYER_SWITCH_TO_REF = 0x30, + DXGI_DEVICE_LAYER_D3D10_DEVICE = 0xffffffff, +}; + +struct layer_get_size_args +{ + DWORD unknown0; + DWORD unknown1; + DWORD *unknown2; + DWORD *unknown3; + IDXGIAdapter *adapter; + WORD interface_major; + WORD interface_minor; + WORD version_build; + WORD version_revision; +}; + +struct dxgi_device_layer +{ + enum dxgi_device_layer_id id; + HRESULT (WINAPI *init)(enum dxgi_device_layer_id id, DWORD *count, DWORD *values); + UINT (WINAPI *get_size)(enum dxgi_device_layer_id id, struct layer_get_size_args *args, DWORD unknown0); + HRESULT (WINAPI *create)(enum dxgi_device_layer_id id, void **layer_base, DWORD unknown0, + void *device_object, REFIID riid, void **device_layer); +}; + /* TRACE helper functions */ const char *debug_dxgi_format(DXGI_FORMAT format) DECLSPEC_HIDDEN; @@ -53,7 +85,6 @@ struct dxgi_factory }; /* IDXGIDevice */ -extern const struct IWineDXGIDeviceVtbl dxgi_device_vtbl DECLSPEC_HIDDEN; struct dxgi_device { const struct IWineDXGIDeviceVtbl *vtbl; @@ -63,6 +94,9 @@ struct dxgi_device IWineDXGIFactory *factory; }; +HRESULT dxgi_device_init(struct dxgi_device *device, struct dxgi_device_layer *layer, + IDXGIFactory *factory, IDXGIAdapter *adapter) DECLSPEC_HIDDEN; + /* IDXGIOutput */ struct dxgi_output { @@ -104,36 +138,4 @@ struct dxgi_surface LONG refcount; }; -/* Layered device */ -enum dxgi_device_layer_id -{ - DXGI_DEVICE_LAYER_DEBUG1 = 0x8, - DXGI_DEVICE_LAYER_THREAD_SAFE = 0x10, - DXGI_DEVICE_LAYER_DEBUG2 = 0x20, - DXGI_DEVICE_LAYER_SWITCH_TO_REF = 0x30, - DXGI_DEVICE_LAYER_D3D10_DEVICE = 0xffffffff, -}; - -struct layer_get_size_args -{ - DWORD unknown0; - DWORD unknown1; - DWORD *unknown2; - DWORD *unknown3; - IDXGIAdapter *adapter; - WORD interface_major; - WORD interface_minor; - WORD version_build; - WORD version_revision; -}; - -struct dxgi_device_layer -{ - enum dxgi_device_layer_id id; - HRESULT (WINAPI *init)(enum dxgi_device_layer_id id, DWORD *count, DWORD *values); - UINT (WINAPI *get_size)(enum dxgi_device_layer_id id, struct layer_get_size_args *args, DWORD unknown0); - HRESULT (WINAPI *create)(enum dxgi_device_layer_id id, void **layer_base, DWORD unknown0, - void *device_object, REFIID riid, void **device_layer); -}; - #endif /* __WINE_DXGI_PRIVATE_H */ diff --git a/dlls/gdi32/brush.c b/dlls/gdi32/brush.c index 721da98a44d..02020332de8 100644 --- a/dlls/gdi32/brush.c +++ b/dlls/gdi32/brush.c @@ -447,24 +447,3 @@ static INT BRUSH_GetObject( HGDIOBJ handle, INT count, LPVOID buffer ) GDI_ReleaseObj( handle ); return count; } - -/*********************************************************************** - * BRUSH_SetSolid - */ -BOOL BRUSH_SetSolid( HGDIOBJ handle, COLORREF new_color ) -{ - BRUSHOBJ * brushPtr; - BOOL res = FALSE; - - if (!(brushPtr = GDI_GetObjPtr( handle, OBJ_BRUSH ))) - return FALSE; - - if (brushPtr->logbrush.lbStyle == BS_SOLID) - { - brushPtr->logbrush.lbColor = new_color; - res = TRUE; - } - - GDI_ReleaseObj( handle ); - return res; -} diff --git a/dlls/gdi32/dc.c b/dlls/gdi32/dc.c index f7b295ac594..c4c5a1325f8 100644 --- a/dlls/gdi32/dc.c +++ b/dlls/gdi32/dc.c @@ -144,7 +144,6 @@ DC *alloc_dc_ptr( const DC_FUNCTIONS *funcs, WORD magic ) dc->BoundsRect.top = 0; dc->BoundsRect.right = 0; dc->BoundsRect.bottom = 0; - dc->saved_visrgn = NULL; PATH_InitGdiPath(&dc->path); if (!(dc->hSelf = alloc_gdi_handle( &dc->header, magic, &dc_funcs ))) @@ -403,7 +402,6 @@ INT save_dc_state( HDC hdc ) newdc->pAbortProc = NULL; newdc->hookProc = NULL; - newdc->saved_visrgn = NULL; if (!(newdc->hSelf = alloc_gdi_handle( &newdc->header, dc->header.type, &dc_funcs ))) { @@ -845,14 +843,6 @@ BOOL WINAPI DeleteDC( HDC hdc ) dc->physDev = NULL; } - while (dc->saved_visrgn) - { - struct saved_visrgn *next = dc->saved_visrgn->next; - DeleteObject( dc->saved_visrgn->hrgn ); - HeapFree( GetProcessHeap(), 0, dc->saved_visrgn ); - dc->saved_visrgn = next; - } - free_dc_ptr( dc ); if (funcs) DRIVER_release_driver( funcs ); /* do that after releasing the GDI lock */ return TRUE; @@ -869,7 +859,17 @@ HDC WINAPI ResetDCW( HDC hdc, const DEVMODEW *devmode ) if ((dc = get_dc_ptr( hdc ))) { - if (dc->funcs->pResetDC) ret = dc->funcs->pResetDC( dc->physDev, devmode ); + if (dc->funcs->pResetDC) + { + ret = dc->funcs->pResetDC( dc->physDev, devmode ); + if (ret) /* reset the visible region */ + { + dc->dirty = 0; + SetRectRgn( dc->hVisRgn, 0, 0, GetDeviceCaps( hdc, DESKTOPHORZRES ), + GetDeviceCaps( hdc, DESKTOPVERTRES ) ); + CLIPPING_UpdateGCRegion( dc ); + } + } release_dc_ptr( dc ); } return ret; diff --git a/dlls/gdi32/driver.c b/dlls/gdi32/driver.c index ec5de204b08..41c59c74711 100644 --- a/dlls/gdi32/driver.c +++ b/dlls/gdi32/driver.c @@ -163,7 +163,6 @@ static struct graphics_driver *create_driver( HMODULE module ) GET_FUNC(SetBkColor); GET_FUNC(SetBkMode); GET_FUNC(SetDCBrushColor); - GET_FUNC(SetDCOrg); GET_FUNC(SetDCPenColor); GET_FUNC(SetDIBColorTable); GET_FUNC(SetDIBits); @@ -199,6 +198,7 @@ static struct graphics_driver *create_driver( HMODULE module ) /* OpenGL32 */ GET_FUNC(wglCreateContext); + GET_FUNC(wglCreateContextAttribsARB); GET_FUNC(wglDeleteContext); GET_FUNC(wglGetProcAddress); GET_FUNC(wglGetPbufferDCARB); diff --git a/dlls/gdi32/enhmfdrv/bitblt.c b/dlls/gdi32/enhmfdrv/bitblt.c index ddb9dd1ffd9..e5c80f6a189 100644 --- a/dlls/gdi32/enhmfdrv/bitblt.c +++ b/dlls/gdi32/enhmfdrv/bitblt.c @@ -79,10 +79,14 @@ static BOOL EMFDRV_BitBlockTransfer( UINT bitsSize; UINT size; BITMAP BM; - WORD nBPP; + WORD nBPP = 0; LPBITMAPINFOHEADER lpBmiH; + BOOL useSrc; EMFDRV_PDEVICE* physDevSrc = (EMFDRV_PDEVICE*)devSrc; - HBITMAP hBitmap = GetCurrentObject(physDevSrc->hdc, OBJ_BITMAP); + HBITMAP hBitmap = NULL; + + useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000)); + if (!physDevSrc && useSrc) return FALSE; if (emrType == EMR_BITBLT) emrSize = sizeof(EMRBITBLT); @@ -91,16 +95,25 @@ static BOOL EMFDRV_BitBlockTransfer( else return FALSE; - if(sizeof(BITMAP) != GetObjectW(hBitmap, sizeof(BITMAP), &BM)) - return FALSE; + if(useSrc) + { + hBitmap = GetCurrentObject(physDevSrc->hdc, OBJ_BITMAP); - nBPP = BM.bmPlanes * BM.bmBitsPixel; - if(nBPP > 8) nBPP = 24; /* FIXME Can't get 16bpp to work for some reason */ + if(sizeof(BITMAP) != GetObjectW(hBitmap, sizeof(BITMAP), &BM)) + return FALSE; - bitsSize = DIB_GetDIBWidthBytes(BM.bmWidth, nBPP) * BM.bmHeight; - bmiSize = sizeof(BITMAPINFOHEADER) + - (nBPP <= 8 ? 1 << nBPP : 0) * sizeof(RGBQUAD); - size = emrSize + bmiSize + bitsSize; + nBPP = BM.bmPlanes * BM.bmBitsPixel; + if(nBPP > 8) nBPP = 24; /* FIXME Can't get 16bpp to work for some reason */ + bitsSize = DIB_GetDIBWidthBytes(BM.bmWidth, nBPP) * BM.bmHeight; + bmiSize = sizeof(BITMAPINFOHEADER) + + (nBPP <= 8 ? 1 << nBPP : 0) * sizeof(RGBQUAD); + } + else + { + bitsSize = bmiSize = 0; + } + + size = emrSize + bmiSize + bitsSize; pEMR = HeapAlloc(GetProcessHeap(), 0, size); if (!pEMR) return FALSE; @@ -119,17 +132,28 @@ static BOOL EMFDRV_BitBlockTransfer( pEMR->dwRop = rop; pEMR->xSrc = xSrc; pEMR->ySrc = ySrc; - pEMR->xformSrc.eM11 = 1.0; /** FIXME: */ - pEMR->xformSrc.eM12 = 0.0; /** Setting default */ - pEMR->xformSrc.eM21 = 0.0; /** value. */ - pEMR->xformSrc.eM22 = 1.0; /** Where should we */ - pEMR->xformSrc.eDx = 0.0; /** get that info */ - pEMR->xformSrc.eDy = 0.0; /** ???? */ - pEMR->crBkColorSrc = GetBkColor(physDevSrc->hdc); - pEMR->iUsageSrc = DIB_RGB_COLORS; - pEMR->offBmiSrc = emrSize; + if (useSrc) + { + GetWorldTransform(physDevSrc->hdc, &pEMR->xformSrc); + pEMR->crBkColorSrc = GetBkColor(physDevSrc->hdc); + pEMR->iUsageSrc = DIB_RGB_COLORS; + pEMR->offBmiSrc = emrSize; + pEMR->offBitsSrc = emrSize + bmiSize; + } + else + { + pEMR->xformSrc.eM11 = 1.0; /** FIXME: */ + pEMR->xformSrc.eM12 = 0.0; /** Setting default */ + pEMR->xformSrc.eM21 = 0.0; /** value. */ + pEMR->xformSrc.eM22 = 1.0; /** Where should we */ + pEMR->xformSrc.eDx = 0.0; /** get that info */ + pEMR->xformSrc.eDy = 0.0; /** ???? */ + pEMR->crBkColorSrc = 0; + pEMR->iUsageSrc = 0; + pEMR->offBmiSrc = 0; + pEMR->offBitsSrc = 0; + } pEMR->cbBmiSrc = bmiSize; - pEMR->offBitsSrc = emrSize + bmiSize; pEMR->cbBitsSrc = bitsSize; if (emrType == EMR_STRETCHBLT) { @@ -138,36 +162,42 @@ static BOOL EMFDRV_BitBlockTransfer( pEMRStretch->cySrc = heightSrc; } - /* Initialize BITMAPINFO structure */ - lpBmiH = (LPBITMAPINFOHEADER)((BYTE*)pEMR + pEMR->offBmiSrc); - - lpBmiH->biSize = sizeof(BITMAPINFOHEADER); - lpBmiH->biWidth = BM.bmWidth; - lpBmiH->biHeight = BM.bmHeight; - lpBmiH->biPlanes = BM.bmPlanes; - lpBmiH->biBitCount = nBPP; - /* Assume the bitmap isn't compressed and set the BI_RGB flag. */ - lpBmiH->biCompression = BI_RGB; - lpBmiH->biSizeImage = bitsSize; - lpBmiH->biYPelsPerMeter = /* 1 meter = 39.37 inch */ - MulDiv(GetDeviceCaps(physDevSrc->hdc,LOGPIXELSX),3937,100); - lpBmiH->biXPelsPerMeter = - MulDiv(GetDeviceCaps(physDevSrc->hdc,LOGPIXELSY),3937,100); - lpBmiH->biClrUsed = nBPP <= 8 ? 1 << nBPP : 0; - /* Set biClrImportant to 0, indicating that all of the - device colors are important. */ - lpBmiH->biClrImportant = 0; - - /* Initialize bitmap bits */ - if (GetDIBits(physDevSrc->hdc, hBitmap, 0, (UINT)lpBmiH->biHeight, - (BYTE*)pEMR + pEMR->offBitsSrc, - (LPBITMAPINFO)lpBmiH, DIB_RGB_COLORS)) + if (useSrc) + { + /* Initialize BITMAPINFO structure */ + lpBmiH = (LPBITMAPINFOHEADER)((BYTE*)pEMR + pEMR->offBmiSrc); + + lpBmiH->biSize = sizeof(BITMAPINFOHEADER); + lpBmiH->biWidth = BM.bmWidth; + lpBmiH->biHeight = BM.bmHeight; + lpBmiH->biPlanes = BM.bmPlanes; + lpBmiH->biBitCount = nBPP; + /* Assume the bitmap isn't compressed and set the BI_RGB flag. */ + lpBmiH->biCompression = BI_RGB; + lpBmiH->biSizeImage = bitsSize; + lpBmiH->biYPelsPerMeter = 0; + lpBmiH->biXPelsPerMeter = 0; + lpBmiH->biClrUsed = nBPP <= 8 ? 1 << nBPP : 0; + /* Set biClrImportant to 0, indicating that all of the + device colors are important. */ + lpBmiH->biClrImportant = 0; + + /* Initialize bitmap bits */ + if (GetDIBits(physDevSrc->hdc, hBitmap, 0, (UINT)lpBmiH->biHeight, + (BYTE*)pEMR + pEMR->offBitsSrc, + (LPBITMAPINFO)lpBmiH, DIB_RGB_COLORS)) + { + ret = EMFDRV_WriteRecord(devDst, (EMR*)pEMR); + if (ret) EMFDRV_UpdateBBox(devDst, &(pEMR->rclBounds)); + } + else + ret = FALSE; + } + else { ret = EMFDRV_WriteRecord(devDst, (EMR*)pEMR); if (ret) EMFDRV_UpdateBBox(devDst, &(pEMR->rclBounds)); - } - else - ret = FALSE; + } HeapFree( GetProcessHeap(), 0, pEMR); return ret; diff --git a/dlls/gdi32/enhmfdrv/init.c b/dlls/gdi32/enhmfdrv/init.c index dd0b89e4980..bc53493a719 100644 --- a/dlls/gdi32/enhmfdrv/init.c +++ b/dlls/gdi32/enhmfdrv/init.c @@ -121,7 +121,6 @@ static const DC_FUNCTIONS EMFDRV_Funcs = EMFDRV_SetBkColor, /* pSetBkColor */ EMFDRV_SetBkMode, /* pSetBkMode */ NULL, /* pSetDCBrushColor */ - NULL, /* pSetDCOrg */ NULL, /* pSetDCPenColor */ NULL, /* pSetDIBColorTable */ NULL, /* pSetDIBits */ diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c index ed64166d176..7f8f6f6d0c0 100644 --- a/dlls/gdi32/font.c +++ b/dlls/gdi32/font.c @@ -306,10 +306,6 @@ HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA ) */ HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf ) { - static const WCHAR ItalicW[] = {' ','I','t','a','l','i','c','\0'}; - static const WCHAR BoldW[] = {' ','B','o','l','d','\0'}; - WCHAR *pFaceNameItalicSuffix, *pFaceNameBoldSuffix; - WCHAR *pFaceNameSuffix = NULL; HFONT hFont; FONTOBJ *fontPtr; @@ -328,24 +324,6 @@ HFONT WINAPI CreateFontIndirectW( const LOGFONTW *plf ) plf->lfOrientation/10., plf->lfEscapement/10., fontPtr); } - pFaceNameItalicSuffix = strstrW(fontPtr->logfont.lfFaceName, ItalicW); - if (pFaceNameItalicSuffix) - { - fontPtr->logfont.lfItalic = TRUE; - pFaceNameSuffix = pFaceNameItalicSuffix; - } - - pFaceNameBoldSuffix = strstrW(fontPtr->logfont.lfFaceName, BoldW); - if (pFaceNameBoldSuffix) - { - if (fontPtr->logfont.lfWeight < FW_BOLD) - fontPtr->logfont.lfWeight = FW_BOLD; - if (!pFaceNameSuffix || (pFaceNameBoldSuffix < pFaceNameSuffix)) - pFaceNameSuffix = pFaceNameBoldSuffix; - } - - if (pFaceNameSuffix) *pFaceNameSuffix = 0; - if (!(hFont = alloc_gdi_handle( &fontPtr->header, OBJ_FONT, &font_funcs ))) { HeapFree( GetProcessHeap(), 0, fontPtr ); diff --git a/dlls/gdi32/gdi16.c b/dlls/gdi32/gdi16.c index ee829e1340e..e62b711111c 100644 --- a/dlls/gdi32/gdi16.c +++ b/dlls/gdi32/gdi16.c @@ -25,7 +25,6 @@ #include "wingdi.h" #include "wownt32.h" #include "wine/wingdi16.h" -#include "gdi_private.h" #include "wine/list.h" #include "wine/debug.h" @@ -34,6 +33,160 @@ WINE_DEFAULT_DEBUG_CHANNEL(gdi); #define HGDIOBJ_32(handle16) ((HGDIOBJ)(ULONG_PTR)(handle16)) #define HGDIOBJ_16(handle32) ((HGDIOBJ16)(ULONG_PTR)(handle32)) +struct saved_visrgn +{ + struct list entry; + HDC hdc; + HRGN hrgn; +}; + +static struct list saved_regions = LIST_INIT( saved_regions ); + +static HPALETTE16 hPrimaryPalette; + +/* + * ############################################################################ + */ + +#include +#define GDI_MAX_THUNKS 32 + +static struct gdi_thunk +{ + BYTE popl_eax; /* popl %eax (return address) */ + BYTE pushl_pfn16; /* pushl pfn16 */ + DWORD pfn16; /* pfn16 */ + BYTE pushl_eax; /* pushl %eax */ + BYTE jmp; /* ljmp GDI_Callback3216 */ + DWORD callback; + HDC16 hdc; +} *GDI_Thunks; + +#include + +/********************************************************************** + * GDI_Callback3216 + */ +static BOOL CALLBACK GDI_Callback3216( DWORD pfn16, HDC hdc, INT code ) +{ + if (pfn16) + { + WORD args[2]; + DWORD ret; + + args[1] = HDC_16(hdc); + args[0] = code; + WOWCallback16Ex( pfn16, WCB16_PASCAL, sizeof(args), args, &ret ); + return LOWORD(ret); + } + return TRUE; +} + + +/****************************************************************** + * GDI_AddThunk + * + */ +static struct gdi_thunk* GDI_AddThunk(HDC16 dc16, ABORTPROC16 pfn16) +{ + struct gdi_thunk* thunk; + + if (!GDI_Thunks) + { + GDI_Thunks = VirtualAlloc(NULL, GDI_MAX_THUNKS * sizeof(*GDI_Thunks), + MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if (!GDI_Thunks) + { + return NULL; + } + for (thunk = GDI_Thunks; thunk < &GDI_Thunks[GDI_MAX_THUNKS]; thunk++) + { + thunk->popl_eax = 0x58; /* popl %eax */ + thunk->pushl_pfn16 = 0x68; /* pushl pfn16 */ + thunk->pfn16 = 0; + thunk->pushl_eax = 0x50; /* pushl %eax */ + thunk->jmp = 0xe9; /* jmp GDI_Callback3216 */ + thunk->callback = (char *)GDI_Callback3216 - (char *)(&thunk->callback + 1); + } + } + for (thunk = GDI_Thunks; thunk < &GDI_Thunks[GDI_MAX_THUNKS]; thunk++) + { + if (thunk->pfn16 == 0) + { + thunk->pfn16 = (DWORD)pfn16; + thunk->hdc = dc16; + return thunk; + } + } + FIXME("Out of mmdrv-thunks. Bump GDI_MAX_THUNKS\n"); + return NULL; +} + +/****************************************************************** + * GDI_DeleteThunk + */ +static void GDI_DeleteThunk(struct gdi_thunk* thunk) +{ + thunk->pfn16 = 0; +} + +/****************************************************************** + * GDI_FindThunk + */ +static struct gdi_thunk* GDI_FindThunk(HDC16 hdc) +{ + struct gdi_thunk* thunk; + + if (!GDI_Thunks) return NULL; + for (thunk = GDI_Thunks; thunk < &GDI_Thunks[GDI_MAX_THUNKS]; thunk++) + { + if (thunk->hdc == hdc) return thunk; + } + return NULL; +} + +/********************************************************************** + * QueryAbort (GDI.155) + * + * Calls the app's AbortProc function if avail. + * + * RETURNS + * TRUE if no AbortProc avail or AbortProc wants to continue printing. + * FALSE if AbortProc wants to abort printing. + */ +BOOL16 WINAPI QueryAbort16(HDC16 hdc16, INT16 reserved) +{ + struct gdi_thunk* thunk = GDI_FindThunk(hdc16); + + if (!thunk) { + ERR("Invalid hdc 0x%x\n", hdc16); + return FALSE; + } + return GDI_Callback3216( thunk->pfn16, HDC_32(hdc16), 0 ); +} + + +/********************************************************************** + * SetAbortProc (GDI.381) + */ +INT16 WINAPI SetAbortProc16(HDC16 hdc16, ABORTPROC16 abrtprc) +{ + struct gdi_thunk* thunk; + + thunk = GDI_AddThunk(hdc16, abrtprc); + if (!thunk) return FALSE; + if (!SetAbortProc(HDC_32( hdc16 ), (ABORTPROC)thunk)) + { + GDI_DeleteThunk(thunk); + return FALSE; + } + return TRUE; +} + +/* + * ############################################################################ + */ + struct callback16_info { FARPROC16 proc; @@ -1167,7 +1320,23 @@ HBRUSH16 WINAPI CreateSolidBrush16( COLORREF color ) */ BOOL16 WINAPI DeleteDC16( HDC16 hdc ) { - return DeleteDC( HDC_32(hdc) ); + if (DeleteDC( HDC_32(hdc) )) + { + struct saved_visrgn *saved, *next; + struct gdi_thunk* thunk; + + if ((thunk = GDI_FindThunk(hdc))) GDI_DeleteThunk(thunk); + + LIST_FOR_EACH_ENTRY_SAFE( saved, next, &saved_regions, struct saved_visrgn, entry ) + { + if (saved->hdc != HDC_32(hdc)) continue; + list_remove( &saved->entry ); + DeleteObject( saved->hrgn ); + HeapFree( GetProcessHeap(), 0, saved ); + } + return TRUE; + } + return FALSE; } @@ -2253,7 +2422,9 @@ HPALETTE16 WINAPI CreatePalette16( const LOGPALETTE* palette ) */ HPALETTE16 WINAPI GDISelectPalette16( HDC16 hdc, HPALETTE16 hpalette, WORD wBkg ) { - return HPALETTE_16( GDISelectPalette( HDC_32(hdc), HPALETTE_32(hpalette), wBkg )); + HPALETTE16 ret = HPALETTE_16( SelectPalette( HDC_32(hdc), HPALETTE_32(hpalette), wBkg )); + if (ret && !wBkg) hPrimaryPalette = hpalette; + return ret; } @@ -2262,7 +2433,7 @@ HPALETTE16 WINAPI GDISelectPalette16( HDC16 hdc, HPALETTE16 hpalette, WORD wBkg */ UINT16 WINAPI GDIRealizePalette16( HDC16 hdc ) { - return GDIRealizePalette( HDC_32(hdc) ); + return RealizePalette( HDC_32(hdc) ); } @@ -3353,9 +3524,8 @@ BOOL16 WINAPI SetLayout16( HDC16 hdc, DWORD layout ) */ BOOL16 WINAPI SetSolidBrush16(HBRUSH16 hBrush, COLORREF newColor ) { - TRACE("(hBrush %04x, newColor %08x)\n", hBrush, newColor); - - return BRUSH_SetSolid( HBRUSH_32(hBrush), newColor ); + FIXME( "%04x %08x no longer supported\n", hBrush, newColor ); + return FALSE; } @@ -3372,16 +3542,8 @@ void WINAPI Copy16( LPVOID src, LPVOID dst, WORD size ) */ UINT16 WINAPI RealizeDefaultPalette16( HDC16 hdc ) { - UINT16 ret = 0; - DC *dc; - - TRACE("%04x\n", hdc ); - - if (!(dc = get_dc_ptr( HDC_32(hdc) ))) return 0; - - if (dc->funcs->pRealizeDefaultPalette) ret = dc->funcs->pRealizeDefaultPalette( dc->physDev ); - release_dc_ptr( dc ); - return ret; + FIXME( "%04x semi-stub\n", hdc ); + return GDIRealizePalette16( hdc ); } /*********************************************************************** @@ -3389,14 +3551,7 @@ UINT16 WINAPI RealizeDefaultPalette16( HDC16 hdc ) */ BOOL16 WINAPI IsDCCurrentPalette16(HDC16 hDC) { - DC *dc = get_dc_ptr( HDC_32(hDC) ); - if (dc) - { - BOOL bRet = dc->hPalette == hPrimaryPalette; - release_dc_ptr( dc ); - return bRet; - } - return FALSE; + return HPALETTE_16( GetCurrentObject( HDC_32(hDC), OBJ_PAL )) == hPrimaryPalette; } /********************************************************************* @@ -3414,17 +3569,29 @@ VOID WINAPI SetMagicColors16(HDC16 hDC, COLORREF color, UINT16 index) */ BOOL16 WINAPI DPtoLP16( HDC16 hdc, LPPOINT16 points, INT16 count ) { - DC * dc = get_dc_ptr( HDC_32(hdc) ); - if (!dc) return FALSE; + POINT points32[8], *pt32 = points32; + int i; + BOOL ret; - while (count--) + if (count > 8) { - points->x = MulDiv( points->x - dc->vportOrgX, dc->wndExtX, dc->vportExtX ) + dc->wndOrgX; - points->y = MulDiv( points->y - dc->vportOrgY, dc->wndExtY, dc->vportExtY ) + dc->wndOrgY; - points++; + if (!(pt32 = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pt32) ))) return FALSE; } - release_dc_ptr( dc ); - return TRUE; + for (i = 0; i < count; i++) + { + pt32[i].x = points[i].x; + pt32[i].y = points[i].y; + } + if ((ret = DPtoLP( HDC_32(hdc), pt32, count ))) + { + for (i = 0; i < count; i++) + { + points[i].x = pt32[i].x; + points[i].y = pt32[i].y; + } + } + if (pt32 != points32) HeapFree( GetProcessHeap(), 0, pt32 ); + return ret; } @@ -3433,17 +3600,29 @@ BOOL16 WINAPI DPtoLP16( HDC16 hdc, LPPOINT16 points, INT16 count ) */ BOOL16 WINAPI LPtoDP16( HDC16 hdc, LPPOINT16 points, INT16 count ) { - DC * dc = get_dc_ptr( HDC_32(hdc) ); - if (!dc) return FALSE; + POINT points32[8], *pt32 = points32; + int i; + BOOL ret; - while (count--) + if (count > 8) { - points->x = MulDiv( points->x - dc->wndOrgX, dc->vportExtX, dc->wndExtX ) + dc->vportOrgX; - points->y = MulDiv( points->y - dc->wndOrgY, dc->vportExtY, dc->wndExtY ) + dc->vportOrgY; - points++; + if (!(pt32 = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pt32) ))) return FALSE; } - release_dc_ptr( dc ); - return TRUE; + for (i = 0; i < count; i++) + { + pt32[i].x = points[i].x; + pt32[i].y = points[i].y; + } + if ((ret = LPtoDP( HDC_32(hdc), pt32, count ))) + { + for (i = 0; i < count; i++) + { + points[i].x = pt32[i].x; + points[i].y = pt32[i].y; + } + } + if (pt32 != points32) HeapFree( GetProcessHeap(), 0, pt32 ); + return ret; } @@ -3470,13 +3649,8 @@ void WINAPI SetDCState16( HDC16 hdc, HDC16 hdcs ) */ DWORD WINAPI SetDCOrg16( HDC16 hdc16, INT16 x, INT16 y ) { - DWORD prevOrg = 0; - HDC hdc = HDC_32( hdc16 ); - DC *dc = get_dc_ptr( hdc ); - if (!dc) return 0; - if (dc->funcs->pSetDCOrg) prevOrg = dc->funcs->pSetDCOrg( dc->physDev, x, y ); - release_dc_ptr( dc ); - return prevOrg; + FIXME( "%04x %d,%d no longer supported\n", hdc16, x, y ); + return 0; } @@ -3485,14 +3659,11 @@ DWORD WINAPI SetDCOrg16( HDC16 hdc16, INT16 x, INT16 y ) */ HRGN16 WINAPI InquireVisRgn16( HDC16 hdc ) { - HRGN16 ret = 0; - DC * dc = get_dc_ptr( HDC_32(hdc) ); - if (dc) - { - ret = HRGN_16(dc->hVisRgn); - release_dc_ptr( dc ); - } - return ret; + static HRGN hrgn; + + if (!hrgn) hrgn = CreateRectRgn( 0, 0, 0, 0 ); + GetRandomRgn( HDC_32(hdc), hrgn, SYSRGN ); + return HRGN_16(hrgn); } @@ -3501,17 +3672,8 @@ HRGN16 WINAPI InquireVisRgn16( HDC16 hdc ) */ INT16 WINAPI OffsetVisRgn16( HDC16 hdc16, INT16 x, INT16 y ) { - INT16 retval; - HDC hdc = HDC_32( hdc16 ); - DC * dc = get_dc_ptr( hdc ); - - if (!dc) return ERROR; - TRACE("%p %d,%d\n", hdc, x, y ); - update_dc( dc ); - retval = OffsetRgn( dc->hVisRgn, x, y ); - CLIPPING_UpdateGCRegion( dc ); - release_dc_ptr( dc ); - return retval; + FIXME( "%04x %d,%d no longer supported\n", hdc16, x, y ); + return ERROR; } @@ -3520,32 +3682,8 @@ INT16 WINAPI OffsetVisRgn16( HDC16 hdc16, INT16 x, INT16 y ) */ INT16 WINAPI ExcludeVisRect16( HDC16 hdc16, INT16 left, INT16 top, INT16 right, INT16 bottom ) { - HRGN tempRgn; - INT16 ret; - POINT pt[2]; - HDC hdc = HDC_32( hdc16 ); - DC * dc = get_dc_ptr( hdc ); - if (!dc) return ERROR; - - pt[0].x = left; - pt[0].y = top; - pt[1].x = right; - pt[1].y = bottom; - - LPtoDP( hdc, pt, 2 ); - - TRACE("%p %d,%d - %d,%d\n", hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y); - - if (!(tempRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR; - else - { - update_dc( dc ); - ret = CombineRgn( dc->hVisRgn, dc->hVisRgn, tempRgn, RGN_DIFF ); - DeleteObject( tempRgn ); - } - if (ret != ERROR) CLIPPING_UpdateGCRegion( dc ); - release_dc_ptr( dc ); - return ret; + FIXME( "%04x %d,%d-%d,%d no longer supported\n", hdc16, left, top, right, bottom ); + return ERROR; } @@ -3554,32 +3692,8 @@ INT16 WINAPI ExcludeVisRect16( HDC16 hdc16, INT16 left, INT16 top, INT16 right, */ INT16 WINAPI IntersectVisRect16( HDC16 hdc16, INT16 left, INT16 top, INT16 right, INT16 bottom ) { - HRGN tempRgn; - INT16 ret; - POINT pt[2]; - HDC hdc = HDC_32( hdc16 ); - DC * dc = get_dc_ptr( hdc ); - if (!dc) return ERROR; - - pt[0].x = left; - pt[0].y = top; - pt[1].x = right; - pt[1].y = bottom; - - LPtoDP( hdc, pt, 2 ); - - TRACE("%p %d,%d - %d,%d\n", hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y); - - if (!(tempRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR; - else - { - update_dc( dc ); - ret = CombineRgn( dc->hVisRgn, dc->hVisRgn, tempRgn, RGN_AND ); - DeleteObject( tempRgn ); - } - if (ret != ERROR) CLIPPING_UpdateGCRegion( dc ); - release_dc_ptr( dc ); - return ret; + FIXME( "%04x %d,%d-%d,%d no longer supported\n", hdc16, left, top, right, bottom ); + return ERROR; } @@ -3590,24 +3704,19 @@ HRGN16 WINAPI SaveVisRgn16( HDC16 hdc16 ) { struct saved_visrgn *saved; HDC hdc = HDC_32( hdc16 ); - DC *dc = get_dc_ptr( hdc ); - if (!dc) return 0; TRACE("%p\n", hdc ); - update_dc( dc ); - if (!(saved = HeapAlloc( GetProcessHeap(), 0, sizeof(*saved) ))) goto error; - if (!(saved->hrgn = CreateRectRgn( 0, 0, 0, 0 ))) goto error; - CombineRgn( saved->hrgn, dc->hVisRgn, 0, RGN_COPY ); - saved->next = dc->saved_visrgn; - dc->saved_visrgn = saved; - release_dc_ptr( dc ); + if (!(saved = HeapAlloc( GetProcessHeap(), 0, sizeof(*saved) ))) return 0; + if (!(saved->hrgn = CreateRectRgn( 0, 0, 0, 0 ))) + { + HeapFree( GetProcessHeap(), 0, saved ); + return 0; + } + saved->hdc = hdc; + GetRandomRgn( hdc, saved->hrgn, SYSRGN ); + list_add_head( &saved_regions, &saved->entry ); return HRGN_16(saved->hrgn); - -error: - release_dc_ptr( dc ); - HeapFree( GetProcessHeap(), 0, saved ); - return 0; } @@ -3618,22 +3727,19 @@ INT16 WINAPI RestoreVisRgn16( HDC16 hdc16 ) { struct saved_visrgn *saved; HDC hdc = HDC_32( hdc16 ); - DC *dc = get_dc_ptr( hdc ); INT16 ret = ERROR; - if (!dc) return ERROR; - TRACE("%p\n", hdc ); - if (!(saved = dc->saved_visrgn)) goto done; - - ret = CombineRgn( dc->hVisRgn, saved->hrgn, 0, RGN_COPY ); - dc->saved_visrgn = saved->next; - DeleteObject( saved->hrgn ); - HeapFree( GetProcessHeap(), 0, saved ); - CLIPPING_UpdateGCRegion( dc ); - done: - release_dc_ptr( dc ); + LIST_FOR_EACH_ENTRY( saved, &saved_regions, struct saved_visrgn, entry ) + { + if (saved->hdc != hdc) continue; + ret = SelectVisRgn( hdc, saved->hrgn ); + list_remove( &saved->entry ); + DeleteObject( saved->hrgn ); + HeapFree( GetProcessHeap(), 0, saved ); + break; + } return ret; } @@ -3643,14 +3749,11 @@ INT16 WINAPI RestoreVisRgn16( HDC16 hdc16 ) */ HRGN16 WINAPI GetClipRgn16( HDC16 hdc ) { - HRGN16 ret = 0; - DC * dc = get_dc_ptr( HDC_32(hdc) ); - if (dc) - { - ret = HRGN_16(dc->hClipRgn); - release_dc_ptr( dc ); - } - return ret; + static HRGN hrgn; + + if (!hrgn) hrgn = CreateRectRgn( 0, 0, 0, 0 ); + GetClipRgn( HDC_32(hdc), hrgn ); + return HRGN_16(hrgn); } diff --git a/dlls/gdi32/gdi32.spec b/dlls/gdi32/gdi32.spec index 6a67f44c7eb..ebd95256367 100644 --- a/dlls/gdi32/gdi32.spec +++ b/dlls/gdi32/gdi32.spec @@ -514,8 +514,6 @@ # Wine extensions: Win16 functions that are needed by other dlls # @ stdcall CloseJob16(long) -@ stdcall DrvGetPrinterData16(str str ptr ptr long ptr) -@ stdcall DrvSetPrinterData16(str str long ptr long) @ stdcall GetDCHook(long ptr) @ stdcall OpenJob16(str str long) @ stdcall SelectVisRgn(long long) diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h index f0248c9bf77..7b565c96587 100644 --- a/dlls/gdi32/gdi_private.h +++ b/dlls/gdi32/gdi_private.h @@ -161,7 +161,6 @@ typedef struct tagDC_FUNCS COLORREF (CDECL *pSetBkColor)(PHYSDEV,COLORREF); INT (CDECL *pSetBkMode)(PHYSDEV,INT); COLORREF (CDECL *pSetDCBrushColor)(PHYSDEV, COLORREF); - DWORD (CDECL *pSetDCOrg)(PHYSDEV,INT,INT); COLORREF (CDECL *pSetDCPenColor)(PHYSDEV, COLORREF); UINT (CDECL *pSetDIBColorTable)(PHYSDEV,UINT,UINT,const RGBQUAD*); INT (CDECL *pSetDIBits)(PHYSDEV,HBITMAP,UINT,UINT,LPCVOID,const BITMAPINFO*,UINT); @@ -200,6 +199,7 @@ typedef struct tagDC_FUNCS /* OpenGL32 */ BOOL (CDECL *pwglCopyContext)(HGLRC, HGLRC, UINT); HGLRC (CDECL *pwglCreateContext)(PHYSDEV); + HGLRC (CDECL *pwglCreateContextAttribsARB)(PHYSDEV, HGLRC, const int*); BOOL (CDECL *pwglDeleteContext)(HGLRC); PROC (CDECL *pwglGetProcAddress)(LPCSTR); HDC (CDECL *pwglGetPbufferDCARB)(PHYSDEV, void*); @@ -234,12 +234,6 @@ typedef struct tagGdiPath typedef struct tagGdiFont GdiFont; -struct saved_visrgn -{ - struct saved_visrgn *next; - HRGN hrgn; -}; - typedef struct tagDC { GDIOBJHDR header; @@ -302,7 +296,6 @@ typedef struct tagDC INT MapMode; INT GraphicsMode; /* Graphics mode */ ABORTPROC pAbortProc; /* AbortProc for Printing */ - ABORTPROC16 pAbortProc16; INT CursPosX; /* Current position */ INT CursPosY; INT ArcDirection; @@ -311,8 +304,6 @@ typedef struct tagDC XFORM xformVport2World; /* Inverse of the above transformation */ BOOL vport2WorldValid; /* Is xformVport2World valid? */ RECT BoundsRect; /* Current bounding rect */ - - struct saved_visrgn *saved_visrgn; } DC; /* DC flags */ @@ -369,9 +360,6 @@ extern HBITMAP BITMAP_CopyBitmap( HBITMAP hbitmap ) DECLSPEC_HIDDEN; extern BOOL BITMAP_SetOwnerDC( HBITMAP hbitmap, DC *dc ) DECLSPEC_HIDDEN; extern INT BITMAP_GetWidthBytes( INT bmWidth, INT bpp ) DECLSPEC_HIDDEN; -/* brush.c */ -extern BOOL BRUSH_SetSolid( HGDIOBJ handle, COLORREF new_color ) DECLSPEC_HIDDEN; - /* clipping.c */ extern void CLIPPING_UpdateGCRegion( DC * dc ) DECLSPEC_HIDDEN; @@ -459,9 +447,6 @@ extern BOOL GDI_hdc_not_using_object(HGDIOBJ obj, HDC hdc) DECLSPEC_HIDDEN; /* metafile.c */ extern HMETAFILE MF_Create_HMETAFILE(METAHEADER *mh) DECLSPEC_HIDDEN; extern METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mr, LPCVOID filename, BOOL unicode ) DECLSPEC_HIDDEN; -extern METAHEADER *MF_ReadMetaFile(HANDLE hfile) DECLSPEC_HIDDEN; -extern METAHEADER *MF_LoadDiskBasedMetaFile(METAHEADER *mh) DECLSPEC_HIDDEN; -extern BOOL MF_PlayMetaFile( HDC hdc, METAHEADER *mh) DECLSPEC_HIDDEN; /* path.c */ @@ -500,7 +485,6 @@ extern POINT *GDI_Bezier( const POINT *Points, INT count, INT *nPtsOut ) DECLSPE extern HPALETTE WINAPI GDISelectPalette( HDC hdc, HPALETTE hpal, WORD wBkg); extern UINT WINAPI GDIRealizePalette( HDC hdc ); extern HPALETTE PALETTE_Init(void) DECLSPEC_HIDDEN; -extern HPALETTE hPrimaryPalette DECLSPEC_HIDDEN; /* region.c */ extern BOOL REGION_FrameRgn( HRGN dest, HRGN src, INT x, INT y ) DECLSPEC_HIDDEN; diff --git a/dlls/gdi32/metafile.c b/dlls/gdi32/metafile.c index a14928c9832..27ce7b5cbab 100644 --- a/dlls/gdi32/metafile.c +++ b/dlls/gdi32/metafile.c @@ -175,7 +175,7 @@ BOOL WINAPI DeleteMetaFile( HMETAFILE hmf ) * Returns a pointer to a memory based METAHEADER read in from file HFILE * */ -METAHEADER *MF_ReadMetaFile(HANDLE hfile) +static METAHEADER *MF_ReadMetaFile(HANDLE hfile) { METAHEADER *mh; DWORD BytesRead, size; @@ -266,7 +266,7 @@ HMETAFILE WINAPI GetMetaFileW( LPCWSTR lpFilename ) * * Creates a new memory-based metafile from a disk-based one. */ -METAHEADER *MF_LoadDiskBasedMetaFile(METAHEADER *mh) +static METAHEADER *MF_LoadDiskBasedMetaFile(METAHEADER *mh) { METAHEADERDISK *mhd; HANDLE hfile; @@ -384,7 +384,7 @@ HMETAFILE WINAPI CopyMetaFileA( HMETAFILE hSrcMetaFile, LPCSTR lpFilename ) * * Helper for PlayMetaFile */ -BOOL MF_PlayMetaFile( HDC hdc, METAHEADER *mh) +static BOOL MF_PlayMetaFile( HDC hdc, METAHEADER *mh) { METARECORD *mr; diff --git a/dlls/gdi32/metafile16.c b/dlls/gdi32/metafile16.c index 812fb9cb7fa..dfde8f75f60 100644 --- a/dlls/gdi32/metafile16.c +++ b/dlls/gdi32/metafile16.c @@ -30,12 +30,15 @@ #include "wine/wingdi16.h" #include "wownt32.h" #include "winreg.h" -#include "winternl.h" -#include "gdi_private.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(metafile); +#define METAFILE_MEMORY 1 +#define METAFILE_DISK 2 +#define MFHEADERSIZE (sizeof(METAHEADER)) +#define MFVERSION 0x300 + /****************************************************************** * MF_GetMetaHeader16 * @@ -58,26 +61,38 @@ static BOOL16 MF_ReleaseMetaHeader16( HMETAFILE16 hmf ) } /****************************************************************** - * MF_Create_HMETATFILE16 - * - * Creates a HMETAFILE16 object from a METAHEADER + * create_metafile16 * - * HMETAFILE16s are Global memory handles. + * Create a 16-bit metafile from a 32-bit one. The 32-bit one is deleted. */ -static HMETAFILE16 MF_Create_HMETAFILE16(METAHEADER *mh) +static HMETAFILE16 create_metafile16( HMETAFILE hmf ) { - HMETAFILE16 hmf; - DWORD size = mh->mtSize * sizeof(WORD); + UINT size; + HMETAFILE16 hmf16; - hmf = GlobalAlloc16(GMEM_MOVEABLE, size); - if(hmf) + if (!hmf) return 0; + size = GetMetaFileBitsEx( hmf, 0, NULL ); + hmf16 = GlobalAlloc16( GMEM_MOVEABLE, size ); + if (hmf16) { - METAHEADER *mh_dest = GlobalLock16(hmf); - memcpy(mh_dest, mh, size); - GlobalUnlock16(hmf); + void *buffer = GlobalLock16( hmf16 ); + GetMetaFileBitsEx( hmf, size, buffer ); + GlobalUnlock16( hmf16 ); } - HeapFree(GetProcessHeap(), 0, mh); - return hmf; + DeleteMetaFile( hmf ); + return hmf16; +} + +/****************************************************************** + * create_metafile32 + * + * Create a 32-bit metafile from a 16-bit one. + */ +static HMETAFILE create_metafile32( HMETAFILE16 hmf16 ) +{ + METAHEADER *mh = MF_GetMetaHeader16( hmf16 ); + if (!mh) return 0; + return SetMetaFileBitsEx( mh->mtSize * 2, (BYTE *)mh ); } /********************************************************************** @@ -93,23 +108,7 @@ HDC16 WINAPI CreateMetaFile16( LPCSTR filename ) */ HMETAFILE16 WINAPI CloseMetaFile16(HDC16 hdc) { - HMETAFILE16 hmf16 = 0; - HMETAFILE hmf = CloseMetaFile( HDC_32(hdc) ); - - if (hmf) - { - UINT size = GetMetaFileBitsEx( hmf, 0, NULL ); - - hmf16 = GlobalAlloc16( GMEM_MOVEABLE, size ); - if (hmf16) - { - void *buffer = GlobalLock16( hmf16 ); - GetMetaFileBitsEx( hmf, size, buffer ); - GlobalUnlock16( hmf16 ); - } - DeleteMetaFile( hmf ); - } - return hmf16; + return create_metafile16( CloseMetaFile( HDC_32(hdc) )); } /****************************************************************** @@ -125,22 +124,7 @@ BOOL16 WINAPI DeleteMetaFile16( HMETAFILE16 hmf ) */ HMETAFILE16 WINAPI GetMetaFile16( LPCSTR lpFilename ) { - METAHEADER *mh; - HANDLE hFile; - - TRACE("%s\n", lpFilename); - - if(!lpFilename) - return 0; - - if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) - return 0; - - mh = MF_ReadMetaFile(hFile); - CloseHandle(hFile); - if(!mh) return 0; - return MF_Create_HMETAFILE16( mh ); + return create_metafile16( GetMetaFileA( lpFilename )); } /****************************************************************** @@ -148,35 +132,10 @@ HMETAFILE16 WINAPI GetMetaFile16( LPCSTR lpFilename ) */ HMETAFILE16 WINAPI CopyMetaFile16( HMETAFILE16 hSrcMetaFile, LPCSTR lpFilename) { - METAHEADER *mh = MF_GetMetaHeader16( hSrcMetaFile ); - METAHEADER *mh2 = NULL; - HANDLE hFile; - - TRACE("(%08x,%s)\n", hSrcMetaFile, lpFilename); - - if(!mh) return 0; - - if(mh->mtType == METAFILE_DISK) - mh2 = MF_LoadDiskBasedMetaFile(mh); - else { - mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 ); - memcpy( mh2, mh, mh->mtSize * 2 ); - } - MF_ReleaseMetaHeader16( hSrcMetaFile ); - - if(lpFilename) { /* disk based metafile */ - DWORD w; - if((hFile = CreateFileA(lpFilename, GENERIC_WRITE, 0, NULL, - CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) { - HeapFree( GetProcessHeap(), 0, mh2 ); - return 0; - } - WriteFile(hFile, mh2, mh2->mtSize * 2, &w, NULL); - CloseHandle(hFile); - mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilename, FALSE); - } - - return MF_Create_HMETAFILE16( mh2 ); + HMETAFILE hmf = create_metafile32( hSrcMetaFile ); + HMETAFILE hmf2 = CopyMetaFileA( hmf, lpFilename ); + DeleteMetaFile( hmf ); + return create_metafile16( hmf2 ); } /****************************************************************** @@ -212,12 +171,11 @@ BOOL16 WINAPI IsValidMetaFile16(HMETAFILE16 hmf) * PlayMetaFile (GDI.123) * */ -BOOL16 WINAPI PlayMetaFile16( HDC16 hdc, HMETAFILE16 hmf ) +BOOL16 WINAPI PlayMetaFile16( HDC16 hdc, HMETAFILE16 hmf16 ) { - BOOL16 ret; - METAHEADER *mh = MF_GetMetaHeader16( hmf ); - ret = MF_PlayMetaFile( HDC_32(hdc), mh ); - MF_ReleaseMetaHeader16( hmf ); + HMETAFILE hmf = create_metafile32( hmf16 ); + BOOL ret = PlayMetaFile( HDC_32(hdc), hmf ); + DeleteMetaFile( hmf ); return ret; } @@ -241,16 +199,11 @@ BOOL16 WINAPI EnumMetaFile16( HDC16 hdc16, HMETAFILE16 hmf, HBRUSH hBrush; HFONT hFont; WORD args[8]; - BOOL16 result = TRUE, loaded = FALSE; + BOOL16 result = TRUE; TRACE("(%p, %04x, %p, %08lx)\n", hdc, hmf, lpEnumFunc, lpData); if(!mh) return FALSE; - if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */ - mh = MF_LoadDiskBasedMetaFile(mh); - if(!mh) return FALSE; - loaded = TRUE; - } /* save the current pen, brush and font */ hPen = GetCurrentObject(hdc, OBJ_PEN); @@ -308,8 +261,6 @@ BOOL16 WINAPI EnumMetaFile16( HDC16 hdc16, HMETAFILE16 hmf, /* free handle table */ GlobalFree16(hHT); - if(loaded) - HeapFree( GetProcessHeap(), 0, mh ); MF_ReleaseMetaHeader16(hmf); return result; } diff --git a/dlls/gdi32/mfdrv/init.c b/dlls/gdi32/mfdrv/init.c index 59c973a6b34..4c88ac6d833 100644 --- a/dlls/gdi32/mfdrv/init.c +++ b/dlls/gdi32/mfdrv/init.c @@ -119,7 +119,6 @@ static const DC_FUNCTIONS MFDRV_Funcs = MFDRV_SetBkColor, /* pSetBkColor */ MFDRV_SetBkMode, /* pSetBkMode */ NULL, /* pSetDCBrushColor*/ - NULL, /* pSetDCOrg */ NULL, /* pSetDCPenColor*/ NULL, /* pSetDIBColorTable */ NULL, /* pSetDIBits */ diff --git a/dlls/gdi32/opengl.c b/dlls/gdi32/opengl.c index 63ba433149d..9193fc536df 100644 --- a/dlls/gdi32/opengl.c +++ b/dlls/gdi32/opengl.c @@ -104,6 +104,25 @@ HGLRC WINAPI wglCreateContext(HDC hdc) return ret; } +/*********************************************************************** + * wglCreateContextAttribsARB + */ +static HGLRC WINAPI wglCreateContextAttribsARB(HDC hdc, HGLRC hShareContext, const int *attributeList) +{ + HGLRC ret = 0; + DC * dc = get_dc_ptr( hdc ); + + TRACE("(%p)\n",hdc); + + if (!dc) return 0; + + update_dc( dc ); + if (!dc->funcs->pwglCreateContextAttribsARB) FIXME(" :stub\n"); + else ret = dc->funcs->pwglCreateContextAttribsARB(dc->physDev, hShareContext, attributeList); + + release_dc_ptr( dc ); + return ret; +} /*********************************************************************** * wglDeleteContext (OPENGL32.@) @@ -279,7 +298,7 @@ BOOL WINAPI wglShareLists(HGLRC hglrc1, HGLRC hglrc2) OPENGL_Context ctx = (OPENGL_Context)hglrc1; TRACE("hglrc1: (%p); hglrc: (%p)\n", hglrc1, hglrc2); - if(ctx == NULL) + if(ctx == NULL || hglrc2 == NULL) return FALSE; /* Retrieve the HDC associated with the context to access the display driver */ @@ -358,7 +377,9 @@ PROC WINAPI wglGetProcAddress(LPCSTR func) * when a non-NULL value is returned by wglGetProcAddress), we return the address * of a wrapper function which will handle the HDC->PhysDev conversion. */ - if(ret && strcmp(func, "wglMakeContextCurrentARB") == 0) + if(ret && strcmp(func, "wglCreateContextAttribsARB") == 0) + return (PROC)wglCreateContextAttribsARB; + else if(ret && strcmp(func, "wglMakeContextCurrentARB") == 0) return (PROC)wglMakeContextCurrentARB; else if(ret && strcmp(func, "wglGetPbufferDCARB") == 0) return (PROC)wglGetPbufferDCARB; diff --git a/dlls/gdi32/palette.c b/dlls/gdi32/palette.c index b4bbc9508d1..e941b10c52c 100644 --- a/dlls/gdi32/palette.c +++ b/dlls/gdi32/palette.c @@ -67,7 +67,7 @@ UINT (WINAPI *pfnRealizePalette)(HDC hdc) = GDIRealizePalette; static UINT SystemPaletteUse = SYSPAL_STATIC; /* currently not considered */ -HPALETTE hPrimaryPalette = 0; /* used for WM_PALETTECHANGED */ +static HPALETTE hPrimaryPalette = 0; /* used for WM_PALETTECHANGED */ static HPALETTE hLastRealizedPalette = 0; /* UnrealizeObject() needs it */ #define NB_RESERVED_COLORS 20 /* number of fixed colors in system palette */ diff --git a/dlls/gdi32/printdrv16.c b/dlls/gdi32/printdrv16.c index e7954eedab6..f0b8cf07b35 100644 --- a/dlls/gdi32/printdrv16.c +++ b/dlls/gdi32/printdrv16.c @@ -57,72 +57,6 @@ static const char DefaultDevMode[] = "Default DevMode"; static const char PrinterDriverData[] = "PrinterDriverData"; static const char Printers[] = "System\\CurrentControlSet\\Control\\Print\\Printers\\"; -/********************************************************************** - * QueryAbort (GDI.155) - * - * Calls the app's AbortProc function if avail. - * - * RETURNS - * TRUE if no AbortProc avail or AbortProc wants to continue printing. - * FALSE if AbortProc wants to abort printing. - */ -BOOL16 WINAPI QueryAbort16(HDC16 hdc16, INT16 reserved) -{ - BOOL ret = TRUE; - HDC hdc = HDC_32( hdc16 ); - DC *dc = get_dc_ptr( hdc ); - - if(!dc) { - ERR("Invalid hdc %p\n", hdc); - return FALSE; - } - if (dc->pAbortProc) ret = dc->pAbortProc(hdc, 0); - release_dc_ptr( dc ); - return ret; -} - - -/********************************************************************** - * call_abort_proc16 - */ -static BOOL CALLBACK call_abort_proc16( HDC hdc, INT code ) -{ - ABORTPROC16 proc16; - DC *dc = get_dc_ptr( hdc ); - - if (!dc) return FALSE; - proc16 = dc->pAbortProc16; - release_dc_ptr( dc ); - if (proc16) - { - WORD args[2]; - DWORD ret; - - args[1] = HDC_16(hdc); - args[0] = code; - WOWCallback16Ex( (DWORD)proc16, WCB16_PASCAL, sizeof(args), args, &ret ); - return LOWORD(ret); - } - return TRUE; -} - - -/********************************************************************** - * SetAbortProc (GDI.381) - */ -INT16 WINAPI SetAbortProc16(HDC16 hdc16, ABORTPROC16 abrtprc) -{ - HDC hdc = HDC_32( hdc16 ); - DC *dc = get_dc_ptr( hdc ); - - if (!dc) return FALSE; - dc->pAbortProc16 = abrtprc; - dc->pAbortProc = call_abort_proc16; - release_dc_ptr( dc ); - return TRUE; -} - - /****************** misc. printer related functions */ /* diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index b67670f53d6..c3e193ad079 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -2977,6 +2977,39 @@ static void test_GetTextMetrics2(const char *fontname, int font_height) ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio); } +static void test_CreateFontIndirect(void) +{ + LOGFONTA lf, getobj_lf; + int ret, i; + HFONT hfont; + char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic"}; + + memset(&lf, 0, sizeof(lf)); + lf.lfCharSet = ANSI_CHARSET; + lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf.lfHeight = 16; + lf.lfWidth = 16; + lf.lfQuality = DEFAULT_QUALITY; + lf.lfItalic = FALSE; + lf.lfWeight = FW_DONTCARE; + + for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++) + { + lstrcpyA(lf.lfFaceName, TestName[i]); + hfont = CreateFontIndirectA(&lf); + ok(hfont != 0, "CreateFontIndirectA failed\n"); + ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf); + ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic); + ok(lf.lfWeight == getobj_lf.lfWeight || + broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */ + "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight); + ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) || + broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */ + "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName); + DeleteObject(hfont); + } +} + START_TEST(font) { init(); @@ -3020,4 +3053,5 @@ START_TEST(font) test_GetTextMetrics2("Arial", -11); test_GetTextMetrics2("Arial", -55); test_GetTextMetrics2("Arial", -110); + test_CreateFontIndirect(); } diff --git a/dlls/gdi32/tests/metafile.c b/dlls/gdi32/tests/metafile.c index b55990199c8..9ce3ece13dc 100644 --- a/dlls/gdi32/tests/metafile.c +++ b/dlls/gdi32/tests/metafile.c @@ -1030,6 +1030,63 @@ static const unsigned char EMF_LINETO_MM_TEXT_BITS[] = { 0x14, 0x00, 0x00, 0x00 }; +static const unsigned char EMF_BITBLT[] = +{ + 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6a, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, + 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00, + 0xa0, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x23, 0x04, 0x00, 0x00, 0x3b, 0x02, 0x00, 0x00, + 0x75, 0x01, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0xb1, 0x05, 0x00, + 0x28, 0x11, 0x03, 0x00, 0x4c, 0x00, 0x00, 0x00, + 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0xcc, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x8c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x62, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 +}; + + /* For debugging or dumping the raw metafiles produced by * new test functions. */ @@ -1382,6 +1439,70 @@ static int compare_emf_bits(const HENHMETAFILE mf, const unsigned char *bits, return 0; } + +/* tests blitting to an EMF */ +static void test_emf_BitBlt(void) +{ + HDC hdcDisplay, hdcMetafile, hdcBitmap; + HBITMAP hBitmap, hOldBitmap; + HENHMETAFILE hMetafile; +#define BMP_DIM 4 + BITMAPINFOHEADER bmih = + { + sizeof(BITMAPINFOHEADER), + BMP_DIM,/* biWidth */ + BMP_DIM,/* biHeight */ + 1, /* biPlanes */ + 24, /* biBitCount */ + BI_RGB, /* biCompression */ + 0, /* biXPelsPerMeter */ + 0, /* biYPelsPerMeter */ + 0, /* biClrUsed */ + 0, /* biClrImportant */ + }; + void *bits; + BOOL ret; + + hdcDisplay = CreateDCA("DISPLAY", NULL, NULL, NULL); + ok( hdcDisplay != 0, "CreateDCA error %d\n", GetLastError() ); + + hdcBitmap = CreateCompatibleDC(hdcDisplay); + ok( hdcBitmap != 0, "CreateCompatibleDC failed\n" ); + bmih.biXPelsPerMeter = MulDiv(GetDeviceCaps(hdcDisplay, LOGPIXELSX), 100, 3937); + bmih.biYPelsPerMeter = MulDiv(GetDeviceCaps(hdcDisplay, LOGPIXELSY), 100, 3937); + hBitmap = CreateDIBSection(hdcDisplay, (const BITMAPINFO *)&bmih, + DIB_RGB_COLORS, &bits, NULL, 0); + hOldBitmap = SelectObject(hdcBitmap, hBitmap); + + hdcMetafile = CreateEnhMetaFileA(hdcBitmap, NULL, NULL, NULL); + ok( hdcMetafile != 0, "CreateEnhMetaFileA failed\n" ); + + /* First fill the bitmap DC with something recognizable, like BLACKNESS */ + ret = BitBlt(hdcBitmap, 0, 0, BMP_DIM, BMP_DIM, 0, 0, 0, BLACKNESS); + ok( ret, "BitBlt(BLACKNESS) failed\n" ); + + ret = BitBlt(hdcMetafile, 0, 0, BMP_DIM, BMP_DIM, hdcBitmap, 0, 0, SRCCOPY); + ok( ret, "BitBlt(SRCCOPY) failed\n" ); + ret = BitBlt(hdcMetafile, 0, 0, BMP_DIM, BMP_DIM, 0, 0, 0, WHITENESS); + ok( ret, "BitBlt(WHITENESS) failed\n" ); + + hMetafile = CloseEnhMetaFile(hdcMetafile); + ok( hMetafile != 0, "CloseEnhMetaFile failed\n" ); + + if(compare_emf_bits(hMetafile, EMF_BITBLT, sizeof(EMF_BITBLT), + "emf_BitBlt", FALSE) != 0) + { + dump_emf_bits(hMetafile, "emf_BitBlt"); + dump_emf_records(hMetafile, "emf_BitBlt"); + } + + SelectObject(hdcBitmap, hOldBitmap); + DeleteObject(hBitmap); + DeleteDC(hdcBitmap); + DeleteDC(hdcDisplay); +#undef BMP_DIM +} + /* Test a blank metafile. May be used as a template for new tests. */ static void test_mf_Blank(void) @@ -2628,6 +2749,7 @@ START_TEST(metafile) /* For enhanced metafiles (enhmfdrv) */ test_ExtTextOut(); test_SaveDC(); + test_emf_BitBlt(); /* For win-format metafiles (mfdrv) */ test_mf_SaveDC(); diff --git a/dlls/jscript/activex.c b/dlls/jscript/activex.c index 60e33e01f00..947e4cfd289 100644 --- a/dlls/jscript/activex.c +++ b/dlls/jscript/activex.c @@ -86,7 +86,7 @@ static IUnknown *create_activex_object(script_ctx_t *ctx, const WCHAR *progid) if(FAILED(hres) || policy != URLPOLICY_ALLOW) return NULL; - hres = CoGetClassObject(&guid, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, NULL, &IID_IClassFactory, (void**)&cf); + hres = CoGetClassObject(&guid, CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER, NULL, &IID_IClassFactory, (void**)&cf); if(FAILED(hres)) return NULL; diff --git a/dlls/jscript/error.c b/dlls/jscript/error.c index 6c89d7073a4..d8503f18971 100644 --- a/dlls/jscript/error.c +++ b/dlls/jscript/error.c @@ -489,11 +489,6 @@ static HRESULT throw_error(script_ctx_t *ctx, jsexcept_t *ei, UINT id, const WCH return id; } -HRESULT throw_eval_error(script_ctx_t *ctx, jsexcept_t *ei, UINT id, const WCHAR *str) -{ - return throw_error(ctx, ei, id, str, ctx->eval_error_constr); -} - HRESULT throw_generic_error(script_ctx_t *ctx, jsexcept_t *ei, UINT id, const WCHAR *str) { return throw_error(ctx, ei, id, str, ctx->error_constr); diff --git a/dlls/jscript/global.c b/dlls/jscript/global.c index 8f6080dc1b1..501da79e71b 100644 --- a/dlls/jscript/global.c +++ b/dlls/jscript/global.c @@ -930,11 +930,127 @@ static HRESULT JSGlobal_encodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, W return S_OK; } +/* ECMA-262 3rd Edition 15.1.3.2 */ static HRESULT JSGlobal_decodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp) { - FIXME("\n"); - return E_NOTIMPL; + BSTR str, ret; + const WCHAR *ptr; + WCHAR *out_ptr; + DWORD len = 0; + HRESULT hres; + + TRACE("\n"); + + if(!arg_cnt(dp)) { + if(retv) { + ret = SysAllocString(undefinedW); + if(!ret) + return E_OUTOFMEMORY; + + V_VT(retv) = VT_BSTR; + V_BSTR(retv) = ret; + } + + return S_OK; + } + + hres = to_string(ctx, get_arg(dp, 0), ei, &str); + if(FAILED(hres)) + return hres; + + ptr = str; + while(*ptr) { + if(*ptr == '%') { + char octets[4]; + unsigned char mask = 0x80; + int i, size, num_bytes = 0; + if(hex_to_int(*(ptr+1)) < 0 || hex_to_int(*(ptr+2)) < 0) { + FIXME("Throw URIError: Invalid hex sequence\n"); + SysFreeString(str); + return E_FAIL; + } + octets[0] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2)); + ptr += 3; + while(octets[0] & mask) { + mask = mask >> 1; + ++num_bytes; + } + if(num_bytes == 1 || num_bytes > 4) { + FIXME("Throw URIError: Invalid initial UTF character\n"); + SysFreeString(str); + return E_FAIL; + } + for(i = 1; i < num_bytes; ++i) { + if(*ptr != '%'){ + FIXME("Throw URIError: Incomplete UTF sequence\n"); + SysFreeString(str); + return E_FAIL; + } + if(hex_to_int(*(ptr+1)) < 0 || hex_to_int(*(ptr+2)) < 0) { + FIXME("Throw URIError: Invalid hex sequence\n"); + SysFreeString(str); + return E_FAIL; + } + octets[i] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2)); + ptr += 3; + } + size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, octets, + num_bytes ? num_bytes : 1, NULL, 0); + if(size == 0) { + FIXME("Throw URIError: Invalid UTF sequence\n"); + SysFreeString(str); + return E_FAIL; + } + len += size; + }else { + ++ptr; + ++len; + } + } + + out_ptr = ret = SysAllocStringLen(NULL, len); + if(!ret) { + SysFreeString(str); + return E_OUTOFMEMORY; + } + + ptr = str; + while(*ptr) { + if(*ptr == '%') { + char octets[4]; + unsigned char mask = 0x80; + int i, size, num_bytes = 0; + octets[0] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2)); + ptr += 3; + while(octets[0] & mask) { + mask = mask >> 1; + ++num_bytes; + } + for(i = 1; i < num_bytes; ++i) { + octets[i] = (hex_to_int(*(ptr+1)) << 4) + hex_to_int(*(ptr+2)); + ptr += 3; + } + size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, octets, + num_bytes ? num_bytes : 1, out_ptr, len); + len -= size; + out_ptr += size; + }else { + *out_ptr++ = *ptr++; + --len; + } + } + + SysFreeString(str); + + if(retv) { + V_VT(retv) = VT_BSTR; + V_BSTR(retv) = ret; + }else { + SysFreeString(ret); + } + + return S_OK; } static const builtin_prop_t JSGlobal_props[] = { diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js index 1fb2f6d8f98..42a79e8f71e 100644 --- a/dlls/jscript/tests/api.js +++ b/dlls/jscript/tests/api.js @@ -60,24 +60,44 @@ ok(tmp === "abc", "encodeURI('abc') = " + tmp); tmp = encodeURIComponent("abc"); ok(tmp === "abc", "encodeURIComponent('abc') = " + tmp); +dec = decodeURIComponent(tmp); +ok(dec === "abc", "decodeURIComponent('" + tmp + "') = " + dec); tmp = encodeURIComponent("{abc}"); ok(tmp === "%7Babc%7D", "encodeURIComponent('{abc}') = " + tmp); +dec = decodeURIComponent(tmp); +ok(dec === "{abc}", "decodeURIComponent('" + tmp + "') = " + dec); tmp = encodeURIComponent(""); ok(tmp === "", "encodeURIComponent('') = " + tmp); +dec = decodeURIComponent(tmp); +ok(dec === "", "decodeURIComponent('" + tmp + "') = " + dec); tmp = encodeURIComponent("\01\02\03\04"); ok(tmp === "%01%02%03%04", "encodeURIComponent('\\01\\02\\03\\04') = " + tmp); +dec = decodeURIComponent(tmp); +ok(dec === "\01\02\03\04", "decodeURIComponent('" + tmp + "') = " + dec); tmp = encodeURIComponent("{#@}"); ok(tmp === "%7B%23%40%7D", "encodeURIComponent('{#@}') = " + tmp); +dec = decodeURIComponent(tmp); +ok(dec === "{#@}", "decodeURIComponent('" + tmp + "') = " + dec); tmp = encodeURIComponent("\xa1 "); ok(tmp === "%C2%A1%20", "encodeURIComponent(\\xa1 ) = " + tmp); +dec = decodeURIComponent(tmp); +ok(dec === "\xa1 ", "decodeURIComponent('" + tmp + "') = " + dec); tmp = encodeURIComponent("\xffff"); ok(tmp.length === 8, "encodeURIComponent('\\xffff').length = " + tmp.length); +dec = decodeURIComponent(tmp); +ok(dec === "\xffff", "decodeURIComponent('" + tmp + "') = " + dec); tmp = encodeURIComponent("abcABC123;/?:@&=+$,-_.!~*'()"); ok(tmp === "abcABC123%3B%2F%3F%3A%40%26%3D%2B%24%2C-_.!~*'()", "encodeURIComponent('abcABC123;/?:@&=+$,-_.!~*'()') = " + tmp); +dec = decodeURIComponent(tmp); +ok(dec === "abcABC123;/?:@&=+$,-_.!~*'()", "decodeURIComponent('" + tmp + "') = " + dec); tmp = encodeURIComponent(); ok(tmp === "undefined", "encodeURIComponent() = " + tmp); tmp = encodeURIComponent("abc", "test"); ok(tmp === "abc", "encodeURIComponent('abc') = " + tmp); +dec = decodeURIComponent(); +ok(dec === "undefined", "decodeURIComponent() = " + dec); +dec = decodeURIComponent("abc", "test"); +ok(dec === "abc", "decodeURIComponent('abc') = " + dec); tmp = escape("abc"); ok(tmp === "abc", "escape('abc') = " + tmp); diff --git a/dlls/kernel32/file.c b/dlls/kernel32/file.c index e6d83bc7e90..8932dea1b33 100644 --- a/dlls/kernel32/file.c +++ b/dlls/kernel32/file.c @@ -821,6 +821,7 @@ BOOL WINAPI GetFileInformationByHandle( HANDLE hFile, BY_HANDLE_FILE_INFORMATION NTSTATUS status; status = NtQueryInformationFile( hFile, &io, &all_info, sizeof(all_info), FileAllInformation ); + if (status == STATUS_BUFFER_OVERFLOW) status = STATUS_SUCCESS; if (status == STATUS_SUCCESS) { info->dwFileAttributes = all_info.BasicInformation.FileAttributes; diff --git a/dlls/kernel32/file16.c b/dlls/kernel32/file16.c index 30c7bdd8163..e4f703daa6e 100644 --- a/dlls/kernel32/file16.c +++ b/dlls/kernel32/file16.c @@ -555,6 +555,7 @@ INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry, ret = GetPrivateProfileSectionA( section, data, size, filename ); if (!ret) { + if (len) *buffer = 0; HeapFree( GetProcessHeap(), 0, data ); return 0; } diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 7e278b59bd8..aad5e794964 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -236,7 +236,7 @@ @ stub CreateKernelThread @ stdcall CreateMailslotA(ptr long long ptr) @ stdcall CreateMailslotW(ptr long long ptr) -# @ stub CreateMemoryResourceNotification +@ stdcall CreateMemoryResourceNotification(long) @ stdcall CreateMutexA(ptr long str) @ stdcall CreateMutexExA(ptr str long long) @ stdcall CreateMutexExW(ptr wstr long long) diff --git a/dlls/kernel32/sync.c b/dlls/kernel32/sync.c index 8330d4a1de5..8918f3df2ae 100644 --- a/dlls/kernel32/sync.c +++ b/dlls/kernel32/sync.c @@ -2171,6 +2171,18 @@ BOOL WINAPI BindIoCompletionCallback( HANDLE FileHandle, LPOVERLAPPED_COMPLETION return FALSE; } + +/*********************************************************************** + * CreateMemoryResourceNotification (KERNEL32.@) + */ +HANDLE WINAPI CreateMemoryResourceNotification(MEMORY_RESOURCE_NOTIFICATION_TYPE nt) +{ + FIXME("(%d) stub\n", nt); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return NULL; +} + + #ifdef __i386__ /*********************************************************************** diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c index ec61659ad0b..3cc9022b32a 100644 --- a/dlls/kernel32/tests/file.c +++ b/dlls/kernel32/tests/file.c @@ -649,12 +649,10 @@ static void test_CopyFileA(void) ok(hmapfile != NULL, "CreateFileMapping: error %d\n", GetLastError()); ret = CopyFileA(source, dest, FALSE); - todo_wine { - ok(!ret, "CopyFileA: expected failure\n"); - ok(GetLastError() == ERROR_USER_MAPPED_FILE || - broken(GetLastError() == ERROR_SHARING_VIOLATION), /* Win9x and WinMe */ - "CopyFileA with mapped dest file: expected ERROR_USER_MAPPED_FILE, got %d\n", GetLastError()); - } + ok(!ret, "CopyFileA: expected failure\n"); + ok(GetLastError() == ERROR_USER_MAPPED_FILE || + broken(GetLastError() == ERROR_SHARING_VIOLATION), /* Win9x */ + "CopyFileA with mapped dest file: expected ERROR_USER_MAPPED_FILE, got %d\n", GetLastError()); CloseHandle(hmapfile); CloseHandle(hfile); @@ -1616,7 +1614,80 @@ static void test_LockFile(void) DeleteFileA( filename ); } -static inline int is_sharing_compatible( DWORD access1, DWORD sharing1, DWORD access2, DWORD sharing2, BOOL is_win9x ) +static BOOL create_fake_dll( LPCSTR filename ) +{ + IMAGE_DOS_HEADER *dos; + IMAGE_NT_HEADERS *nt; + IMAGE_SECTION_HEADER *sec; + BYTE *buffer; + DWORD lfanew = sizeof(*dos); + DWORD size = lfanew + sizeof(*nt) + sizeof(*sec); + DWORD written; + BOOL ret; + + HANDLE file = CreateFileA( filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + if (file == INVALID_HANDLE_VALUE) return FALSE; + + buffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ); + + dos = (IMAGE_DOS_HEADER *)buffer; + dos->e_magic = IMAGE_DOS_SIGNATURE; + dos->e_cblp = sizeof(*dos); + dos->e_cp = 1; + dos->e_cparhdr = lfanew / 16; + dos->e_minalloc = 0; + dos->e_maxalloc = 0xffff; + dos->e_ss = 0x0000; + dos->e_sp = 0x00b8; + dos->e_lfarlc = lfanew; + dos->e_lfanew = lfanew; + + nt = (IMAGE_NT_HEADERS *)(buffer + lfanew); + nt->Signature = IMAGE_NT_SIGNATURE; +#if defined __i386__ + nt->FileHeader.Machine = IMAGE_FILE_MACHINE_I386; +#elif defined __x86_64__ + nt->FileHeader.Machine = IMAGE_FILE_MACHINE_AMD64; +#elif defined __powerpc__ + nt->FileHeader.Machine = IMAGE_FILE_MACHINE_POWERPC; +#else +# error You must specify the machine type +#endif + nt->FileHeader.NumberOfSections = 1; + nt->FileHeader.SizeOfOptionalHeader = IMAGE_SIZEOF_NT_OPTIONAL_HEADER; + nt->FileHeader.Characteristics = IMAGE_FILE_DLL | IMAGE_FILE_EXECUTABLE_IMAGE; + nt->OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR_MAGIC; + nt->OptionalHeader.MajorLinkerVersion = 1; + nt->OptionalHeader.MinorLinkerVersion = 0; + nt->OptionalHeader.ImageBase = 0x10000000; + nt->OptionalHeader.SectionAlignment = 0x1000; + nt->OptionalHeader.FileAlignment = 0x1000; + nt->OptionalHeader.MajorOperatingSystemVersion = 1; + nt->OptionalHeader.MinorOperatingSystemVersion = 0; + nt->OptionalHeader.MajorImageVersion = 1; + nt->OptionalHeader.MinorImageVersion = 0; + nt->OptionalHeader.MajorSubsystemVersion = 4; + nt->OptionalHeader.MinorSubsystemVersion = 0; + nt->OptionalHeader.SizeOfImage = 0x2000; + nt->OptionalHeader.SizeOfHeaders = size; + nt->OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI; + nt->OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES; + + sec = (IMAGE_SECTION_HEADER *)(nt + 1); + memcpy( sec->Name, ".rodata", sizeof(".rodata") ); + sec->Misc.VirtualSize = 0x1000; + sec->VirtualAddress = 0x1000; + sec->SizeOfRawData = 0; + sec->PointerToRawData = 0; + sec->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; + + ret = WriteFile( file, buffer, size, &written, NULL ) && written == size; + HeapFree( GetProcessHeap(), 0, buffer ); + CloseHandle( file ); + return ret; +} + +static int is_sharing_compatible( DWORD access1, DWORD sharing1, DWORD access2, DWORD sharing2, BOOL is_win9x ) { if (!is_win9x) { @@ -1641,6 +1712,14 @@ static inline int is_sharing_compatible( DWORD access1, DWORD sharing1, DWORD ac return 1; } +static int is_sharing_map_compatible( DWORD map_access, DWORD access2, DWORD sharing2 ) +{ + if ((map_access == PAGE_READWRITE || map_access == PAGE_EXECUTE_READWRITE) && + !(sharing2 & FILE_SHARE_WRITE)) return 0; + if ((map_access & SEC_IMAGE) && (access2 & GENERIC_WRITE)) return 0; + return 1; +} + static void test_file_sharing(void) { static const DWORD access_modes[] = @@ -1651,20 +1730,20 @@ static void test_file_sharing(void) FILE_SHARE_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_SHARE_DELETE, FILE_SHARE_READ|FILE_SHARE_DELETE, FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE }; + static const DWORD mapping_modes[] = + { PAGE_READONLY, PAGE_WRITECOPY, PAGE_READWRITE, SEC_IMAGE | PAGE_WRITECOPY }; int a1, s1, a2, s2; int ret; HANDLE h, h2; BOOL is_win9x = FALSE; /* make sure the file exists */ - h = CreateFileA( filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 ); - if (h == INVALID_HANDLE_VALUE) + if (!create_fake_dll( filename )) { ok(0, "couldn't create file \"%s\" (err=%d)\n", filename, GetLastError()); return; } is_win9x = GetFileAttributesW(filenameW) == INVALID_FILE_ATTRIBUTES; - CloseHandle( h ); for (a1 = 0; a1 < sizeof(access_modes)/sizeof(access_modes[0]); a1++) { @@ -1693,12 +1772,10 @@ static void test_file_sharing(void) SetLastError(0xdeadbeef); h2 = CreateFileA( filename, access_modes[a2], sharing_modes[s2], NULL, OPEN_EXISTING, 0, 0 ); - + ret = GetLastError(); if (is_sharing_compatible( access_modes[a1], sharing_modes[s1], access_modes[a2], sharing_modes[s2], is_win9x )) { - ret = GetLastError(); - ok( h2 != INVALID_HANDLE_VALUE, "open failed for modes %x/%x/%x/%x\n", access_modes[a1], sharing_modes[s1], @@ -1706,13 +1783,9 @@ static void test_file_sharing(void) ok( ret == 0xdeadbeef /* Win9x */ || ret == 0, /* XP */ "wrong error code %d\n", ret ); - - CloseHandle( h2 ); } else { - ret = GetLastError(); - ok( h2 == INVALID_HANDLE_VALUE, "open succeeded for modes %x/%x/%x/%x\n", access_modes[a1], sharing_modes[s1], @@ -1720,12 +1793,107 @@ static void test_file_sharing(void) ok( ret == ERROR_SHARING_VIOLATION, "wrong error code %d\n", ret ); } + if (h2 != INVALID_HANDLE_VALUE) CloseHandle( h2 ); } } CloseHandle( h ); } } + for (a1 = 0; a1 < sizeof(mapping_modes)/sizeof(mapping_modes[0]); a1++) + { + HANDLE m; + + create_fake_dll( filename ); + SetLastError(0xdeadbeef); + h = CreateFileA( filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0 ); + if (h == INVALID_HANDLE_VALUE) + { + ok(0,"couldn't create file \"%s\" (err=%d)\n",filename,GetLastError()); + return; + } + m = CreateFileMappingA( h, NULL, mapping_modes[a1], 0, 0, NULL ); + ok( m != 0, "failed to create mapping %x err %u\n", mapping_modes[a1], GetLastError() ); + CloseHandle( h ); + if (!m) continue; + + for (a2 = 0; a2 < sizeof(access_modes)/sizeof(access_modes[0]); a2++) + { + for (s2 = 0; s2 < sizeof(sharing_modes)/sizeof(sharing_modes[0]); s2++) + { + /* Win9x doesn't support FILE_SHARE_DELETE */ + if (is_win9x && (sharing_modes[s2] & FILE_SHARE_DELETE)) + continue; + + SetLastError(0xdeadbeef); + h2 = CreateFileA( filename, access_modes[a2], sharing_modes[s2], + NULL, OPEN_EXISTING, 0, 0 ); + + ret = GetLastError(); + if (h2 == INVALID_HANDLE_VALUE) + { + if (is_sharing_map_compatible(mapping_modes[a1], access_modes[a2], sharing_modes[s2])) + ok( is_win9x, /* there's no sharing at all with a mapping on win9x */ + "open failed for modes map %x/%x/%x\n", + mapping_modes[a1], access_modes[a2], sharing_modes[s2] ); + ok( ret == ERROR_SHARING_VIOLATION, + "wrong error code %d\n", ret ); + } + else + { + if (!is_sharing_map_compatible(mapping_modes[a1], access_modes[a2], sharing_modes[s2])) + ok( broken(1), /* no checking on nt4 */ + "open succeeded for modes map %x/%x/%x\n", + mapping_modes[a1], access_modes[a2], sharing_modes[s2] ); + ok( ret == 0xdeadbeef /* Win9x */ || + ret == 0, /* XP */ + "wrong error code %d\n", ret ); + CloseHandle( h2 ); + } + } + } + + /* try CREATE_ALWAYS over an existing mapping */ + SetLastError(0xdeadbeef); + h2 = CreateFileA( filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, CREATE_ALWAYS, 0, 0 ); + ret = GetLastError(); + if ((mapping_modes[a1] & SEC_IMAGE) || is_win9x) + { + ok( h2 == INVALID_HANDLE_VALUE, "create succeeded for map %x\n", mapping_modes[a1] ); + ok( ret == ERROR_SHARING_VIOLATION, "wrong error code %d for %x\n", ret, mapping_modes[a1] ); + } + else + { + ok( h2 == INVALID_HANDLE_VALUE, "create succeeded for map %x\n", mapping_modes[a1] ); + ok( ret == ERROR_USER_MAPPED_FILE, "wrong error code %d for %x\n", ret, mapping_modes[a1] ); + } + if (h2 != INVALID_HANDLE_VALUE) CloseHandle( h2 ); + + /* try DELETE_ON_CLOSE over an existing mapping */ + SetLastError(0xdeadbeef); + h2 = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, 0 ); + ret = GetLastError(); + if (is_win9x) + { + ok( h2 == INVALID_HANDLE_VALUE, "create succeeded for map %x\n", mapping_modes[a1] ); + ok( ret == ERROR_SHARING_VIOLATION, "wrong error code %d for %x\n", ret, mapping_modes[a1] ); + } + else if (mapping_modes[a1] & SEC_IMAGE) + { + ok( h2 == INVALID_HANDLE_VALUE, "create succeeded for map %x\n", mapping_modes[a1] ); + ok( ret == ERROR_ACCESS_DENIED, "wrong error code %d for %x\n", ret, mapping_modes[a1] ); + } + else + { + ok( h2 != INVALID_HANDLE_VALUE, "open failed for map %x err %u\n", mapping_modes[a1], ret ); + } + if (h2 != INVALID_HANDLE_VALUE) CloseHandle( h2 ); + + CloseHandle( m ); + } + SetLastError(0xdeadbeef); h = CreateFileA( filename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, 0 ); ok( h != INVALID_HANDLE_VALUE, "CreateFileA error %d\n", GetLastError() ); diff --git a/dlls/kernel32/tests/volume.c b/dlls/kernel32/tests/volume.c index f569247a1c2..efd74d5abf2 100644 --- a/dlls/kernel32/tests/volume.c +++ b/dlls/kernel32/tests/volume.c @@ -155,8 +155,11 @@ static void test_GetVolumeNameForVolumeMountPointA(void) GetLastError()); /* Try on a arbitrary directory */ + /* On FAT filesystems it seems that GetLastError() is set to + ERROR_INVALID_FUNCTION. */ ret = pGetVolumeNameForVolumeMountPointA(temp_path, volume, len); - ok(ret == FALSE && GetLastError() == ERROR_NOT_A_REPARSE_POINT, + ok(ret == FALSE && (GetLastError() == ERROR_NOT_A_REPARSE_POINT || + GetLastError() == ERROR_INVALID_FUNCTION), "GetVolumeNameForVolumeMountPointA failed on %s, last=%d\n", temp_path, GetLastError()); diff --git a/dlls/mountmgr.sys/mountmgr.c b/dlls/mountmgr.sys/mountmgr.c index a80d4924ebf..7056ef406d0 100644 --- a/dlls/mountmgr.sys/mountmgr.c +++ b/dlls/mountmgr.sys/mountmgr.c @@ -400,10 +400,14 @@ NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path ) static const WCHAR device_mountmgrW[] = {'\\','D','e','v','i','c','e','\\','M','o','u','n','t','P','o','i','n','t','M','a','n','a','g','e','r',0}; static const WCHAR link_mountmgrW[] = {'\\','?','?','\\','M','o','u','n','t','P','o','i','n','t','M','a','n','a','g','e','r',0}; static const WCHAR harddiskW[] = {'\\','D','r','i','v','e','r','\\','H','a','r','d','d','i','s','k',0}; + static const WCHAR devicemapW[] = {'H','A','R','D','W','A','R','E','\\','D','E','V','I','C','E','M','A','P',0}; + static const WCHAR parallelW[] = {'P','A','R','A','L','L','E','L',' ','P','O','R','T','S',0}; + static const WCHAR serialW[] = {'S','E','R','I','A','L','C','O','M','M',0}; UNICODE_STRING nameW, linkW; DEVICE_OBJECT *device; NTSTATUS status; + HKEY hkey, devicemap_key; TRACE( "%s\n", debugstr_w(path->Buffer) ); @@ -422,6 +426,18 @@ NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path ) RegCreateKeyExW( HKEY_LOCAL_MACHINE, mounted_devicesW, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &mount_key, NULL ); + if (!RegCreateKeyExW( HKEY_LOCAL_MACHINE, devicemapW, 0, NULL, REG_OPTION_VOLATILE, + KEY_ALL_ACCESS, NULL, &devicemap_key, NULL )) + { + if (!RegCreateKeyExW( devicemap_key, parallelW, 0, NULL, REG_OPTION_VOLATILE, + KEY_ALL_ACCESS, NULL, &hkey, NULL )) + RegCloseKey( hkey ); + if (!RegCreateKeyExW( devicemap_key, serialW, 0, NULL, REG_OPTION_VOLATILE, + KEY_ALL_ACCESS, NULL, &hkey, NULL )) + RegCloseKey( hkey ); + RegCloseKey( devicemap_key ); + } + RtlInitUnicodeString( &nameW, harddiskW ); status = IoCreateDriver( &nameW, harddisk_driver_entry ); diff --git a/dlls/msdaps/usrmarshal.c b/dlls/msdaps/usrmarshal.c index 8e158626083..0624c3a5315 100644 --- a/dlls/msdaps/usrmarshal.c +++ b/dlls/msdaps/usrmarshal.c @@ -122,6 +122,7 @@ HRESULT __RPC_STUB IDBProperties_GetProperties_Stub(IDBProperties* This, ULONG c TRACE("(%p, %d, %p, %p, %p, %p)\n", This, cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets, ppErrorInfoRem); + *pcPropertySets = 0; *ppErrorInfoRem = NULL; hr = IDBProperties_GetProperties(This, cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets); diff --git a/dlls/mshtml/De.rc b/dlls/mshtml/De.rc index 2b58b41affb..50d519d70a7 100644 --- a/dlls/mshtml/De.rc +++ b/dlls/mshtml/De.rc @@ -37,9 +37,11 @@ STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMEN CAPTION "Wine-Gecko-Installation" FONT 8, "MS Shell Dlg" { - LTEXT "Wine could not find a Gecko package which is needed for applications embedding HTML " \ - "to work correctly. Wine can automatically download and install it for you.\n\n" \ - "Note: it's recommended to use distro packages instead. See http://wiki.winehq.org/Gecko for details.", + LTEXT "Wine kann das Gecko-Paket nicht finden. Es wird von Programmen mit eingebettetem HTML benötigt, " \ + "damit diese richtig funktionieren.\n" \ + "Wine kann das Paket für Sie herunterladen und installieren.\n\n" \ + "Hinweis: Es wird empfohlen das Paket ihrer Distribution zu verwenden. " \ + "Weitere Hinweise finden Sie unter http://wiki.winehq.org/Gecko", ID_DWL_STATUS, 10, 10, 240, 50, SS_LEFT CONTROL "Fortschritt", ID_DWL_PROGRESS, PROGRESS_CLASSA, WS_BORDER|PBS_SMOOTH, 10, 50, 240, 12 DEFPUSHBUTTON "&Installieren", ID_DWL_INSTALL, 200, 70, 50, 15, WS_GROUP | WS_TABSTOP diff --git a/dlls/mshtml/Lt.rc b/dlls/mshtml/Lt.rc index 9883bb4cfb5..8f7e772a3a7 100644 --- a/dlls/mshtml/Lt.rc +++ b/dlls/mshtml/Lt.rc @@ -31,18 +31,18 @@ STRINGTABLE DISCARDABLE IDS_INSTALLING "Įdiegiama..." } -ID_DWL_DIALOG DIALOG LOADONCALL MOVEABLE DISCARDABLE 0, 0, 260, 95 +ID_DWL_DIALOG DIALOG LOADONCALL MOVEABLE DISCARDABLE 0, 0, 260, 105 STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "Wine Gecko diegimo programa" FONT 8, "MS Shell Dlg" { - LTEXT "Wine could not find a Gecko package which is needed for applications embedding HTML " \ - "to work correctly. Wine can automatically download and install it for you.\n\n" \ - "Note: it's recommended to use distro packages instead. See http://wiki.winehq.org/Gecko for details.", + LTEXT "Wine nepavyko rasti Gecko paketo reikalingo programoms įterpiančioms HTML " \ + "teisingai veikti. Wine gali automatiškai atsiųsti ir įdiegti šį paketą.\n\n" \ + "Pastaba: rekomenduojama naudoti distribucijos paketus. Daugiau informacijos http://wiki.winehq.org/Gecko.", ID_DWL_STATUS, 10, 10, 240, 50, SS_LEFT - CONTROL "Eiga", ID_DWL_PROGRESS, PROGRESS_CLASSA, WS_BORDER|PBS_SMOOTH, 10, 40, 240, 12 - DEFPUSHBUTTON "&Įdiegti", ID_DWL_INSTALL, 200, 70, 50, 15, WS_GROUP | WS_TABSTOP - PUSHBUTTON "&Atsisakyti", IDCANCEL, 140, 70, 50, 15, WS_GROUP | WS_TABSTOP + CONTROL "Eiga", ID_DWL_PROGRESS, PROGRESS_CLASSA, WS_BORDER|PBS_SMOOTH, 10, 60, 240, 12 + DEFPUSHBUTTON "&Įdiegti", ID_DWL_INSTALL, 200, 80, 50, 15, WS_GROUP | WS_TABSTOP + PUSHBUTTON "&Atsisakyti", IDCANCEL, 140, 80, 50, 15, WS_GROUP | WS_TABSTOP } IDD_HYPERLINK DIALOG LOADONCALL MOVEABLE DISCARDABLE 0, 0, 250, 65 diff --git a/dlls/mshtml/Ru.rc b/dlls/mshtml/Ru.rc index 02bc433c767..8d3a4c3cc0a 100644 --- a/dlls/mshtml/Ru.rc +++ b/dlls/mshtml/Ru.rc @@ -31,18 +31,18 @@ STRINGTABLE DISCARDABLE IDS_INSTALLING "Установка..." } -ID_DWL_DIALOG DIALOG LOADONCALL MOVEABLE DISCARDABLE 0, 0, 261, 95 +ID_DWL_DIALOG DIALOG LOADONCALL MOVEABLE DISCARDABLE 0, 0, 261, 110 STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "Установка Wine Gecko" FONT 8, "MS Shell Dlg" { - LTEXT "Wine could not find a Gecko package which is needed for applications embedding HTML " \ - "to work correctly. Wine can automatically download and install it for you.\n\n" \ - "Note: it's recommended to use distro packages instead. See http://wiki.winehq.org/Gecko for details.", + LTEXT "Wine не может найти пакет Gecko который нужен для приложений со встроенным HTML " \ + "для корректной работы. Wine может автоматически загрузить и установить его для Вас.\n\n" \ + "Примечание: Рекомендовано использовать пакет из Вашего дистрибутива. Посетите http://wiki.winehq.org/Gecko для деталей.", ID_DWL_STATUS, 10, 10, 240, 50, SS_LEFT - CONTROL "Прогресс", ID_DWL_PROGRESS, PROGRESS_CLASSA, WS_BORDER|PBS_SMOOTH, 10, 46, 240, 12 - DEFPUSHBUTTON "&Установить", ID_DWL_INSTALL, 200, 70, 50, 15, WS_GROUP | WS_TABSTOP - PUSHBUTTON "&Отмена", IDCANCEL, 140, 63, 70, 15, WS_GROUP | WS_TABSTOP + CONTROL "Прогресс", ID_DWL_PROGRESS, PROGRESS_CLASSA, WS_BORDER|PBS_SMOOTH, 10, 65, 240, 12 + DEFPUSHBUTTON "&Установить", ID_DWL_INSTALL, 180, 85, 70, 15, WS_GROUP | WS_TABSTOP + PUSHBUTTON "&Отмена", IDCANCEL, 100, 85, 70, 15, WS_GROUP | WS_TABSTOP } IDD_HYPERLINK DIALOG LOADONCALL MOVEABLE DISCARDABLE 0, 0, 250, 65 @@ -58,3 +58,14 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "OK", IDOK, 200, 10, 45, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP PUSHBUTTON "Отмена", IDCANCEL, 200, 28, 45, 14, WS_GROUP | WS_TABSTOP } + +ID_PROMPT_DIALOG DIALOG 0, 0, 200, 90 +STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "" +FONT 8, "MS Shell Dlg" +{ + LTEXT "", ID_PROMPT_PROMPT, 10, 10, 180, 30 + EDITTEXT ID_PROMPT_EDIT, 10, 45, 180, 14, ES_AUTOHSCROLL | WS_BORDER | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 40, 65, 45, 15, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP + PUSHBUTTON "Отмена", IDCANCEL, 115, 65, 45, 15, WS_GROUP | WS_TABSTOP +} diff --git a/dlls/mshtml/Sv.rc b/dlls/mshtml/Sv.rc index e9ba10e7975..c5a2cc8c383 100644 --- a/dlls/mshtml/Sv.rc +++ b/dlls/mshtml/Sv.rc @@ -33,9 +33,9 @@ STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMEN CAPTION "Wine Gecko Installationsprogram" FONT 8, "MS Shell Dlg" { - LTEXT "Wine could not find a Gecko package which is needed for applications embedding HTML " \ - "to work correctly. Wine can automatically download and install it for you.\n\n" \ - "Note: it's recommended to use distro packages instead. See http://wiki.winehq.org/Gecko for details.", + LTEXT "Wine kunde inte hitta paketet Gecko vilket krävs för att program med inbäddad HTML " \ + "ska fungera korrekt. Wine kan hämta och installera det automatiskt åt dig.\n\n" \ + "Obs: Du rekommenderas att använda din distributions paket i stället. Se http://wiki.winehq.org/Gecko för mer information.", ID_DWL_STATUS, 10, 10, 240, 50, SS_LEFT CONTROL "Förlopp", ID_DWL_PROGRESS, PROGRESS_CLASSA, WS_BORDER|PBS_SMOOTH, 10, 40, 240, 12 DEFPUSHBUTTON "&Installera", ID_DWL_INSTALL, 200, 70, 50, 15, WS_GROUP | WS_TABSTOP diff --git a/dlls/mshtml/conpoint.c b/dlls/mshtml/conpoint.c index 10d8e291bf4..0f4960136fb 100644 --- a/dlls/mshtml/conpoint.c +++ b/dlls/mshtml/conpoint.c @@ -198,7 +198,7 @@ static const IConnectionPointVtbl ConnectionPointVtbl = ConnectionPoint_EnumConnections }; -void ConnectionPoint_Init(ConnectionPoint *cp, ConnectionPointContainer *container, REFIID riid) +void ConnectionPoint_Init(ConnectionPoint *cp, ConnectionPointContainer *container, REFIID riid, cp_static_data_t *data) { cp->lpConnectionPointVtbl = &ConnectionPointVtbl; cp->container = CONPTCONT(container); @@ -206,6 +206,7 @@ void ConnectionPoint_Init(ConnectionPoint *cp, ConnectionPointContainer *contain cp->sinks_size = 0; cp->iid = riid; cp->next = NULL; + cp->data = data; cp->next = container->cp_list; container->cp_list = cp; @@ -260,6 +261,9 @@ static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPo TRACE("(%p)->(%s %p)\n", This, debugstr_cp_guid(riid), ppCP); + if(This->forward_container) + return IConnectionPointContainer_FindConnectionPoint(CONPTCONT(This), riid, ppCP); + *ppCP = NULL; for(iter = This->cp_list; iter; iter = iter->next) { diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 980b13b1654..f93fc8c1a23 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -103,6 +103,7 @@ static REFIID tid_ids[] = { &DIID_DispHTMLTableRow, &DIID_DispHTMLUnknownElement, &DIID_DispHTMLWindow2, + &DIID_HTMLDocumentEvents, &IID_IHTMLAnchorElement, &IID_IHTMLBodyElement, &IID_IHTMLBodyElement2, @@ -144,6 +145,7 @@ static REFIID tid_ids[] = { &IID_IHTMLUniqueName, &IID_IHTMLWindow2, &IID_IHTMLWindow3, + &IID_IHTMLWindow4, &IID_IOmNavigator }; @@ -303,6 +305,61 @@ static dispex_data_t *preprocess_dispex_data(DispatchEx *This) return data; } +static int id_cmp(const void *p1, const void *p2) +{ + return *(DISPID*)p1 - *(DISPID*)p2; +} + +HRESULT get_dispids(tid_t tid, DWORD *ret_size, DISPID **ret) +{ + unsigned i, func_cnt; + FUNCDESC *funcdesc; + ITypeInfo *ti; + TYPEATTR *attr; + DISPID *ids; + HRESULT hres; + + hres = get_typeinfo(tid, &ti); + if(FAILED(hres)) + return hres; + + hres = ITypeInfo_GetTypeAttr(ti, &attr); + if(FAILED(hres)) { + ITypeInfo_Release(ti); + return hres; + } + + func_cnt = attr->cFuncs; + ITypeInfo_ReleaseTypeAttr(ti, attr); + + ids = heap_alloc(func_cnt*sizeof(DISPID)); + if(!ids) { + ITypeInfo_Release(ti); + return E_OUTOFMEMORY; + } + + for(i=0; i < func_cnt; i++) { + hres = ITypeInfo_GetFuncDesc(ti, i, &funcdesc); + if(FAILED(hres)) + break; + + ids[i] = funcdesc->memid; + ITypeInfo_ReleaseFuncDesc(ti, funcdesc); + } + + ITypeInfo_Release(ti); + if(FAILED(hres)) { + heap_free(ids); + return hres; + } + + qsort(ids, func_cnt, sizeof(DISPID), id_cmp); + + *ret_size = func_cnt; + *ret = ids; + return S_OK; +} + static CRITICAL_SECTION cs_dispex_static_data; static CRITICAL_SECTION_DEBUG cs_dispex_static_data_dbg = { diff --git a/dlls/mshtml/htmlanchor.c b/dlls/mshtml/htmlanchor.c index 04960d90337..6bbaf26dfae 100644 --- a/dlls/mshtml/htmlanchor.c +++ b/dlls/mshtml/htmlanchor.c @@ -313,43 +313,55 @@ static HRESULT WINAPI HTMLAnchorElement_get_hash(IHTMLAnchorElement *iface, BSTR static HRESULT WINAPI HTMLAnchorElement_put_onblur(IHTMLAnchorElement *iface, VARIANT v) { HTMLAnchorElement *This = HTMLANCHOR_THIS(iface); - FIXME("(%p)->()\n", This); - return E_NOTIMPL; + + TRACE("(%p)->()\n", This); + + return IHTMLElement2_put_onblur(HTMLELEM2(&This->element), v); } static HRESULT WINAPI HTMLAnchorElement_get_onblur(IHTMLAnchorElement *iface, VARIANT *p) { HTMLAnchorElement *This = HTMLANCHOR_THIS(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, p); + + return IHTMLElement2_get_onblur(HTMLELEM2(&This->element), p); } static HRESULT WINAPI HTMLAnchorElement_put_onfocus(IHTMLAnchorElement *iface, VARIANT v) { HTMLAnchorElement *This = HTMLANCHOR_THIS(iface); - FIXME("(%p)->()\n", This); - return E_NOTIMPL; + + TRACE("(%p)->()\n", This); + + return IHTMLElement2_put_onfocus(HTMLELEM2(&This->element), v); } static HRESULT WINAPI HTMLAnchorElement_get_onfocus(IHTMLAnchorElement *iface, VARIANT *p) { HTMLAnchorElement *This = HTMLANCHOR_THIS(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, p); + + return IHTMLElement2_get_onfocus(HTMLELEM2(&This->element), p); } static HRESULT WINAPI HTMLAnchorElement_put_accessKey(IHTMLAnchorElement *iface, BSTR v) { HTMLAnchorElement *This = HTMLANCHOR_THIS(iface); - FIXME("(%p)->(%s)\n", This, debugstr_w(v)); - return E_NOTIMPL; + + TRACE("(%p)->(%s)\n", This, debugstr_w(v)); + + return IHTMLElement2_put_accessKey(HTMLELEM2(&This->element), v); } static HRESULT WINAPI HTMLAnchorElement_get_accessKey(IHTMLAnchorElement *iface, BSTR *p) { HTMLAnchorElement *This = HTMLANCHOR_THIS(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, p); + + return IHTMLElement2_get_accessKey(HTMLELEM2(&This->element), p); } static HRESULT WINAPI HTMLAnchorElement_get_protocolLong(IHTMLAnchorElement *iface, BSTR *p) @@ -376,29 +388,37 @@ static HRESULT WINAPI HTMLAnchorElement_get_nameProp(IHTMLAnchorElement *iface, static HRESULT WINAPI HTMLAnchorElement_put_tabIndex(IHTMLAnchorElement *iface, short v) { HTMLAnchorElement *This = HTMLANCHOR_THIS(iface); - FIXME("(%p)->()\n", This); - return E_NOTIMPL; + + TRACE("(%p)->()\n", This); + + return IHTMLElement2_put_tabIndex(HTMLELEM2(&This->element), v); } static HRESULT WINAPI HTMLAnchorElement_get_tabIndex(IHTMLAnchorElement *iface, short *p) { HTMLAnchorElement *This = HTMLANCHOR_THIS(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, p); + + return IHTMLElement2_get_tabIndex(HTMLELEM2(&This->element), p); } static HRESULT WINAPI HTMLAnchorElement_focus(IHTMLAnchorElement *iface) { HTMLAnchorElement *This = HTMLANCHOR_THIS(iface); - FIXME("(%p)\n", This); - return E_NOTIMPL; + + TRACE("(%p)\n", This); + + return IHTMLElement2_focus(HTMLELEM2(&This->element)); } static HRESULT WINAPI HTMLAnchorElement_blur(IHTMLAnchorElement *iface) { HTMLAnchorElement *This = HTMLANCHOR_THIS(iface); - FIXME("(%p)\n", This); - return E_NOTIMPL; + + TRACE("(%p)\n", This); + + return IHTMLElement2_blur(HTMLELEM2(&This->element)); } #undef HTMLANCHOR_THIS diff --git a/dlls/mshtml/htmlbody.c b/dlls/mshtml/htmlbody.c index 4da3373eba1..427444e01fe 100644 --- a/dlls/mshtml/htmlbody.c +++ b/dlls/mshtml/htmlbody.c @@ -771,7 +771,7 @@ HTMLElement *HTMLBodyElement_Create(HTMLDocumentNode *doc, nsIDOMHTMLElement *ns HTMLTextContainer_Init(&ret->textcont, doc, nselem, &HTMLBodyElement_dispex); - ConnectionPoint_Init(&ret->cp_propnotif, &ret->textcont.element.cp_container, &IID_IPropertyNotifySink); + ConnectionPoint_Init(&ret->cp_propnotif, &ret->textcont.element.cp_container, &IID_IPropertyNotifySink, NULL); nsres = nsIDOMHTMLElement_QueryInterface(nselem, &IID_nsIDOMHTMLBodyElement, (void**)&ret->nsbody); diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index 836f1aee4b3..e746fb0bf71 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -1706,6 +1706,8 @@ static BOOL htmldoc_qi(HTMLDocument *This, REFIID riid, void **ppv) return TRUE; } +static cp_static_data_t HTMLDocumentEvents_data = { HTMLDocumentEvents_tid }; + static void init_doc(HTMLDocument *doc, IUnknown *unk_impl, IDispatchEx *dispex) { doc->lpHTMLDocument2Vtbl = &HTMLDocumentVtbl; @@ -1727,9 +1729,9 @@ static void init_doc(HTMLDocument *doc, IUnknown *unk_impl, IDispatchEx *dispex) HTMLDocument_Hlink_Init(doc); ConnectionPointContainer_Init(&doc->cp_container, (IUnknown*)HTMLDOC(doc)); - ConnectionPoint_Init(&doc->cp_propnotif, &doc->cp_container, &IID_IPropertyNotifySink); - ConnectionPoint_Init(&doc->cp_htmldocevents, &doc->cp_container, &DIID_HTMLDocumentEvents); - ConnectionPoint_Init(&doc->cp_htmldocevents2, &doc->cp_container, &DIID_HTMLDocumentEvents2); + ConnectionPoint_Init(&doc->cp_propnotif, &doc->cp_container, &IID_IPropertyNotifySink, NULL); + ConnectionPoint_Init(&doc->cp_htmldocevents, &doc->cp_container, &DIID_HTMLDocumentEvents, &HTMLDocumentEvents_data); + ConnectionPoint_Init(&doc->cp_htmldocevents2, &doc->cp_container, &DIID_HTMLDocumentEvents2, NULL); } static void destroy_htmldoc(HTMLDocument *This) @@ -1765,6 +1767,8 @@ static void HTMLDocumentNode_destructor(HTMLDOMNode *iface) if(This->nsevent_listener) release_nsevents(This); + if(This->catmgr) + ICatInformation_Release(This->catmgr); if(This->secmgr) IInternetSecurityManager_Release(This->secmgr); @@ -1823,6 +1827,8 @@ HRESULT create_doc_from_nsdoc(nsIDOMHTMLDocument *nsdoc, HTMLDocumentObj *doc_ob doc->ref = 1; doc->basedoc.window = window; + if(window == doc_obj->basedoc.window) + doc->basedoc.cp_container.forward_container = &doc_obj->basedoc.cp_container; nsIDOMHTMLDocument_AddRef(nsdoc); doc->nsdoc = nsdoc; @@ -1835,6 +1841,7 @@ HRESULT create_doc_from_nsdoc(nsIDOMHTMLDocument *nsdoc, HTMLDocumentObj *doc_ob HTMLDOMNode_Init(doc, &doc->node, (nsIDOMNode*)nsdoc); doc->node.vtbl = &HTMLDocumentNodeImplVtbl; + doc->node.cp_container = &doc->basedoc.cp_container; hres = CoInternetCreateSecurityManager(NULL, &doc->secmgr, 0); if(FAILED(hres)) { diff --git a/dlls/mshtml/htmldoc3.c b/dlls/mshtml/htmldoc3.c index a00fa95b21b..b930d882344 100644 --- a/dlls/mshtml/htmldoc3.c +++ b/dlls/mshtml/htmldoc3.c @@ -431,6 +431,8 @@ static HRESULT WINAPI HTMLDocument3_getElementById(IHTMLDocument3 *iface, BSTR v HTMLDocument *This = HTMLDOC3_THIS(iface); nsIDOMElement *nselem; HTMLDOMNode *node; + nsIDOMNode *nsnode, *nsnode_by_id, *nsnode_by_name; + nsIDOMNodeList *nsnode_list; nsAString id_str; nsresult nsres; @@ -442,16 +444,64 @@ static HRESULT WINAPI HTMLDocument3_getElementById(IHTMLDocument3 *iface, BSTR v } nsAString_Init(&id_str, v); + /* get element by id attribute */ nsres = nsIDOMHTMLDocument_GetElementById(This->doc_node->nsdoc, &id_str, &nselem); - nsAString_Finish(&id_str); if(FAILED(nsres)) { ERR("GetElementById failed: %08x\n", nsres); + nsAString_Finish(&id_str); return E_FAIL; } + nsnode_by_id = (nsIDOMNode*)nselem; - if(nselem) { - node = get_node(This->doc_node, (nsIDOMNode*)nselem, TRUE); - nsIDOMElement_Release(nselem); + /* get first element by name attribute */ + nsres = nsIDOMHTMLDocument_GetElementsByName(This->doc_node->nsdoc, &id_str, &nsnode_list); + if(FAILED(nsres)) { + ERR("getElementsByName failed: %08x\n", nsres); + nsAString_Finish(&id_str); + if(nsnode_by_id) + nsIDOMNode_Release(nsnode_by_id); + return E_FAIL; + } + nsIDOMNodeList_Item(nsnode_list, 0, &nsnode_by_name); + nsIDOMNodeList_Release(nsnode_list); + + nsAString_Finish(&id_str); + + if(nsnode_by_name && nsnode_by_id) { + nsIDOM3Node *node3; + PRUint16 pos; + + nsres = nsIDOMNode_QueryInterface(nsnode_by_name, &IID_nsIDOM3Node, (void**)&node3); + if(NS_FAILED(nsres)) { + FIXME("failed to get nsIDOM3Node interface: 0x%08x\n", nsres); + nsIDOMNode_Release(nsnode_by_name); + nsIDOMNode_Release(nsnode_by_id); + return E_FAIL; + } + + nsres = nsIDOM3Node_CompareDocumentPosition(node3, nsnode_by_id, &pos); + nsIDOM3Node_Release(node3); + if(NS_FAILED(nsres)) { + FIXME("nsIDOM3Node_CompareDocumentPosition failed: 0x%08x\n", nsres); + nsIDOMNode_Release(nsnode_by_name); + nsIDOMNode_Release(nsnode_by_id); + return E_FAIL; + } + + TRACE("CompareDocumentPosition gave: 0x%x\n", pos); + if(pos & PRECEDING || pos & CONTAINS) { + nsnode = nsnode_by_id; + nsIDOMNode_Release(nsnode_by_name); + }else { + nsnode = nsnode_by_name; + nsIDOMNode_Release(nsnode_by_id); + } + }else + nsnode = nsnode_by_name ? nsnode_by_name : nsnode_by_id; + + if(nsnode) { + node = get_node(This->doc_node, nsnode, TRUE); + nsIDOMNode_Release(nsnode); IHTMLDOMNode_QueryInterface(HTMLDOMNODE(node), &IID_IHTMLElement, (void**)pel); }else { diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index b794b73288a..0864e49a7cd 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -908,8 +908,63 @@ static HRESULT WINAPI HTMLElement_get_innerText(IHTMLElement *iface, BSTR *p) static HRESULT WINAPI HTMLElement_put_outerHTML(IHTMLElement *iface, BSTR v) { HTMLElement *This = HTMLELEM_THIS(iface); - FIXME("(%p)->(%s)\n", This, debugstr_w(v)); - return E_NOTIMPL; + nsIDOMDocumentFragment *nsfragment; + nsIDOMDocumentRange *nsdocrange; + nsIDOMNSRange *nsrange; + nsIDOMNode *nsparent; + nsIDOMRange *range; + nsAString html_str; + nsresult nsres; + HRESULT hres = S_OK; + + TRACE("(%p)->(%s)\n", This, debugstr_w(v)); + + nsres = nsIDOMHTMLDocument_QueryInterface(This->node.doc->nsdoc, &IID_nsIDOMDocumentRange, (void**)&nsdocrange); + if(NS_FAILED(nsres)) + return E_FAIL; + + nsres = nsIDOMDocumentRange_CreateRange(nsdocrange, &range); + nsIDOMDocumentRange_Release(nsdocrange); + if(NS_FAILED(nsres)) { + ERR("CreateRange failed: %08x\n", nsres); + return E_FAIL; + } + + nsres = nsIDOMRange_QueryInterface(range, &IID_nsIDOMNSRange, (void**)&nsrange); + nsIDOMRange_Release(range); + if(NS_FAILED(nsres)) { + ERR("Could not get nsIDOMNSRange: %08x\n", nsres); + return E_FAIL; + } + + nsAString_Init(&html_str, v); + nsIDOMNSRange_CreateContextualFragment(nsrange, &html_str, &nsfragment); + nsIDOMNSRange_Release(nsrange); + nsAString_Finish(&html_str); + if(NS_FAILED(nsres)) { + ERR("CreateContextualFragment failed: %08x\n", nsres); + return E_FAIL; + } + + nsres = nsIDOMNode_GetParentNode(This->node.nsnode, &nsparent); + if(NS_SUCCEEDED(nsres) && nsparent) { + nsIDOMNode *nstmp; + + nsres = nsIDOMNode_ReplaceChild(nsparent, (nsIDOMNode*)nsfragment, This->node.nsnode, &nstmp); + nsIDOMNode_Release(nsparent); + if(NS_FAILED(nsres)) { + ERR("ReplaceChild failed: %08x\n", nsres); + hres = E_FAIL; + }else if(nstmp) { + nsIDOMNode_Release(nstmp); + } + }else { + ERR("GetParentNode failed: %08x\n", nsres); + hres = E_FAIL; + } + + nsIDOMDocumentFragment_Release(nsfragment); + return hres; } static HRESULT WINAPI HTMLElement_get_outerHTML(IHTMLElement *iface, BSTR *p) @@ -959,19 +1014,13 @@ static HRESULT HTMLElement_InsertAdjacentNode(HTMLElement *This, BSTR where, nsI static const WCHAR wszAfterEnd[] = {'a','f','t','e','r','E','n','d',0}; nsresult nsres; - if(!This->nselem) { - FIXME("NULL nselem\n"); - return E_NOTIMPL; - } - if (!strcmpiW(where, wszBeforeBegin)) { nsIDOMNode *unused; nsIDOMNode *parent; - nsres = nsIDOMNode_GetParentNode(This->nselem, &parent); + nsres = nsIDOMNode_GetParentNode(This->node.nsnode, &parent); if (!parent) return E_INVALIDARG; - nsres = nsIDOMNode_InsertBefore(parent, nsnode, - (nsIDOMNode *)This->nselem, &unused); + nsres = nsIDOMNode_InsertBefore(parent, nsnode, This->node.nsnode, &unused); if (unused) nsIDOMNode_Release(unused); nsIDOMNode_Release(parent); } @@ -979,15 +1028,15 @@ static HRESULT HTMLElement_InsertAdjacentNode(HTMLElement *This, BSTR where, nsI { nsIDOMNode *unused; nsIDOMNode *first_child; - nsIDOMNode_GetFirstChild(This->nselem, &first_child); - nsres = nsIDOMNode_InsertBefore(This->nselem, nsnode, first_child, &unused); + nsIDOMNode_GetFirstChild(This->node.nsnode, &first_child); + nsres = nsIDOMNode_InsertBefore(This->node.nsnode, nsnode, first_child, &unused); if (unused) nsIDOMNode_Release(unused); if (first_child) nsIDOMNode_Release(first_child); } else if (!strcmpiW(where, wszBeforeEnd)) { nsIDOMNode *unused; - nsres = nsIDOMNode_AppendChild(This->nselem, nsnode, &unused); + nsres = nsIDOMNode_AppendChild(This->node.nsnode, nsnode, &unused); if (unused) nsIDOMNode_Release(unused); } else if (!strcmpiW(where, wszAfterEnd)) @@ -995,10 +1044,10 @@ static HRESULT HTMLElement_InsertAdjacentNode(HTMLElement *This, BSTR where, nsI nsIDOMNode *unused; nsIDOMNode *next_sibling; nsIDOMNode *parent; - nsIDOMNode_GetParentNode(This->nselem, &parent); + nsIDOMNode_GetParentNode(This->node.nsnode, &parent); if (!parent) return E_INVALIDARG; - nsIDOMNode_GetNextSibling(This->nselem, &next_sibling); + nsIDOMNode_GetNextSibling(This->node.nsnode, &next_sibling); if (next_sibling) { nsres = nsIDOMNode_InsertBefore(parent, nsnode, next_sibling, &unused); @@ -1054,7 +1103,7 @@ static HRESULT WINAPI HTMLElement_insertAdjacentHTML(IHTMLElement *iface, BSTR w return E_FAIL; } - nsIDOMRange_SetStartBefore(range, (nsIDOMNode *)This->nselem); + nsIDOMRange_SetStartBefore(range, This->node.nsnode); nsIDOMRange_QueryInterface(range, &IID_nsIDOMNSRange, (void **)&nsrange); nsIDOMRange_Release(range); diff --git a/dlls/mshtml/htmlelemcol.c b/dlls/mshtml/htmlelemcol.c index 70827bcd8e9..c9737077382 100644 --- a/dlls/mshtml/htmlelemcol.c +++ b/dlls/mshtml/htmlelemcol.c @@ -205,6 +205,26 @@ static HRESULT WINAPI HTMLElementCollection_get__newEnum(IHTMLElementCollection return E_NOTIMPL; } +static BOOL is_elem_id(HTMLElement *elem, LPCWSTR name) +{ + BSTR elem_id; + HRESULT hres; + + hres = IHTMLElement_get_id(HTMLELEM(elem), &elem_id); + if(FAILED(hres)){ + WARN("IHTMLElement_get_id failed: 0x%08x\n", hres); + return FALSE; + } + + if(elem_id && !strcmpW(elem_id, name)) { + SysFreeString(elem_id); + return TRUE; + } + + SysFreeString(elem_id); + return FALSE; +} + static BOOL is_elem_name(HTMLElement *elem, LPCWSTR name) { const PRUnichar *str; @@ -376,7 +396,16 @@ static HRESULT HTMLElementCollection_get_dispid(IUnknown *iface, BSTR name, DWOR for(ptr = name; *ptr && isdigitW(*ptr); ptr++) idx = idx*10 + (*ptr-'0'); - if(*ptr || idx >= This->len) + if(*ptr) { + /* the name contains alpha characters, so search by name & id */ + for(idx = 0; idx < This->len; ++idx) { + if(is_elem_id(This->elems[idx], name) || + is_elem_name(This->elems[idx], name)) + break; + } + } + + if(idx >= This->len) return DISP_E_UNKNOWNNAME; *dispid = DISPID_ELEMCOL_0 + idx; diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index 345fd839aac..af1327cf0aa 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -24,6 +24,7 @@ #include "winbase.h" #include "winuser.h" #include "ole2.h" +#include "mshtmdid.h" #include "mshtml_private.h" #include "htmlevent.h" @@ -118,6 +119,7 @@ typedef struct { LPCWSTR name; LPCWSTR attr_name; DWORD type; + DISPID dispid; DWORD flags; } event_info_t; @@ -126,24 +128,42 @@ typedef struct { #define EVENT_FORWARDBODY 0x0004 static const event_info_t event_info[] = { - {beforeunloadW, onbeforeunloadW, EVENTT_NONE, EVENT_DEFAULTLISTENER|EVENT_FORWARDBODY}, - {blurW, onblurW, EVENTT_HTML, EVENT_DEFAULTLISTENER}, - {changeW, onchangeW, EVENTT_HTML, EVENT_DEFAULTLISTENER|EVENT_BUBBLE}, - {clickW, onclickW, EVENTT_MOUSE, EVENT_DEFAULTLISTENER|EVENT_BUBBLE}, - {dblclickW, ondblclickW, EVENTT_MOUSE, EVENT_DEFAULTLISTENER|EVENT_BUBBLE}, - {dragW, ondragW, EVENTT_MOUSE, 0}, - {dragstartW, ondragstartW, EVENTT_MOUSE, 0}, - {focusW, onfocusW, EVENTT_HTML, EVENT_DEFAULTLISTENER}, - {keydownW, onkeydownW, EVENTT_KEY, EVENT_DEFAULTLISTENER|EVENT_BUBBLE}, - {keyupW, onkeyupW, EVENTT_KEY, EVENT_DEFAULTLISTENER|EVENT_BUBBLE}, - {loadW, onloadW, EVENTT_HTML, 0}, - {mousedownW, onmousedownW, EVENTT_MOUSE, EVENT_DEFAULTLISTENER|EVENT_BUBBLE}, - {mouseoutW, onmouseoutW, EVENTT_MOUSE, EVENT_DEFAULTLISTENER|EVENT_BUBBLE}, - {mouseoverW, onmouseoverW, EVENTT_MOUSE, EVENT_DEFAULTLISTENER|EVENT_BUBBLE}, - {mouseupW, onmouseupW, EVENTT_MOUSE, EVENT_DEFAULTLISTENER|EVENT_BUBBLE}, - {pasteW, onpasteW, EVENTT_NONE, 0}, - {readystatechangeW, onreadystatechangeW, EVENTT_NONE, 0}, - {selectstartW, onselectstartW, EVENTT_MOUSE, 0} + {beforeunloadW, onbeforeunloadW, EVENTT_NONE, DISPID_EVMETH_ONBEFOREUNLOAD, + EVENT_DEFAULTLISTENER|EVENT_FORWARDBODY}, + {blurW, onblurW, EVENTT_HTML, DISPID_EVMETH_ONBLUR, + EVENT_DEFAULTLISTENER}, + {changeW, onchangeW, EVENTT_HTML, DISPID_EVMETH_ONCHANGE, + EVENT_DEFAULTLISTENER|EVENT_BUBBLE}, + {clickW, onclickW, EVENTT_MOUSE, DISPID_EVMETH_ONCLICK, + EVENT_DEFAULTLISTENER|EVENT_BUBBLE}, + {dblclickW, ondblclickW, EVENTT_MOUSE, DISPID_EVMETH_ONDBLCLICK, + EVENT_DEFAULTLISTENER|EVENT_BUBBLE}, + {dragW, ondragW, EVENTT_MOUSE, DISPID_EVMETH_ONDRAG, + 0}, + {dragstartW, ondragstartW, EVENTT_MOUSE, DISPID_EVMETH_ONDRAGSTART, + 0}, + {focusW, onfocusW, EVENTT_HTML, DISPID_EVMETH_ONFOCUS, + EVENT_DEFAULTLISTENER}, + {keydownW, onkeydownW, EVENTT_KEY, DISPID_EVMETH_ONKEYDOWN, + EVENT_DEFAULTLISTENER|EVENT_BUBBLE}, + {keyupW, onkeyupW, EVENTT_KEY, DISPID_EVMETH_ONKEYUP, + EVENT_DEFAULTLISTENER|EVENT_BUBBLE}, + {loadW, onloadW, EVENTT_HTML, DISPID_EVMETH_ONLOAD, + 0}, + {mousedownW, onmousedownW, EVENTT_MOUSE, DISPID_EVMETH_ONMOUSEDOWN, + EVENT_DEFAULTLISTENER|EVENT_BUBBLE}, + {mouseoutW, onmouseoutW, EVENTT_MOUSE, DISPID_EVMETH_ONMOUSEOUT, + EVENT_DEFAULTLISTENER|EVENT_BUBBLE}, + {mouseoverW, onmouseoverW, EVENTT_MOUSE, DISPID_EVMETH_ONMOUSEOVER, + EVENT_DEFAULTLISTENER|EVENT_BUBBLE}, + {mouseupW, onmouseupW, EVENTT_MOUSE, DISPID_EVMETH_ONMOUSEUP, + EVENT_DEFAULTLISTENER|EVENT_BUBBLE}, + {pasteW, onpasteW, EVENTT_NONE, DISPID_EVMETH_ONPASTE, + 0}, + {readystatechangeW, onreadystatechangeW, EVENTT_NONE, DISPID_EVMETH_ONREADYSTATECHANGE, + 0}, + {selectstartW, onselectstartW, EVENTT_MOUSE, DISPID_EVMETH_ONSELECTSTART, + 0} }; eventid_t str_to_eid(LPCWSTR str) @@ -738,17 +758,68 @@ static IHTMLEventObj *create_event(HTMLDOMNode *target, eventid_t eid, nsIDOMEve return HTMLEVENTOBJ(ret); } +static HRESULT call_cp_func(IDispatch *disp, DISPID dispid) +{ + DISPPARAMS dp = {NULL,NULL,0,0}; + ULONG argerr; + EXCEPINFO ei; + VARIANT vres; + HRESULT hres; + + V_VT(&vres) = VT_EMPTY; + memset(&ei, 0, sizeof(ei)); + hres = IDispatch_Invoke(disp, dispid, &IID_NULL, 0, DISPATCH_METHOD, &dp, &vres, &ei, &argerr); + if(SUCCEEDED(hres) && V_VT(&vres) != VT_EMPTY) { + FIXME("handle result %s\n", debugstr_variant(&vres)); + VariantClear(&vres); + } + + return hres; +} + +static BOOL is_cp_event(ConnectionPoint *cp, DISPID dispid) +{ + cp_static_data_t *data; + unsigned min, max, i; + HRESULT hres; + + data = cp->data; + if(!data) + return FALSE; + + if(!data->ids) { + hres = get_dispids(data->tid, &data->id_cnt, &data->ids); + if(FAILED(hres)) + return hres; + } + + min = 0; + max = data->id_cnt; + while(min <= max) { + i = (min+max)/2; + if(data->ids[i] == dispid) + return TRUE; + + if(data->ids[i] < dispid) + min = i+1; + else + max = i-1; + } + + return FALSE; +} + static void call_event_handlers(HTMLDocumentNode *doc, IHTMLEventObj *event_obj, event_target_t *event_target, - eventid_t eid, IDispatch *this_obj) + ConnectionPointContainer *cp_container, eventid_t eid, IDispatch *this_obj) { - handler_vector_t *handler_vector; + handler_vector_t *handler_vector = NULL; DWORD i; HRESULT hres; - if(!event_target || !(handler_vector = event_target->event_table[eid])) - return; + if(event_target) + handler_vector = event_target->event_table[eid]; - if(handler_vector->handler_prop) { + if(handler_vector && handler_vector->handler_prop) { DISPID named_arg = DISPID_THIS; VARIANTARG arg; DISPPARAMS dp = {&arg, &named_arg, 1, 1}; @@ -764,7 +835,7 @@ static void call_event_handlers(HTMLDocumentNode *doc, IHTMLEventObj *event_obj, WARN("%s <<< %08x\n", debugstr_w(event_info[eid].name), hres); } - if(handler_vector->handler_cnt) { + if(handler_vector && handler_vector->handler_cnt) { VARIANTARG arg; DISPPARAMS dp = {&arg, NULL, 1, 0}; @@ -782,6 +853,26 @@ static void call_event_handlers(HTMLDocumentNode *doc, IHTMLEventObj *event_obj, } } } + + if(cp_container) { + ConnectionPoint *cp; + + if(cp_container->forward_container) + cp_container = cp_container->forward_container; + + for(cp = cp_container->cp_list; cp; cp = cp->next) { + if(cp->sinks_size && is_cp_event(cp, event_info[eid].dispid)) { + for(i=0; i < cp->sinks_size; i++) { + TRACE("cp %s [%d] >>>\n", debugstr_w(event_info[eid].name), i); + hres = call_cp_func(cp->sinks[i].disp, event_info[eid].dispid); + if(hres == S_OK) + TRACE("cp %s [%d] <<<\n", debugstr_w(event_info[eid].name), i); + else + WARN("cp %s [%d] <<< %08x\n", debugstr_w(event_info[eid].name), i, hres); + } + } + } + } } void fire_event(HTMLDocumentNode *doc, eventid_t eid, nsIDOMNode *target, nsIDOMEvent *nsevent) @@ -805,7 +896,8 @@ void fire_event(HTMLDocumentNode *doc, eventid_t eid, nsIDOMNode *target, nsIDOM do { node = get_node(doc, nsnode, FALSE); if(node) - call_event_handlers(doc, event_obj, *get_node_event_target(node), eid, (IDispatch*)HTMLDOMNODE(node)); + call_event_handlers(doc, event_obj, *get_node_event_target(node), node->cp_container, eid, + (IDispatch*)HTMLDOMNODE(node)); if(!(event_info[eid].flags & EVENT_BUBBLE)) break; @@ -831,14 +923,15 @@ void fire_event(HTMLDocumentNode *doc, eventid_t eid, nsIDOMNode *target, nsIDOM if(NS_SUCCEEDED(nsres) && nsbody) { node = get_node(doc, (nsIDOMNode*)nsbody, FALSE); if(node) - call_event_handlers(doc, event_obj, *get_node_event_target(node), eid, (IDispatch*)HTMLDOMNODE(node)); + call_event_handlers(doc, event_obj, *get_node_event_target(node), node->cp_container, + eid, (IDispatch*)HTMLDOMNODE(node)); nsIDOMHTMLElement_Release(nsbody); }else { ERR("Could not get body: %08x\n", nsres); } } - call_event_handlers(doc, event_obj, doc->basedoc.doc_node->node.event_target, eid, + call_event_handlers(doc, event_obj, doc->basedoc.doc_node->node.event_target, &doc->basedoc.cp_container, eid, (IDispatch*)HTMLDOC(&doc->basedoc)); break; diff --git a/dlls/mshtml/htmlstyle3.c b/dlls/mshtml/htmlstyle3.c index 505e91e01d1..56fd3df3bc7 100644 --- a/dlls/mshtml/htmlstyle3.c +++ b/dlls/mshtml/htmlstyle3.c @@ -103,7 +103,15 @@ static HRESULT WINAPI HTMLStyle3_get_layoutFlow(IHTMLStyle3 *iface, BSTR *p) static HRESULT WINAPI HTMLStyle3_put_zoom(IHTMLStyle3 *iface, VARIANT v) { HTMLStyle *This = HTMLSTYLE3_THIS(iface); - FIXME("(%p)->(%s)\n", This, debugstr_variant(&v)); + + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + + /* zoom property is IE CSS extension that is mostly used as a hack to workaround IE bugs. + * The value is set to 1 then. We can safely ignore setting zoom to 1. */ + if(V_VT(&v) == VT_I4 && V_I4(&v) == 1) + return S_OK; + + FIXME("stub for %s\n", debugstr_variant(&v)); return E_NOTIMPL; } diff --git a/dlls/mshtml/htmltable.c b/dlls/mshtml/htmltable.c index 76997486117..6357f77e4ba 100644 --- a/dlls/mshtml/htmltable.c +++ b/dlls/mshtml/htmltable.c @@ -584,7 +584,7 @@ HTMLElement *HTMLTable_Create(HTMLDocumentNode *doc, nsIDOMHTMLElement *nselem) HTMLElement_Init(&ret->element, doc, nselem, &HTMLTable_dispex); - ConnectionPoint_Init(&ret->cp, &ret->element.cp_container, &DIID_HTMLTableEvents); + ConnectionPoint_Init(&ret->cp, &ret->element.cp_container, &DIID_HTMLTableEvents, NULL); nsres = nsIDOMHTMLElement_QueryInterface(nselem, &IID_nsIDOMHTMLTableElement, (void**)&ret->nstable); if(NS_FAILED(nsres)) diff --git a/dlls/mshtml/htmltextcont.c b/dlls/mshtml/htmltextcont.c index 35fa01b1f83..46b5d87b842 100644 --- a/dlls/mshtml/htmltextcont.c +++ b/dlls/mshtml/htmltextcont.c @@ -189,5 +189,5 @@ void HTMLTextContainer_Init(HTMLTextContainer *This, HTMLDocumentNode *doc, nsID HTMLElement_Init(&This->element, doc, nselem, dispex_data); - ConnectionPoint_Init(&This->cp, &This->element.cp_container, &DIID_HTMLTextContainerEvents); + ConnectionPoint_Init(&This->cp, &This->element.cp_container, &DIID_HTMLTextContainerEvents, NULL); } diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 9f3b3e7f0c0..17d2bfe32cb 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -126,6 +126,9 @@ static HRESULT WINAPI HTMLWindow2_QueryInterface(IHTMLWindow2 *iface, REFIID rii }else if(IsEqualGUID(&IID_IHTMLWindow3, riid)) { TRACE("(%p)->(IID_IHTMLWindow3 %p)\n", This, ppv); *ppv = HTMLWINDOW3(This); + }else if(IsEqualGUID(&IID_IHTMLWindow4, riid)) { + TRACE("(%p)->(IID_IHTMLWindow4 %p)\n", This, ppv); + *ppv = HTMLWINDOW4(This); }else if(dispex_query_interface(&This->dispex, riid, ppv)) { return *ppv ? S_OK : E_NOINTERFACE; } @@ -232,11 +235,122 @@ static HRESULT WINAPI HTMLWindow2_Invoke(IHTMLWindow2 *iface, DISPID dispIdMembe pVarResult, pExcepInfo, puArgErr); } +static HRESULT get_frame_by_index(nsIDOMWindowCollection *nsFrames, PRUint32 index, HTMLWindow **ret) +{ + PRUint32 length; + nsIDOMWindow *nsWindow; + nsresult nsres; + + nsres = nsIDOMWindowCollection_GetLength(nsFrames, &length); + if(NS_FAILED(nsres)) { + FIXME("nsIDOMWindowCollection_GetLength failed: 0x%08x\n", nsres); + return E_FAIL; + } + + if(index >= length) + return DISP_E_MEMBERNOTFOUND; + + nsres = nsIDOMWindowCollection_Item(nsFrames, index, &nsWindow); + if(NS_FAILED(nsres)) { + FIXME("nsIDOMWindowCollection_Item failed: 0x%08x\n", nsres); + return E_FAIL; + } + + *ret = nswindow_to_window(nsWindow); + + nsIDOMWindow_Release(nsWindow); + + return S_OK; +} + static HRESULT WINAPI HTMLWindow2_item(IHTMLWindow2 *iface, VARIANT *pvarIndex, VARIANT *pvarResult) { HTMLWindow *This = HTMLWINDOW2_THIS(iface); - FIXME("(%p)->(%p %p)\n", This, pvarIndex, pvarResult); - return E_NOTIMPL; + nsIDOMWindowCollection *nsFrames; + HTMLWindow *window; + HRESULT hres; + nsresult nsres; + + TRACE("(%p)->(%p %p)\n", This, pvarIndex, pvarResult); + + nsres = nsIDOMWindow_GetFrames(This->nswindow, &nsFrames); + if(NS_FAILED(nsres)) { + FIXME("nsIDOMWindow_GetFrames failed: 0x%08x\n", nsres); + return E_FAIL; + } + + if(V_VT(pvarIndex) == VT_I4) { + int index = V_I4(pvarIndex); + TRACE("Getting index %d\n", index); + if(index < 0) { + hres = DISP_E_MEMBERNOTFOUND; + goto cleanup; + } + hres = get_frame_by_index(nsFrames, index, &window); + if(FAILED(hres)) + goto cleanup; + }else if(V_VT(pvarIndex) == VT_UINT) { + unsigned int index = V_UINT(pvarIndex); + TRACE("Getting index %u\n", index); + hres = get_frame_by_index(nsFrames, index, &window); + if(FAILED(hres)) + goto cleanup; + }else if(V_VT(pvarIndex) == VT_BSTR) { + BSTR str = V_BSTR(pvarIndex); + PRUint32 length, i; + + TRACE("Getting name %s\n", wine_dbgstr_w(str)); + + nsres = nsIDOMWindowCollection_GetLength(nsFrames, &length); + + window = NULL; + for(i = 0; i < length && !window; ++i) { + HTMLWindow *cur_window; + nsIDOMWindow *nsWindow; + BSTR id; + + nsres = nsIDOMWindowCollection_Item(nsFrames, i, &nsWindow); + if(NS_FAILED(nsres)) { + FIXME("nsIDOMWindowCollection_Item failed: 0x%08x\n", nsres); + hres = E_FAIL; + goto cleanup; + } + + cur_window = nswindow_to_window(nsWindow); + + nsIDOMWindow_Release(nsWindow); + + hres = IHTMLElement_get_id(HTMLELEM(&cur_window->frame_element->element), &id); + if(FAILED(hres)) { + FIXME("IHTMLElement_get_id failed: 0x%08x\n", hres); + goto cleanup; + } + + if(!strcmpW(id, str)) + window = cur_window; + + SysFreeString(id); + } + + if(!window) { + hres = DISP_E_MEMBERNOTFOUND; + goto cleanup; + } + }else { + hres = E_INVALIDARG; + goto cleanup; + } + + IHTMLWindow2_AddRef(HTMLWINDOW2(window)); + V_VT(pvarResult) = VT_DISPATCH; + V_DISPATCH(pvarResult) = (IDispatch*)window; + + hres = S_OK; + +cleanup: + nsIDOMWindowCollection_Release(nsFrames); + + return hres; } static HRESULT WINAPI HTMLWindow2_get_length(IHTMLWindow2 *iface, LONG *p) @@ -268,8 +382,12 @@ static HRESULT WINAPI HTMLWindow2_get_length(IHTMLWindow2 *iface, LONG *p) static HRESULT WINAPI HTMLWindow2_get_frames(IHTMLWindow2 *iface, IHTMLFramesCollection2 **p) { HTMLWindow *This = HTMLWINDOW2_THIS(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + FIXME("(%p)->(%p): semi-stub\n", This, p); + + /* FIXME: Should return a separate Window object */ + *p = (IHTMLFramesCollection2*)HTMLWINDOW2(This); + HTMLWindow2_AddRef(iface); + return S_OK; } static HRESULT WINAPI HTMLWindow2_put_defaultStatus(IHTMLWindow2 *iface, BSTR v) @@ -578,8 +696,15 @@ static HRESULT WINAPI HTMLWindow2_get_name(IHTMLWindow2 *iface, BSTR *p) static HRESULT WINAPI HTMLWindow2_get_parent(IHTMLWindow2 *iface, IHTMLWindow2 **p) { HTMLWindow *This = HTMLWINDOW2_THIS(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + TRACE("(%p)->(%p)\n", This, p); + + if(This->parent) { + *p = HTMLWINDOW2(This->parent); + IHTMLWindow2_AddRef(*p); + }else + *p = NULL; + + return S_OK; } static HRESULT WINAPI HTMLWindow2_open(IHTMLWindow2 *iface, BSTR url, BSTR name, @@ -605,9 +730,16 @@ static HRESULT WINAPI HTMLWindow2_get_self(IHTMLWindow2 *iface, IHTMLWindow2 **p static HRESULT WINAPI HTMLWindow2_get_top(IHTMLWindow2 *iface, IHTMLWindow2 **p) { - HTMLWindow *This = HTMLWINDOW2_THIS(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + HTMLWindow *This = HTMLWINDOW2_THIS(iface), *curr; + TRACE("(%p)->(%p)\n", This, p); + + curr = This; + while(curr->parent) + curr = curr->parent; + *p = HTMLWINDOW2(curr); + IHTMLWindow2_AddRef(*p); + + return S_OK; } static HRESULT WINAPI HTMLWindow2_get_window(IHTMLWindow2 *iface, IHTMLWindow2 **p) @@ -1354,6 +1486,99 @@ static const IHTMLWindow3Vtbl HTMLWindow3Vtbl = { HTMLWindow3_showModelessDialog }; +#define HTMLWINDOW4_THIS(iface) DEFINE_THIS(HTMLWindow, HTMLWindow4, iface) + +static HRESULT WINAPI HTMLWindow4_QueryInterface(IHTMLWindow4 *iface, REFIID riid, void **ppv) +{ + HTMLWindow *This = HTMLWINDOW4_THIS(iface); + + return IHTMLWindow2_QueryInterface(HTMLWINDOW2(This), riid, ppv); +} + +static ULONG WINAPI HTMLWindow4_AddRef(IHTMLWindow4 *iface) +{ + HTMLWindow *This = HTMLWINDOW4_THIS(iface); + + return IHTMLWindow2_AddRef(HTMLWINDOW2(This)); +} + +static ULONG WINAPI HTMLWindow4_Release(IHTMLWindow4 *iface) +{ + HTMLWindow *This = HTMLWINDOW4_THIS(iface); + + return IHTMLWindow2_Release(HTMLWINDOW2(This)); +} + +static HRESULT WINAPI HTMLWindow4_GetTypeInfoCount(IHTMLWindow4 *iface, UINT *pctinfo) +{ + HTMLWindow *This = HTMLWINDOW4_THIS(iface); + + return IDispatchEx_GetTypeInfoCount(DISPATCHEX(This), pctinfo); +} + +static HRESULT WINAPI HTMLWindow4_GetTypeInfo(IHTMLWindow4 *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLWindow *This = HTMLWINDOW4_THIS(iface); + + return IDispatchEx_GetTypeInfo(DISPATCHEX(This), iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI HTMLWindow4_GetIDsOfNames(IHTMLWindow4 *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, + LCID lcid, DISPID *rgDispId) +{ + HTMLWindow *This = HTMLWINDOW4_THIS(iface); + + return IDispatchEx_GetIDsOfNames(DISPATCHEX(This), riid, rgszNames, cNames, lcid, rgDispId); +} + +static HRESULT WINAPI HTMLWindow4_Invoke(IHTMLWindow4 *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLWindow *This = HTMLWINDOW4_THIS(iface); + + return IDispatchEx_Invoke(DISPATCHEX(This), dispIdMember, riid, lcid, wFlags, pDispParams, + pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLWindow4_createPopup(IHTMLWindow4 *iface, VARIANT *varArgIn, + IDispatch **ppPopup) +{ + HTMLWindow *This = HTMLWINDOW4_THIS(iface); + FIXME("(%p)->(%p %p)\n", This, varArgIn, ppPopup); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLWindow4_get_frameElement(IHTMLWindow4 *iface, IHTMLFrameBase **p) +{ + HTMLWindow *This = HTMLWINDOW4_THIS(iface); + TRACE("(%p)->(%p)\n", This, p); + + if(This->frame_element) { + *p = HTMLFRAMEBASE(This->frame_element); + IHTMLFrameBase_AddRef(*p); + }else + *p = NULL; + + return S_OK; +} + +#undef HTMLWINDOW4_THIS + +static const IHTMLWindow4Vtbl HTMLWindow4Vtbl = { + HTMLWindow4_QueryInterface, + HTMLWindow4_AddRef, + HTMLWindow4_Release, + HTMLWindow4_GetTypeInfoCount, + HTMLWindow4_GetTypeInfo, + HTMLWindow4_GetIDsOfNames, + HTMLWindow4_Invoke, + HTMLWindow4_createPopup, + HTMLWindow4_get_frameElement +}; + #define DISPEX_THIS(iface) DEFINE_THIS(HTMLWindow, IDispatchEx, iface) static HRESULT WINAPI WindowDispEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) @@ -1601,6 +1826,7 @@ static const IDispatchExVtbl WindowDispExVtbl = { static const tid_t HTMLWindow_iface_tids[] = { IHTMLWindow2_tid, IHTMLWindow3_tid, + IHTMLWindow4_tid, 0 }; @@ -1633,6 +1859,7 @@ HRESULT HTMLWindow_Create(HTMLDocumentObj *doc_obj, nsIDOMWindow *nswindow, HTML window->lpHTMLWindow2Vtbl = &HTMLWindow2Vtbl; window->lpHTMLWindow3Vtbl = &HTMLWindow3Vtbl; + window->lpHTMLWindow4Vtbl = &HTMLWindow4Vtbl; window->lpIDispatchExVtbl = &WindowDispExVtbl; window->ref = 1; window->doc_obj = doc_obj; diff --git a/dlls/mshtml/install.c b/dlls/mshtml/install.c index 5eca3a6174d..cfe3cd01a85 100644 --- a/dlls/mshtml/install.c +++ b/dlls/mshtml/install.c @@ -182,7 +182,7 @@ static BOOL install_from_unix_file(const char *file_name) int fd; BOOL ret; - static WCHAR *(*wine_get_dos_file_name)(const char*); + static WCHAR * (CDECL *wine_get_dos_file_name)(const char*); static const WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0}; fd = open(file_name, O_RDONLY); diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 43601ae9ddf..8e5f9016d3c 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -18,6 +18,7 @@ #include "wingdi.h" #include "docobj.h" +#include "comcat.h" #include "mshtml.h" #include "mshtmhst.h" #include "hlink.h" @@ -79,6 +80,7 @@ typedef enum { DispHTMLTableRow_tid, DispHTMLUnknownElement_tid, DispHTMLWindow2_tid, + HTMLDocumentEvents_tid, IHTMLAnchorElement_tid, IHTMLBodyElement_tid, IHTMLBodyElement2_tid, @@ -120,6 +122,7 @@ typedef enum { IHTMLUniqueName_tid, IHTMLWindow2_tid, IHTMLWindow3_tid, + IHTMLWindow4_tid, IOmNavigator_tid, LAST_tid } tid_t; @@ -156,6 +159,7 @@ void init_dispex(DispatchEx*,IUnknown*,dispex_static_data_t*); void release_dispex(DispatchEx*); BOOL dispex_query_interface(DispatchEx*,REFIID,void**); HRESULT dispex_get_dprop_ref(DispatchEx*,const WCHAR*,BOOL,VARIANT**); +HRESULT get_dispids(tid_t,DWORD*,DISPID**); typedef struct HTMLDocumentNode HTMLDocumentNode; typedef struct HTMLDocumentObj HTMLDocumentObj; @@ -215,6 +219,7 @@ struct HTMLWindow { DispatchEx dispex; const IHTMLWindow2Vtbl *lpHTMLWindow2Vtbl; const IHTMLWindow3Vtbl *lpHTMLWindow3Vtbl; + const IHTMLWindow4Vtbl *lpHTMLWindow4Vtbl; const IDispatchExVtbl *lpIDispatchExVtbl; LONG ref; @@ -259,10 +264,17 @@ typedef enum { } USERMODE; typedef struct { + tid_t tid; + DWORD id_cnt; + DISPID *ids; +} cp_static_data_t; + +typedef struct ConnectionPointContainer { const IConnectionPointContainerVtbl *lpConnectionPointContainerVtbl; ConnectionPoint *cp_list; IUnknown *outer; + struct ConnectionPointContainer *forward_container; } ConnectionPointContainer; struct ConnectionPoint { @@ -278,6 +290,7 @@ struct ConnectionPoint { DWORD sinks_size; const IID *iid; + cp_static_data_t *data; ConnectionPoint *next; }; @@ -445,6 +458,7 @@ struct HTMLDOMNode { nsIDOMNode *nsnode; HTMLDocumentNode *doc; event_target_t *event_target; + ConnectionPointContainer *cp_container; HTMLDOMNode *next; }; @@ -501,6 +515,7 @@ struct HTMLDocumentNode { BOOL content_ready; IInternetSecurityManager *secmgr; + ICatInformation *catmgr; nsDocumentEventListener *nsevent_listener; BOOL *event_vector; @@ -514,6 +529,7 @@ struct HTMLDocumentNode { #define HTMLWINDOW2(x) ((IHTMLWindow2*) &(x)->lpHTMLWindow2Vtbl) #define HTMLWINDOW3(x) ((IHTMLWindow3*) &(x)->lpHTMLWindow3Vtbl) +#define HTMLWINDOW4(x) ((IHTMLWindow4*) &(x)->lpHTMLWindow4Vtbl) #define HTMLDOC(x) ((IHTMLDocument2*) &(x)->lpHTMLDocument2Vtbl) #define HTMLDOC3(x) ((IHTMLDocument3*) &(x)->lpHTMLDocument3Vtbl) @@ -614,7 +630,7 @@ void HTMLDocumentNode_SecMgr_Init(HTMLDocumentNode*); HRESULT HTMLCurrentStyle_Create(HTMLElement*,IHTMLCurrentStyle**); -void ConnectionPoint_Init(ConnectionPoint*,ConnectionPointContainer*,REFIID); +void ConnectionPoint_Init(ConnectionPoint*,ConnectionPointContainer*,REFIID,cp_static_data_t*); void ConnectionPointContainer_Init(ConnectionPointContainer*,IUnknown*); void ConnectionPointContainer_Destroy(ConnectionPointContainer*); diff --git a/dlls/mshtml/nsiface.idl b/dlls/mshtml/nsiface.idl index 19f29b0b663..9d0bb309dbd 100644 --- a/dlls/mshtml/nsiface.idl +++ b/dlls/mshtml/nsiface.idl @@ -140,6 +140,8 @@ typedef nsISupports nsIContent; typedef nsISupports nsINode; typedef nsISupports nsIStyleSheet; typedef nsISupports nsIStyleRule; +typedef nsISupports nsIVariant; +typedef nsISupports nsIDOMUserDataHandler; [ object, @@ -603,6 +605,37 @@ interface nsIDOMNodeList : nsISupports [ object, + uuid(29fb2a18-1dd2-11b2-8dd9-a6fd5d5ad12f), + local + /* NOT_FROZEN */ +] +interface nsIDOM3Node : nsISupports +{ + enum NSDOCPOSITION { + DISCONNECTED = 1, + PRECEDING = 2, + FOLLOWING = 4, + CONTAINS = 8, + CONTAINED_BY = 16, + IMPLEMENTATION_SPECIFIC = 32 + }; + + nsresult GetBaseURI(nsAString *aBaseURI); + nsresult CompareDocumentPosition(nsIDOMNode *other, PRUint16 *_retval); + nsresult GetTextContent(nsAString *aTextContent); + nsresult SetTextContent(const nsAString *aTextContent); + nsresult IsSameNode(nsIDOMNode *other, PRBool *_retval); + nsresult LookupPrefix(const nsAString *namespaceURI, PRBool *_retval); + nsresult IsDefaultNamespace(const nsAString *namespaceURI, PRBool *_retval); + nsresult LookupNamespaceURI(const nsAString *prefix, nsAString _retval); + nsresult IsEqualNode(nsIDOMNode *arg, PRBool *_retval); + nsresult GetFeature(const nsAString *feature, const nsAString *version, nsISupports **_retval); + nsresult SetUserData(const nsAString *key, nsIVariant *data, nsIDOMUserDataHandler *handler, nsIVariant **_retval); + nsresult GetUserData(const nsAString *key, nsIVariant **_retval); +} + +[ + object, uuid(a6cf907c-15b3-11d2-932e-00805f8add32), local /* FROZEN */ diff --git a/dlls/mshtml/secmgr.c b/dlls/mshtml/secmgr.c index 8938943fb56..e35a83b5c29 100644 --- a/dlls/mshtml/secmgr.c +++ b/dlls/mshtml/secmgr.c @@ -84,7 +84,7 @@ static HRESULT WINAPI InternetHostSecurityManager_ProcessUrlAction(IInternetHost pContext, cbContext, dwFlags, dwReserved); } -static DWORD confirm_safety(HTMLDocumentNode *This, const WCHAR *url, IUnknown *obj) +static HRESULT confirm_safety(HTMLDocumentNode *This, const WCHAR *url, struct CONFIRMSAFETY *cs, DWORD *ret) { DWORD policy, enabled_opts, supported_opts; IObjectSafety *obj_safety; @@ -94,12 +94,29 @@ static DWORD confirm_safety(HTMLDocumentNode *This, const WCHAR *url, IUnknown * hres = IInternetSecurityManager_ProcessUrlAction(This->secmgr, url, URLACTION_SCRIPT_SAFE_ACTIVEX, (BYTE*)&policy, sizeof(policy), NULL, 0, 0, 0); - if(FAILED(hres) || policy != URLPOLICY_ALLOW) - return URLPOLICY_DISALLOW; + if(FAILED(hres) || policy != URLPOLICY_ALLOW) { + *ret = URLPOLICY_DISALLOW; + return S_OK; + } + + hres = IUnknown_QueryInterface(cs->pUnk, &IID_IObjectSafety, (void**)&obj_safety); + if(FAILED(hres)) { + CATID scripting_catid = CATID_SafeForScripting; + + if(!This->catmgr) { + hres = CoCreateInstance(&CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, + &IID_ICatInformation, (void**)&This->catmgr); + if(FAILED(hres)) + return hres; + } + + hres = ICatInformation_IsClassOfCategories(This->catmgr, &cs->clsid, 1, &scripting_catid, 0, NULL); + if(FAILED(hres)) + return hres; - hres = IUnknown_QueryInterface(obj, &IID_IObjectSafety, (void**)&obj_safety); - if(FAILED(hres)) - return URLPOLICY_DISALLOW; + *ret = hres == S_OK ? URLPOLICY_ALLOW : URLPOLICY_DISALLOW; + return S_OK; + } hres = IObjectSafety_GetInterfaceSafetyOptions(obj_safety, &IID_IDispatchEx, &supported_opts, &enabled_opts); if(SUCCEEDED(hres)) { @@ -109,10 +126,9 @@ static DWORD confirm_safety(HTMLDocumentNode *This, const WCHAR *url, IUnknown * hres = IObjectSafety_SetInterfaceSafetyOptions(obj_safety, &IID_IDispatchEx, enabled_opts, enabled_opts); } IObjectSafety_Release(obj_safety); - if(FAILED(hres)) - return URLPOLICY_DISALLOW; - return URLPOLICY_ALLOW; + *ret = SUCCEEDED(hres) ? URLPOLICY_ALLOW : URLPOLICY_DISALLOW; + return S_OK; } static HRESULT WINAPI InternetHostSecurityManager_QueryCustomPolicy(IInternetHostSecurityManager *iface, REFGUID guidKey, @@ -149,7 +165,9 @@ static HRESULT WINAPI InternetHostSecurityManager_QueryCustomPolicy(IInternetHos return E_FAIL; } - policy = confirm_safety(This, url, cs->pUnk); + hres = confirm_safety(This, url, cs, &policy); + if(FAILED(hres)) + return hres; *ppPolicy = CoTaskMemAlloc(sizeof(policy)); if(!*ppPolicy) diff --git a/dlls/mshtml/task.c b/dlls/mshtml/task.c index e6b94a2d228..eae51cacd15 100644 --- a/dlls/mshtml/task.c +++ b/dlls/mshtml/task.c @@ -199,12 +199,6 @@ HRESULT clear_task_timer(HTMLDocument *doc, BOOL interval, DWORD id) return S_OK; } -void parse_complete(HTMLDocumentObj *doc) -{ - TRACE("(%p)\n", doc); - -} - static void call_timer_disp(IDispatch *disp) { DISPPARAMS dp = {NULL, NULL, 0, 0}; diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index 2559fdc3d30..bd55c9f5fba 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -52,12 +52,21 @@ static const char elem_test_str[] = "" "" ""; +static const char elem_test2_str[] = + "test" + "
" + ""; + static const char indent_test_str[] = "testabc
123"; static const char cond_comment_str[] = "test" "" ""; +static const char frameset_str[] = + "frameset test" + "" + ""; static WCHAR characterW[] = {'c','h','a','r','a','c','t','e','r',0}; static WCHAR texteditW[] = {'t','e','x','t','e','d','i','t',0}; @@ -1568,6 +1577,21 @@ static void _test_elem_set_innerhtml(unsigned line, IUnknown *unk, const char *i SysFreeString(html); } +#define test_elem_set_outerhtml(e,t) _test_elem_set_outerhtml(__LINE__,e,t) +static void _test_elem_set_outerhtml(unsigned line, IUnknown *unk, const char *outer_html) +{ + IHTMLElement *elem = _get_elem_iface(line, unk); + BSTR html; + HRESULT hres; + + html = a2bstr(outer_html); + hres = IHTMLElement_put_outerHTML(elem, html); + ok_(__FILE__,line)(hres == S_OK, "put_outerHTML failed: %08x\n", hres); + + IHTMLElement_Release(elem); + SysFreeString(html); +} + #define get_first_child(n) _get_first_child(__LINE__,n) static IHTMLDOMNode *_get_first_child(unsigned line, IUnknown *unk) { @@ -5372,6 +5396,7 @@ static void test_elems(IHTMLDocument2 *doc) ok(!node, "node = %p\n", node); elem2 = get_doc_elem_by_id(doc, "x"); + test_elem_tag((IUnknown*)elem2, "A"); node = node_get_next((IUnknown*)elem2); IHTMLDOMNode_Release(node); IHTMLElement_Release(elem2); @@ -5386,6 +5411,33 @@ static void test_elems(IHTMLDocument2 *doc) IHTMLWindow2_Release(window); } +static void test_elems2(IHTMLDocument2 *doc) +{ + IHTMLElement *elem, *elem2; + + static const elem_type_t outer_types[] = { + ET_BR, + ET_A + }; + + elem = get_doc_elem_by_id(doc, "divid"); + + test_elem_set_innerhtml((IUnknown*)elem, "
"); + elem2 = get_doc_elem_by_id(doc, "innerid"); + ok(elem2 != NULL, "elem2 == NULL\n"); + test_elem_set_outerhtml((IUnknown*)elem2, "
a"); + test_elem_all((IUnknown*)elem, outer_types, sizeof(outer_types)/sizeof(*outer_types)); + IHTMLElement_Release(elem2); + + elem2 = get_doc_elem_by_id(doc, "aid"); + ok(elem2 != NULL, "elem2 == NULL\n"); + test_elem_set_outerhtml((IUnknown*)elem2, ""); + test_elem_all((IUnknown*)elem, outer_types, 1); + IHTMLElement_Release(elem2); + + IHTMLElement_Release(elem); +} + static void test_create_elems(IHTMLDocument2 *doc) { IHTMLElement *elem, *body, *elem2; @@ -5548,6 +5600,220 @@ static void test_cond_comment(IHTMLDocument2 *doc) IHTMLElementCollection_Release(col); } +static void test_frame(IDispatch *disp, const char *exp_id) +{ + IHTMLWindow2 *frame2, *parent, *top; + IHTMLDocument2 *parent_doc, *top_doc; + IHTMLWindow4 *frame; + IHTMLFrameBase *frame_elem; + IHTMLElement *html_elem; + BSTR bstr; + HRESULT hres; + + hres = IDispatch_QueryInterface(disp, &IID_IHTMLWindow4, (void**)&frame); + ok(hres == S_OK, "Could not get IHTMLWindow4 interface: 0x%08x\n", hres); + if(FAILED(hres)) + return; + + hres = IHTMLWindow4_get_frameElement(frame, &frame_elem); + ok(hres == S_OK, "IHTMLWindow4_get_frameElement failed: 0x%08x\n", hres); + IHTMLWindow4_Release(frame); + if(FAILED(hres)) + return; + + hres = IHTMLFrameBase_QueryInterface(frame_elem, &IID_IHTMLElement, (void**)&html_elem); + ok(hres == S_OK, "Could not get IHTMLElement interface: 0x%08x\n", hres); + IHTMLFrameBase_Release(frame_elem); + if(FAILED(hres)) + return; + + hres = IHTMLElement_get_id(html_elem, &bstr); + ok(hres == S_OK, "IHTMLElement_get_id failed: 0x%08x\n", hres); + ok(!strcmp_wa(bstr, exp_id), "Expected ID: \"%s\", found ID: %s\n", exp_id, wine_dbgstr_w(bstr)); + IHTMLElement_Release(html_elem); + SysFreeString(bstr); + + hres = IDispatch_QueryInterface(disp, &IID_IHTMLWindow2, (void**)&frame2); + ok(hres == S_OK, "Could not get IHTMLWindow2 interface: 0x%08x\n", hres); + if(FAILED(hres)) + return; + + hres = IHTMLWindow2_get_parent(frame2, &parent); + ok(hres == S_OK, "IHTMLWindow2_get_parent failed: 0x%08x\n", hres); + if(FAILED(hres)){ + IHTMLWindow2_Release(frame2); + return; + } + + hres = IHTMLWindow2_get_document(parent, &parent_doc); + ok(hres == S_OK, "IHTMLWindow2_get_document failed: 0x%08x\n", hres); + IHTMLWindow2_Release(parent); + if(FAILED(hres)){ + IHTMLWindow2_Release(frame2); + return; + } + + hres = IHTMLDocument2_get_title(parent_doc, &bstr); + ok(hres == S_OK, "IHTMLDocument2_get_title failed: 0x%08x\n", hres); + ok(!strcmp_wa(bstr, "frameset test"), "Did not get the right parent. Expected \"frameset test\", found %s\n", wine_dbgstr_w(bstr)); + IHTMLDocument2_Release(parent_doc); + SysFreeString(bstr); + + /* test get_top */ + hres = IHTMLWindow2_get_top(frame2, &top); + ok(hres == S_OK, "IHTMLWindow2_get_top failed: 0x%08x\n", hres); + IHTMLWindow2_Release(frame2); + if(FAILED(hres)) + return; + + hres = IHTMLWindow2_get_document(top, &top_doc); + ok(hres == S_OK, "IHTMLWindow2_get_document failed: 0x%08x\n", hres); + IHTMLWindow2_Release(top); + if(FAILED(hres)) + return; + + hres = IHTMLDocument2_get_title(top_doc, &bstr); + ok(hres == S_OK, "IHTMLDocument2_get_title failed: 0x%08x\n", hres); + ok(!strcmp_wa(bstr, "frameset test"), "Did not get the right parent. Expected \"frameset test\", found %s\n", wine_dbgstr_w(bstr)); + IHTMLDocument2_Release(top_doc); + SysFreeString(bstr); +} + +static void test_frameset(IHTMLDocument2 *doc) +{ + IHTMLWindow2 *window; + IHTMLFramesCollection2 *frames; + IHTMLElement *elem; + LONG length; + VARIANT index_var, result_var; + HRESULT hres; + + window = get_doc_window(doc); + + /* test using IHTMLFramesCollection object */ + + hres = IHTMLWindow2_get_frames(window, &frames); + ok(hres == S_OK, "IHTMLWindow2_get_frames failed: 0x%08x\n", hres); + IHTMLWindow2_Release(window); + if(FAILED(hres)) + return; + + /* test result length */ + hres = IHTMLFramesCollection2_get_length(frames, &length); + ok(hres == S_OK, "IHTMLFramesCollection2_get_length failed: 0x%08x\n", hres); + ok(length == 2, "IHTMLFramesCollection2_get_length should have been 2, was: %d\n", length); + + /* test first frame */ + V_VT(&index_var) = VT_I4; + V_I4(&index_var) = 0; + hres = IHTMLFramesCollection2_item(frames, &index_var, &result_var); + ok(hres == S_OK, "IHTMLFramesCollection2_item failed: 0x%08x\n", hres); + if(SUCCEEDED(hres)) { + ok(V_VT(&result_var) == VT_DISPATCH, "result type should have been VT_DISPATCH, was: 0x%x\n", V_VT(&result_var)); + test_frame((IDispatch*)V_DISPATCH(&result_var), "fr1"); + } + VariantClear(&result_var); + + /* test second frame */ + V_I4(&index_var) = 1; + hres = IHTMLFramesCollection2_item(frames, &index_var, &result_var); + ok(hres == S_OK, "IHTMLFramesCollection2_item failed: 0x%08x\n", hres); + if(SUCCEEDED(hres)) { + ok(V_VT(&result_var) == VT_DISPATCH, "result type should have been VT_DISPATCH, was: 0x%x\n", V_VT(&result_var)); + test_frame((IDispatch*)V_DISPATCH(&result_var), "fr2"); + } + VariantClear(&result_var); + + /* fail on third frame */ + V_I4(&index_var) = 2; + hres = IHTMLFramesCollection2_item(frames, &index_var, &result_var); + ok(hres == DISP_E_MEMBERNOTFOUND, "IHTMLFramesCollection2_item should have" + "failed with DISP_E_MEMBERNOTFOUND, instead: 0x%08x\n", hres); + VariantClear(&result_var); + + /* string argument (element id lookup) */ + V_VT(&index_var) = VT_BSTR; + V_BSTR(&index_var) = a2bstr("fr1"); + hres = IHTMLFramesCollection2_item(frames, &index_var, &result_var); + ok(hres == S_OK, "IHTMLFramesCollection2_item failed: 0x%08x\n", hres); + if(SUCCEEDED(hres)) { + ok(V_VT(&result_var) == VT_DISPATCH, "result type should have been VT_DISPATCH, was: 0x%x\n", V_VT(&result_var)); + test_frame((IDispatch*)V_DISPATCH(&result_var), "fr1"); + } + VariantClear(&result_var); + VariantClear(&index_var); + + /* invalid argument */ + V_VT(&index_var) = VT_BOOL; + V_BOOL(&index_var) = VARIANT_TRUE; + hres = IHTMLFramesCollection2_item(frames, &index_var, &result_var); + ok(hres == E_INVALIDARG, "IHTMLFramesCollection2_item should have" + "failed with E_INVALIDARG, instead: 0x%08x\n", hres); + VariantClear(&result_var); + + IHTMLFramesCollection2_Release(frames); + + /* test using IHTMLWindow2 inheritance */ + + /* test result length */ + hres = IHTMLWindow2_get_length(window, &length); + ok(hres == S_OK, "IHTMLWindow2_get_length failed: 0x%08x\n", hres); + ok(length == 2, "IHTMLWindow2_get_length should have been 2, was: %d\n", length); + + /* test first frame */ + V_VT(&index_var) = VT_I4; + V_I4(&index_var) = 0; + hres = IHTMLWindow2_item(window, &index_var, &result_var); + ok(hres == S_OK, "IHTMLWindow2_item failed: 0x%08x\n", hres); + if(SUCCEEDED(hres)) { + ok(V_VT(&result_var) == VT_DISPATCH, "result type should have been VT_DISPATCH, was: 0x%x\n", V_VT(&result_var)); + test_frame((IDispatch*)V_DISPATCH(&result_var), "fr1"); + } + VariantClear(&result_var); + + /* test second frame */ + V_I4(&index_var) = 1; + hres = IHTMLWindow2_item(window, &index_var, &result_var); + ok(hres == S_OK, "IHTMLWindow2_item failed: 0x%08x\n", hres); + if(SUCCEEDED(hres)) { + ok(V_VT(&result_var) == VT_DISPATCH, "result type should have been VT_DISPATCH, was: 0x%x\n", V_VT(&result_var)); + test_frame((IDispatch*)V_DISPATCH(&result_var), "fr2"); + } + VariantClear(&result_var); + + /* fail on third frame */ + V_I4(&index_var) = 2; + hres = IHTMLWindow2_item(window, &index_var, &result_var); + ok(hres == DISP_E_MEMBERNOTFOUND, "IHTMLWindow2_item should have" + "failed with DISP_E_MEMBERNOTFOUND, instead: 0x%08x\n", hres); + VariantClear(&result_var); + + /* string argument (element id lookup) */ + V_VT(&index_var) = VT_BSTR; + V_BSTR(&index_var) = a2bstr("fr2"); + hres = IHTMLWindow2_item(window, &index_var, &result_var); + ok(hres == S_OK, "IHTMLWindow2_item failed: 0x%08x\n", hres); + if(SUCCEEDED(hres)) { + ok(V_VT(&result_var) == VT_DISPATCH, "result type should have been VT_DISPATCH, was: 0x%x\n", V_VT(&result_var)); + test_frame((IDispatch*)V_DISPATCH(&result_var), "fr2"); + } + VariantClear(&result_var); + VariantClear(&index_var); + + /* invalid argument */ + V_VT(&index_var) = VT_BOOL; + V_BOOL(&index_var) = VARIANT_TRUE; + hres = IHTMLWindow2_item(window, &index_var, &result_var); + ok(hres == E_INVALIDARG, "IHTMLWindow2_item should have" + "failed with E_INVALIDARG, instead: 0x%08x\n", hres); + VariantClear(&result_var); + + /* getElementById with node name attributes */ + elem = get_doc_elem_by_id(doc, "nm1"); + test_elem_id((IUnknown*)elem, "fr1"); + IHTMLElement_Release(elem); +} + static IHTMLDocument2 *notif_doc; static BOOL doc_complete; @@ -5658,10 +5924,8 @@ typedef void (*domtest_t)(IHTMLDocument2*); static void run_domtest(const char *str, domtest_t test) { IHTMLDocument2 *doc; - IHTMLElement *body = NULL; ULONG ref; MSG msg; - HRESULT hres; doc = create_doc_with_string(str); if(!doc) @@ -5674,15 +5938,7 @@ static void run_domtest(const char *str, domtest_t test) DispatchMessage(&msg); } - hres = IHTMLDocument2_get_body(doc, &body); - ok(hres == S_OK, "get_body failed: %08x\n", hres); - - if(body) { - IHTMLElement_Release(body); - test(doc); - }else { - skip("Could not get document body. Assuming no Gecko installed.\n"); - } + test(doc); ref = IHTMLDocument2_Release(doc); ok(!ref || @@ -5690,39 +5946,8 @@ static void run_domtest(const char *str, domtest_t test) "ref = %d\n", ref); } -static void gecko_installer_workaround(BOOL disable) -{ - HKEY hkey; - DWORD res; - - static BOOL has_url = FALSE; - static char url[2048]; - - if(!disable && !has_url) - return; - - res = RegOpenKey(HKEY_CURRENT_USER, "Software\\Wine\\MSHTML", &hkey); - if(res != ERROR_SUCCESS) - return; - - if(disable) { - DWORD type, size = sizeof(url); - - res = RegQueryValueEx(hkey, "GeckoUrl", NULL, &type, (PVOID)url, &size); - if(res == ERROR_SUCCESS && type == REG_SZ) - has_url = TRUE; - - RegDeleteValue(hkey, "GeckoUrl"); - }else { - RegSetValueEx(hkey, "GeckoUrl", 0, REG_SZ, (PVOID)url, lstrlenA(url)+1); - } - - RegCloseKey(hkey); -} - START_TEST(dom) { - gecko_installer_workaround(TRUE); CoInitialize(NULL); run_domtest(doc_str1, test_doc_elem); @@ -5734,11 +5959,12 @@ START_TEST(dom) }else { skip("IE running in Enhanced Security Configuration\n"); } + run_domtest(elem_test2_str, test_elems2); run_domtest(doc_blank, test_create_elems); run_domtest(doc_blank, test_defaults); run_domtest(indent_test_str, test_indent); run_domtest(cond_comment_str, test_cond_comment); + run_domtest(frameset_str, test_frameset); CoUninitialize(); - gecko_installer_workaround(FALSE); } diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 9d23775e79b..1f4b466b582 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -27,6 +27,7 @@ #include "winbase.h" #include "ole2.h" #include "mshtml.h" +#include "mshtmdid.h" #include "docobj.h" #include "hlink.h" #include "dispex.h" @@ -61,6 +62,7 @@ DEFINE_EXPECT(body_onclick); DEFINE_EXPECT(div_onclick); DEFINE_EXPECT(div_onclick_attached); DEFINE_EXPECT(timeout); +DEFINE_EXPECT(doccp_onclick); static HWND container_hwnd = NULL; static IHTMLWindow2 *window; @@ -847,6 +849,74 @@ static HRESULT WINAPI nocall(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFla EVENT_HANDLER_FUNC_OBJ(nocall); +#define CONNECTION_POINT_OBJ(cpname, diid) \ + static HRESULT WINAPI cpname ## _QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) \ + { \ + *ppv = NULL; \ + if(IsEqualGUID(riid, &IID_IUnknown) \ + || IsEqualGUID(riid, &IID_IDispatch) \ + || IsEqualGUID(riid, &diid)) \ + *ppv = iface; \ + else { \ + ok(0, "unexpected riid %s\n", debugstr_guid(riid)); \ + return E_NOINTERFACE; \ + } \ + return S_OK; \ + } \ + static IDispatchExVtbl cpname ## Vtbl = { \ + cpname ## _QueryInterface, \ + DispatchEx_AddRef, \ + DispatchEx_Release, \ + DispatchEx_GetTypeInfoCount, \ + DispatchEx_GetTypeInfo, \ + DispatchEx_GetIDsOfNames, \ + cpname, \ + DispatchEx_GetDispID, \ + DispatchEx_InvokeEx, \ + DispatchEx_DeleteMemberByName, \ + DispatchEx_DeleteMemberByDispID, \ + DispatchEx_GetMemberProperties, \ + DispatchEx_GetMemberName, \ + DispatchEx_GetNextDispID, \ + DispatchEx_GetNameSpaceParent \ + }; \ + static IDispatchEx cpname ## _obj = { &cpname ## Vtbl } + +#define test_cp_args(a,b,c,d,e,f) _test_cp_args(__LINE__,a,b,c,d,e,f) +static void _test_cp_args(unsigned line, REFIID riid, WORD flags, DISPPARAMS *dp, VARIANT *vres, EXCEPINFO *ei, UINT *argerr) +{ + ok_(__FILE__,line)(IsEqualGUID(&IID_NULL, riid), "riid = %s\n", debugstr_guid(riid)); + ok_(__FILE__,line)(flags == DISPATCH_METHOD, "flags = %x\n", flags); + ok_(__FILE__,line)(dp != NULL, "dp == NULL\n"); + ok_(__FILE__,line)(!dp->cArgs, "dp->cArgs = %d\n", dp->cArgs); + ok_(__FILE__,line)(!dp->rgvarg, "dp->rgvarg = %p\n", dp->rgvarg); + ok_(__FILE__,line)(!dp->cNamedArgs, "dp->cNamedArgs = %d\n", dp->cNamedArgs); + ok_(__FILE__,line)(!dp->rgdispidNamedArgs, "dp->rgdispidNamedArgs = %p\n", dp->rgdispidNamedArgs); + ok_(__FILE__,line)(vres != NULL, "vres == NULL\n"); + ok_(__FILE__,line)(V_VT(vres) == VT_EMPTY, "V_VT(vres) = %d\n", V_VT(vres)); + ok_(__FILE__,line)(ei != NULL, "ei == NULL\n"); + ok_(__FILE__,line)(argerr != NULL, "argerr == NULL\n"); +} + +static HRESULT WINAPI doccp(IDispatchEx *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pVarResult, EXCEPINFO *pei, UINT *puArgErr) +{ + switch(dispIdMember) { + case DISPID_HTMLDOCUMENTEVENTS_ONCLICK: + CHECK_EXPECT(doccp_onclick); + test_cp_args(riid, wFlags, pdp, pVarResult, pei, puArgErr); + break; + default: + ok(0, "unexpected call %d\n", dispIdMember); + return E_NOTIMPL; + } + + return S_OK; +} + +CONNECTION_POINT_OBJ(doccp, DIID_HTMLDocumentEvents); + static HRESULT WINAPI timeoutFunc_Invoke(IDispatchEx *iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) @@ -899,9 +969,51 @@ static void pump_msgs(BOOL *b) } } +static IConnectionPoint *get_cp(IUnknown *unk, REFIID riid) +{ + IConnectionPointContainer *cp_container; + IConnectionPoint *cp; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IConnectionPointContainer, (void**)&cp_container); + ok(hres == S_OK, "Could not get IConnectionPointContainer: %08x\n", hres); + + hres = IConnectionPointContainer_FindConnectionPoint(cp_container, riid, &cp); + IConnectionPointContainer_Release(cp_container); + ok(hres == S_OK, "FindConnectionPoint failed: %08x\n", hres); + + return cp; +} + +static DWORD register_cp(IUnknown *unk, REFIID riid, IUnknown *sink) +{ + IConnectionPoint *cp; + DWORD cookie; + HRESULT hres; + + cp = get_cp(unk, riid); + hres = IConnectionPoint_Advise(cp, sink, &cookie); + IConnectionPoint_Release(cp); + ok(hres == S_OK, "Advise failed: %08x\n", hres); + + return cookie; +} + +static void unregister_cp(IUnknown *unk, REFIID riid, DWORD cookie) +{ + IConnectionPoint *cp; + HRESULT hres; + + cp = get_cp(unk, riid); + hres = IConnectionPoint_Unadvise(cp, cookie); + IConnectionPoint_Release(cp); + ok(hres == S_OK, "Unadvise failed: %08x\n", hres); +} + static void test_onclick(IHTMLDocument2 *doc) { IHTMLElement *div, *body; + DWORD cp_cookie; VARIANT v; HRESULT hres; @@ -991,6 +1103,25 @@ static void test_onclick(IHTMLDocument2 *doc) CHECK_CALLED(body_onclick); CHECK_CALLED(document_onclick); + cp_cookie = register_cp((IUnknown*)doc, &DIID_HTMLDocumentEvents, (IUnknown*)&doccp_obj); + + SET_EXPECT(div_onclick); + SET_EXPECT(div_onclick_attached); + SET_EXPECT(body_onclick); + SET_EXPECT(document_onclick); + SET_EXPECT(doccp_onclick); + + hres = IHTMLElement_click(div); + ok(hres == S_OK, "click failed: %08x\n", hres); + + CHECK_CALLED(div_onclick); + CHECK_CALLED(div_onclick_attached); + CHECK_CALLED(body_onclick); + CHECK_CALLED(document_onclick); + CHECK_CALLED(doccp_onclick); + + unregister_cp((IUnknown*)doc, &DIID_HTMLDocumentEvents, cp_cookie); + IHTMLElement_Release(div); IHTMLElement_Release(body); } diff --git a/dlls/mshtml/tests/htmldoc.c b/dlls/mshtml/tests/htmldoc.c index 79d77863243..08973f61fa5 100644 --- a/dlls/mshtml/tests/htmldoc.c +++ b/dlls/mshtml/tests/htmldoc.c @@ -184,7 +184,6 @@ static const WCHAR about_blank_url[] = {'a','b','o','u','t',':','b','l','a','n', static HRESULT QueryInterface(REFIID riid, void **ppv); static void test_MSHTML_QueryStatus(IUnknown*,DWORD); -static BOOL nogecko = FALSE; #define test_readyState(u) _test_readyState(__LINE__,u) static void _test_readyState(unsigned,IUnknown*); @@ -2919,26 +2918,12 @@ static void test_download(DWORD flags) if(flags & DWL_TRYCSS) SET_CALLED(Exec_ShellDocView_84); if(flags & DWL_CSS) { - if(called_CreateInstance) { - CHECK_CALLED(CreateInstance); - CHECK_CALLED(Start); - CHECK_CALLED(LockRequest); - CHECK_CALLED(Terminate); - CHECK_CALLED(Protocol_Read); - CHECK_CALLED(UnlockRequest); - }else { - skip("CreateInstance not called. Assuming no Gecko installed.\n"); - - SET_CALLED(Exec_ShellDocView_84); - SET_CALLED(CreateInstance); - SET_CALLED(Start); - SET_CALLED(LockRequest); - SET_CALLED(Terminate); - SET_CALLED(Protocol_Read); - SET_CALLED(UnlockRequest); - - nogecko = TRUE; - } + CHECK_CALLED(CreateInstance); + CHECK_CALLED(Start); + CHECK_CALLED(LockRequest); + CHECK_CALLED(Terminate); + CHECK_CALLED(Protocol_Read); + CHECK_CALLED(UnlockRequest); } SET_CALLED(Exec_Explorer_69); SET_CALLED(EnableModeless_TRUE); /* IE7 */ @@ -3327,13 +3312,12 @@ static void test_exec_fontname(IUnknown *unk, LPCWSTR name, LPCWSTR exname) } hres = IOleCommandTarget_Exec(cmdtrg, &CGID_MSHTML, IDM_FONTNAME, 0, in, out); - if(!nogecko) - ok(hres == S_OK, "Exec(IDM_FONTNAME) failed: %08x\n", hres); + ok(hres == S_OK, "Exec(IDM_FONTNAME) failed: %08x\n", hres); if(in) VariantClear(in); - if(out && !nogecko) { + if(out) { ok(V_VT(out) == VT_BSTR, "V_VT(out) = %x\n", V_VT(out)); if(V_VT(out) == VT_BSTR) { if(exname) @@ -4300,17 +4284,15 @@ static void test_editing_mode(BOOL do_load) test_exec_noargs(unk, IDM_JUSTIFYRIGHT); test_timer(EXPECT_UPDATEUI); - if(!nogecko) - test_QueryStatus(unk, &CGID_MSHTML, IDM_JUSTIFYRIGHT, - OLECMDF_SUPPORTED|OLECMDF_ENABLED|OLECMDF_LATCHED); + test_QueryStatus(unk, &CGID_MSHTML, IDM_JUSTIFYRIGHT, + OLECMDF_SUPPORTED|OLECMDF_ENABLED|OLECMDF_LATCHED); test_exec_noargs(unk, IDM_JUSTIFYCENTER); test_timer(EXPECT_UPDATEUI); test_QueryStatus(unk, &CGID_MSHTML, IDM_JUSTIFYRIGHT, OLECMDF_SUPPORTED|OLECMDF_ENABLED); - if(!nogecko) - test_QueryStatus(unk, &CGID_MSHTML, IDM_JUSTIFYCENTER, - OLECMDF_SUPPORTED|OLECMDF_ENABLED|OLECMDF_LATCHED); + test_QueryStatus(unk, &CGID_MSHTML, IDM_JUSTIFYCENTER, + OLECMDF_SUPPORTED|OLECMDF_ENABLED|OLECMDF_LATCHED); test_exec_noargs(unk, IDM_HORIZONTALLINE); test_timer(EXPECT_UPDATEUI); @@ -4348,36 +4330,6 @@ static void register_protocol(void) IInternetSession_Release(session); } -static void gecko_installer_workaround(BOOL disable) -{ - HKEY hkey; - DWORD res; - - static BOOL has_url = FALSE; - static char url[2048]; - - if(!disable && !has_url) - return; - - res = RegOpenKey(HKEY_CURRENT_USER, "Software\\Wine\\MSHTML", &hkey); - if(res != ERROR_SUCCESS) - return; - - if(disable) { - DWORD type, size = sizeof(url); - - res = RegQueryValueEx(hkey, "GeckoUrl", NULL, &type, (PVOID)url, &size); - if(res == ERROR_SUCCESS && type == REG_SZ) - has_url = TRUE; - - RegDeleteValue(hkey, "GeckoUrl"); - }else { - RegSetValueEx(hkey, "GeckoUrl", 0, REG_SZ, (PVOID)url, lstrlenA(url)+1); - } - - RegCloseKey(hkey); -} - static void test_HTMLDoc_ISupportErrorInfo(void) { HRESULT hres; @@ -4425,8 +4377,6 @@ static void test_IPersistHistory(void) START_TEST(htmldoc) { - gecko_installer_workaround(TRUE); - CoInitialize(NULL); container_hwnd = create_container_window(); register_protocol(); @@ -4445,6 +4395,4 @@ START_TEST(htmldoc) DestroyWindow(container_hwnd); CoUninitialize(); - - gecko_installer_workaround(FALSE); } diff --git a/dlls/mshtml/tests/script.c b/dlls/mshtml/tests/script.c index 8daa9bcb3fe..22ed48e420f 100644 --- a/dlls/mshtml/tests/script.c +++ b/dlls/mshtml/tests/script.c @@ -121,6 +121,7 @@ DEFINE_EXPECT(AXGetInterfaceSafetyOptions); DEFINE_EXPECT(AXSetInterfaceSafetyOptions); #define TESTSCRIPT_CLSID "{178fc163-f585-4e24-9c13-4bb7faf80746}" +#define TESTACTIVEX_CLSID "{178fc163-f585-4e24-9c13-4bb7faf80646}" #define DISPID_SCRIPT_TESTPROP 0x100000 @@ -133,6 +134,7 @@ static IHTMLDocument2 *notif_doc; static IDispatchEx *window_dispex; static BOOL doc_complete; static IDispatch *script_disp; +static BOOL ax_objsafe; static const char *debugstr_guid(REFIID riid) { @@ -165,6 +167,28 @@ static BSTR a2bstr(const char *str) return ret; } +static BOOL init_key(const char *key_name, const char *def_value, BOOL init) +{ + HKEY hkey; + DWORD res; + + if(!init) { + RegDeleteKey(HKEY_CLASSES_ROOT, key_name); + return TRUE; + } + + res = RegCreateKeyA(HKEY_CLASSES_ROOT, key_name, &hkey); + if(res != ERROR_SUCCESS) + return FALSE; + + if(def_value) + res = RegSetValueA(hkey, NULL, REG_SZ, def_value, strlen(def_value)); + + RegCloseKey(hkey); + + return res == ERROR_SUCCESS; +} + static HRESULT WINAPI PropertyNotifySink_QueryInterface(IPropertyNotifySink *iface, REFIID riid, void**ppv) { @@ -492,7 +516,6 @@ static IHTMLDocument2 *create_and_load_doc(const char *str) { IHTMLDocument2 *doc; IHTMLElement *body = NULL; - ULONG ref; MSG msg; HRESULT hres; static const WCHAR ucPtr[] = {'b','a','c','k','g','r','o','u','n','d',0}; @@ -511,13 +534,6 @@ static IHTMLDocument2 *create_and_load_doc(const char *str) hres = IHTMLDocument2_get_body(doc, &body); ok(hres == S_OK, "get_body failed: %08x\n", hres); - if(!body) { - skip("Could not get document body. Assuming no Gecko installed.\n"); - ref = IHTMLDocument2_Release(doc); - ok(!ref, "ref = %d\n", ref); - return NULL; - } - /* Check we can query for function on the IHTMLElementBody interface */ name = (WCHAR*)ucPtr; hres = IHTMLElement_GetIDsOfNames(body, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispID); @@ -599,6 +615,8 @@ static HRESULT WINAPI AXObjectSafety_QueryInterface(IObjectSafety *iface, REFIID if(IsEqualGUID(&IID_IObjectSafety, riid)) { CHECK_EXPECT(AXQueryInterface_IObjectSafety); + if(!ax_objsafe) + return E_NOINTERFACE; *ppv = iface; return S_OK; } @@ -647,6 +665,12 @@ static const IObjectSafetyVtbl AXObjectSafetyVtbl = { static IObjectSafety AXObjectSafety = { &AXObjectSafetyVtbl }; +static BOOL set_safe_reg(BOOL init) +{ + return init_key("CLSID\\"TESTACTIVEX_CLSID"\\Implemented Categories\\{7dd95801-9882-11cf-9fa9-00aa006c42c4}", + NULL, init); +} + static void test_security(void) { IInternetHostSecurityManager *sec_mgr; @@ -673,6 +697,7 @@ static void test_security(void) cs.pUnk = (IUnknown*)&AXObjectSafety; cs.dwFlags = 0; + ax_objsafe = TRUE; SET_EXPECT(AXQueryInterface_IActiveScript); SET_EXPECT(AXQueryInterface_IObjectSafety); SET_EXPECT(AXGetInterfaceSafetyOptions); @@ -689,6 +714,55 @@ static void test_security(void) ok(*(DWORD*)ppolicy == URLPOLICY_ALLOW, "policy = %x\n", *(DWORD*)ppolicy); CoTaskMemFree(ppolicy); + ax_objsafe = FALSE; + SET_EXPECT(AXQueryInterface_IActiveScript); + SET_EXPECT(AXQueryInterface_IObjectSafety); + hres = IInternetHostSecurityManager_QueryCustomPolicy(sec_mgr, &GUID_CUSTOM_CONFIRMOBJECTSAFETY, + &ppolicy, &policy_size, (BYTE*)&cs, sizeof(cs), 0); + CHECK_CALLED(AXQueryInterface_IActiveScript); + CHECK_CALLED(AXQueryInterface_IObjectSafety); + + ok(hres == S_OK, "QueryCusromPolicy failed: %08x\n", hres); + ok(policy_size == sizeof(DWORD), "policy_size = %d\n", policy_size); + ok(*(DWORD*)ppolicy == URLPOLICY_DISALLOW, "policy = %x\n", *(DWORD*)ppolicy); + CoTaskMemFree(ppolicy); + + if(set_safe_reg(TRUE)) { + ax_objsafe = FALSE; + SET_EXPECT(AXQueryInterface_IActiveScript); + SET_EXPECT(AXQueryInterface_IObjectSafety); + hres = IInternetHostSecurityManager_QueryCustomPolicy(sec_mgr, &GUID_CUSTOM_CONFIRMOBJECTSAFETY, + &ppolicy, &policy_size, (BYTE*)&cs, sizeof(cs), 0); + CHECK_CALLED(AXQueryInterface_IActiveScript); + CHECK_CALLED(AXQueryInterface_IObjectSafety); + + ok(hres == S_OK, "QueryCusromPolicy failed: %08x\n", hres); + ok(policy_size == sizeof(DWORD), "policy_size = %d\n", policy_size); + ok(*(DWORD*)ppolicy == URLPOLICY_ALLOW, "policy = %x\n", *(DWORD*)ppolicy); + CoTaskMemFree(ppolicy); + + ax_objsafe = TRUE; + SET_EXPECT(AXQueryInterface_IActiveScript); + SET_EXPECT(AXQueryInterface_IObjectSafety); + SET_EXPECT(AXGetInterfaceSafetyOptions); + SET_EXPECT(AXSetInterfaceSafetyOptions); + hres = IInternetHostSecurityManager_QueryCustomPolicy(sec_mgr, &GUID_CUSTOM_CONFIRMOBJECTSAFETY, + &ppolicy, &policy_size, (BYTE*)&cs, sizeof(cs), 0); + CHECK_CALLED(AXQueryInterface_IActiveScript); + CHECK_CALLED(AXQueryInterface_IObjectSafety); + CHECK_CALLED(AXGetInterfaceSafetyOptions); + CHECK_CALLED(AXSetInterfaceSafetyOptions); + + ok(hres == S_OK, "QueryCusromPolicy failed: %08x\n", hres); + ok(policy_size == sizeof(DWORD), "policy_size = %d\n", policy_size); + ok(*(DWORD*)ppolicy == URLPOLICY_ALLOW, "policy = %x\n", *(DWORD*)ppolicy); + CoTaskMemFree(ppolicy); + + set_safe_reg(FALSE); + }else { + skip("Could not set safety registry\n"); + } + IInternetHostSecurityManager_Release(sec_mgr); } @@ -1510,28 +1584,6 @@ static void test_simple_script(void) CHECK_CALLED(Close); } -static BOOL init_key(const char *key_name, const char *def_value, BOOL init) -{ - HKEY hkey; - DWORD res; - - if(!init) { - RegDeleteKey(HKEY_CLASSES_ROOT, key_name); - return TRUE; - } - - res = RegCreateKeyA(HKEY_CLASSES_ROOT, key_name, &hkey); - if(res != ERROR_SUCCESS) - return FALSE; - - if(def_value) - res = RegSetValueA(hkey, NULL, REG_SZ, def_value, strlen(def_value)); - - RegCloseKey(hkey); - - return res == ERROR_SUCCESS; -} - static BOOL init_registry(BOOL init) { return init_key("TestScript\\CLSID", TESTSCRIPT_CLSID, init) @@ -1558,39 +1610,8 @@ static BOOL register_script_engine(void) return TRUE; } -static void gecko_installer_workaround(BOOL disable) -{ - HKEY hkey; - DWORD res; - - static BOOL has_url = FALSE; - static char url[2048]; - - if(!disable && !has_url) - return; - - res = RegOpenKey(HKEY_CURRENT_USER, "Software\\Wine\\MSHTML", &hkey); - if(res != ERROR_SUCCESS) - return; - - if(disable) { - DWORD type, size = sizeof(url); - - res = RegQueryValueEx(hkey, "GeckoUrl", NULL, &type, (PVOID)url, &size); - if(res == ERROR_SUCCESS && type == REG_SZ) - has_url = TRUE; - - RegDeleteValue(hkey, "GeckoUrl"); - }else { - RegSetValueEx(hkey, "GeckoUrl", 0, REG_SZ, (PVOID)url, lstrlenA(url)+1); - } - - RegCloseKey(hkey); -} - START_TEST(script) { - gecko_installer_workaround(TRUE); CoInitialize(NULL); if(winetest_interactive || ! is_ie_hardened()) { @@ -1605,5 +1626,4 @@ START_TEST(script) } CoUninitialize(); - gecko_installer_workaround(FALSE); } diff --git a/dlls/msi/action.c b/dlls/msi/action.c index 3a11c616a82..0755f428675 100644 --- a/dlls/msi/action.c +++ b/dlls/msi/action.c @@ -716,7 +716,6 @@ static UINT msi_set_context(MSIPACKAGE *package) package->Context = MSIINSTALLCONTEXT_MACHINE; } - MSI_SetPropertyW(package, szAllUsers, szOne); return ERROR_SUCCESS; } diff --git a/dlls/msi/files.c b/dlls/msi/files.c index d9470df01fc..7e74dca9696 100644 --- a/dlls/msi/files.c +++ b/dlls/msi/files.c @@ -155,7 +155,7 @@ static UINT copy_install_file(MSIPACKAGE *package, MSIFILE *file, LPWSTR source) gle = copy_file(file, source); TRACE("Overwriting existing file: %d\n", gle); } - if (gle == ERROR_SHARING_VIOLATION) + if (gle == ERROR_SHARING_VIOLATION || gle == ERROR_USER_MAPPED_FILE) { WCHAR tmpfileW[MAX_PATH], *pathW, *p; DWORD len; diff --git a/dlls/msi/media.c b/dlls/msi/media.c index bc60b60ad4e..67d73ccfcaf 100644 --- a/dlls/msi/media.c +++ b/dlls/msi/media.c @@ -362,7 +362,7 @@ static INT_PTR cabinet_copy_file(FDINOTIFICATIONTYPE fdint, if (handle != INVALID_HANDLE_VALUE) goto done; err = GetLastError(); } - if (err == ERROR_SHARING_VIOLATION) + if (err == ERROR_SHARING_VIOLATION || err == ERROR_USER_MAPPED_FILE) { WCHAR tmpfileW[MAX_PATH], *tmppathW, *p; DWORD len; diff --git a/dlls/msi/package.c b/dlls/msi/package.c index 87f1092c9e9..574289fb3f1 100644 --- a/dlls/msi/package.c +++ b/dlls/msi/package.c @@ -345,7 +345,7 @@ static VOID set_installer_properties(MSIPACKAGE *package) WCHAR *ptr; OSVERSIONINFOEXW OSVersion; MEMORYSTATUSEX msex; - DWORD verval; + DWORD verval, len; WCHAR verstr[10], bufstr[20]; HDC dc; HKEY hkey; @@ -445,11 +445,12 @@ static VOID set_installer_properties(MSIPACKAGE *package) static const WCHAR szUserLangID[] = {'U','s','e','r','L','a','n','g','u','a','g','e','I','D',0}; static const WCHAR szSystemLangID[] = {'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0}; static const WCHAR szProductState[] = {'P','r','o','d','u','c','t','S','t','a','t','e',0}; + static const WCHAR szLogonUser[] = {'L','o','g','o','n','U','s','e','r',0}; /* * Other things that probably should be set: * - * ComputerName LogonUser VirtualMemory + * ComputerName VirtualMemory * ShellAdvSupport DefaultUIFont PackagecodeChanging * CaptionHeight BorderTop BorderSide TextHeight * RedirectedDllSupport @@ -653,6 +654,18 @@ static VOID set_installer_properties(MSIPACKAGE *package) sprintfW(bufstr, szIntFormat, MsiQueryProductStateW(package->ProductCode)); MSI_SetPropertyW( package, szProductState, bufstr ); + + len = 0; + if (!GetUserNameW( NULL, &len ) && GetLastError() == ERROR_MORE_DATA) + { + WCHAR *username; + if ((username = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) + { + if (GetUserNameW( username, &len )) + MSI_SetPropertyW( package, szLogonUser, username ); + HeapFree( GetProcessHeap(), 0, username ); + } + } } static UINT msi_load_summary_properties( MSIPACKAGE *package ) diff --git a/dlls/msi/select.c b/dlls/msi/select.c index c4b9e804c07..f6b5daef2f9 100644 --- a/dlls/msi/select.c +++ b/dlls/msi/select.c @@ -368,12 +368,14 @@ static const MSIVIEWOPS select_ops = NULL, }; -static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPCWSTR name ) +static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPCWSTR name, + LPCWSTR table_name ) { UINT r, n=0; MSIVIEW *table; - TRACE("%p adding %s\n", sv, debugstr_w( name ) ); + TRACE("%p adding %s.%s\n", sv, debugstr_w( table_name ), + debugstr_w( name )); if( sv->view.ops != &select_ops ) return ERROR_FUNCTION_FAILED; @@ -389,7 +391,7 @@ static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPCWSTR name ) if( sv->num_cols >= sv->max_cols ) return ERROR_FUNCTION_FAILED; - r = VIEW_find_column( table, name, NULL, &n ); + r = VIEW_find_column( table, name, table_name, &n ); if( r != ERROR_SUCCESS ) return r; @@ -433,7 +435,7 @@ UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, while( columns ) { - r = SELECT_AddColumn( sv, columns->column ); + r = SELECT_AddColumn( sv, columns->column, columns->table ); if( r ) break; columns = columns->next; diff --git a/dlls/msi/storages.c b/dlls/msi/storages.c index 005bcdb663e..844db8d0a82 100644 --- a/dlls/msi/storages.c +++ b/dlls/msi/storages.c @@ -296,6 +296,7 @@ static UINT STORAGES_get_column_info(struct tagMSIVIEW *view, UINT n, static const WCHAR Name[] = {'N','a','m','e',0}; static const WCHAR Data[] = {'D','a','t','a',0}; + static const WCHAR _Storages[] = {'_','S','t','o','r','a','g','e','s',0}; TRACE("(%p, %d, %p, %p, %p, %p)\n", view, n, name, type, temporary, table_name); @@ -322,6 +323,16 @@ static UINT STORAGES_get_column_info(struct tagMSIVIEW *view, UINT n, if (!*name) return ERROR_FUNCTION_FAILED; } + if (table_name) + { + *table_name = strdupW(_Storages); + if (!*table_name) + { + msi_free(name); + return ERROR_FUNCTION_FAILED; + } + } + if (temporary) *temporary = FALSE; diff --git a/dlls/msi/streams.c b/dlls/msi/streams.c index 23ae971c7d8..faa27c8cb8f 100644 --- a/dlls/msi/streams.c +++ b/dlls/msi/streams.c @@ -262,6 +262,7 @@ static UINT STREAMS_get_column_info(struct tagMSIVIEW *view, UINT n, static const WCHAR Name[] = {'N','a','m','e',0}; static const WCHAR Data[] = {'D','a','t','a',0}; + static const WCHAR _Streams[] = {'_','S','t','r','e','a','m','s',0}; TRACE("(%p, %d, %p, %p, %p, %p)\n", view, n, name, type, temporary, table_name); @@ -288,6 +289,16 @@ static UINT STREAMS_get_column_info(struct tagMSIVIEW *view, UINT n, if (!*name) return ERROR_FUNCTION_FAILED; } + if (table_name) + { + *table_name = strdupW(_Streams); + if (!*table_name) + { + msi_free(name); + return ERROR_FUNCTION_FAILED; + } + } + if (temporary) *temporary = FALSE; diff --git a/dlls/msi/table.c b/dlls/msi/table.c index 33d1fce64c6..fa32a04a21e 100644 --- a/dlls/msi/table.c +++ b/dlls/msi/table.c @@ -1201,7 +1201,7 @@ static UINT msi_stream_name( const MSITABLEVIEW *tv, UINT row, LPWSTR *pstname ) switch( n ) { case 2: - sprintfW( number, fmt, ival^0x8000 ); + sprintfW( number, fmt, ival-0x8000 ); break; case 4: sprintfW( number, fmt, ival^0x80000000 ); @@ -2573,7 +2573,7 @@ static MSIRECORD *msi_get_transform_record( const MSITABLEVIEW *tv, const string case 2: val = read_raw_int(rawdata, ofs, n); if (val) - MSI_RecordSetInteger( rec, i+1, val^0x8000 ); + MSI_RecordSetInteger( rec, i+1, val-0x8000 ); TRACE(" field %d [0x%04x]\n", i+1, val ); break; case 4: diff --git a/dlls/msi/tests/automation.c b/dlls/msi/tests/automation.c index 4af37aa8219..29a7cd2b60b 100644 --- a/dlls/msi/tests/automation.c +++ b/dlls/msi/tests/automation.c @@ -1506,8 +1506,7 @@ static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *in hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var)); ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr); - /* FIXME: Off by one second */ - todo_wine ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult)); + ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult)); VariantClear(&varresult); VariantClear(&var); diff --git a/dlls/msi/tests/db.c b/dlls/msi/tests/db.c index 19cd74cd646..041e8605bd0 100644 --- a/dlls/msi/tests/db.c +++ b/dlls/msi/tests/db.c @@ -7901,6 +7901,80 @@ static void test_dbmerge(void) DeleteFileA("binary.dat"); } +static void test_select_with_tablenames(void) +{ + MSIHANDLE hdb, view, rec; + LPCSTR query; + UINT r; + int i; + + int vals[4][2] = { + {1,12}, + {4,12}, + {1,15}, + {4,15}}; + + hdb = create_db(); + ok(hdb, "failed to create db\n"); + + /* Build a pair of tables with the same column names, but unique data */ + query = "CREATE TABLE `T1` ( `A` SHORT, `B` SHORT PRIMARY KEY `A`)"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "INSERT INTO `T1` ( `A`, `B` ) VALUES ( 1, 2 )"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "INSERT INTO `T1` ( `A`, `B` ) VALUES ( 4, 5 )"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "CREATE TABLE `T2` ( `A` SHORT, `B` SHORT PRIMARY KEY `A`)"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "INSERT INTO `T2` ( `A`, `B` ) VALUES ( 11, 12 )"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "INSERT INTO `T2` ( `A`, `B` ) VALUES ( 14, 15 )"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + + /* Test that selection based on prefixing the column with the table + * actually selects the right data */ + + query = "SELECT T1.A, T2.B FROM T1,T2"; + r = MsiDatabaseOpenView(hdb, query, &view); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiViewExecute(view, 0); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + for (i = 0; i < 4; i++) + { + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiRecordGetInteger(rec, 1); + ok(r == vals[i][0], "Expected %d, got %d\n", vals[i][0], r); + + r = MsiRecordGetInteger(rec, 2); + ok(r == vals[i][1], "Expected %d, got %d\n", vals[i][1], r); + + MsiCloseHandle(rec); + } + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + + MsiViewClose(view); + MsiCloseHandle(view); + MsiCloseHandle(hdb); + DeleteFileA(msifile); +} + UINT ordervals[6][3] = { { MSI_NULL_INTEGER, 12, 13 }, @@ -8579,6 +8653,7 @@ START_TEST(db) test_dbtopackage(); test_droptable(); test_dbmerge(); + test_select_with_tablenames(); test_insertorder(); test_columnorder(); test_suminfo_import(); diff --git a/dlls/msi/tests/install.c b/dlls/msi/tests/install.c index c6fd1ca4701..a0075389175 100644 --- a/dlls/msi/tests/install.c +++ b/dlls/msi/tests/install.c @@ -920,6 +920,32 @@ static const CHAR ip_custom_action_dat[] = "Action\tType\tSource\tTarget\tISComm "CustomAction\tAction\n" "TestInstalledProp\t19\t\tTest failed\t\n"; +static const CHAR aup_install_exec_seq_dat[] = "Action\tCondition\tSequence\n" + "s72\tS255\tI2\n" + "InstallExecuteSequence\tAction\n" + "CostFinalize\t\t1000\n" + "ValidateProductID\t\t700\n" + "CostInitialize\t\t800\n" + "FileCost\t\t900\n" + "RemoveFiles\t\t3500\n" + "InstallFiles\t\t4000\n" + "RegisterUser\t\t6000\n" + "RegisterProduct\t\t6100\n" + "PublishFeatures\t\t6300\n" + "PublishProduct\t\t6400\n" + "InstallFinalize\t\t6600\n" + "InstallInitialize\t\t1500\n" + "ProcessComponents\t\t1600\n" + "UnpublishFeatures\t\t1800\n" + "InstallValidate\t\t1400\n" + "LaunchConditions\t\t100\n" + "TestAllUsersProp\tALLUSERS AND NOT REMOVE\t50\n"; + +static const CHAR aup_custom_action_dat[] = "Action\tType\tSource\tTarget\tISComments\n" + "s72\ti2\tS64\tS0\tS255\n" + "CustomAction\tAction\n" + "TestAllUsersProp\t19\t\tTest failed\t\n"; + typedef struct _msi_table { const CHAR *filename; @@ -1547,6 +1573,19 @@ static const msi_table ip_tables[] = ADD_TABLE(property) }; +static const msi_table aup_tables[] = +{ + ADD_TABLE(component), + ADD_TABLE(directory), + ADD_TABLE(feature), + ADD_TABLE(feature_comp), + ADD_TABLE(file), + ADD_TABLE(aup_install_exec_seq), + ADD_TABLE(aup_custom_action), + ADD_TABLE(media), + ADD_TABLE(property) +}; + static const msi_table fiu_tables[] = { ADD_TABLE(rof_component), @@ -6730,6 +6769,37 @@ static void test_installed_prop(void) delete_test_files(); } +static void test_allusers_prop(void) +{ + UINT r; + + create_test_files(); + create_database(msifile, aup_tables, sizeof(aup_tables) / sizeof(msi_table)); + + MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); + + r = MsiInstallProductA(msifile, "FULL=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\changed", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\first", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\filename", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\one.txt", TRUE), "File installed\n"); + ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + r = MsiInstallProductA(msifile, "REMOVE=ALL"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + delete_test_files(); +} + static char session_manager[] = "System\\CurrentControlSet\\Control\\Session Manager"; static char rename_ops[] = "PendingFileRenameOperations"; @@ -7065,6 +7135,7 @@ START_TEST(install) test_file_in_use(); test_file_in_use_cab(); test_MsiSetExternalUI(); + test_allusers_prop(); DeleteFileA(log_file); diff --git a/dlls/msvcr71/msvcr71.spec b/dlls/msvcr71/msvcr71.spec index 0beec0ca73a..2a35217d6ad 100644 --- a/dlls/msvcr71/msvcr71.spec +++ b/dlls/msvcr71/msvcr71.spec @@ -363,7 +363,7 @@ @ cdecl _lfind(ptr ptr ptr long ptr) msvcrt._lfind @ cdecl _loaddll(str) msvcrt._loaddll @ cdecl _local_unwind2(ptr long) msvcrt._local_unwind2 -@ stub _localtime64 +@ cdecl _localtime64(ptr) msvcrt._localtime64 @ cdecl _lock(long) msvcrt._lock @ cdecl _locking(long long long) msvcrt._locking @ cdecl _logb(double) msvcrt._logb @@ -435,7 +435,7 @@ @ cdecl _memicmp(str str long) msvcrt._memicmp @ cdecl _mkdir(str) msvcrt._mkdir @ cdecl _mktemp(str) msvcrt._mktemp -@ stub _mktime64 +@ cdecl _mktime64(ptr) msvcrt._mktime64 @ cdecl _msize(ptr) msvcrt._msize @ cdecl _nextafter(double double) msvcrt._nextafter @ cdecl _onexit(ptr) msvcrt._onexit @@ -527,7 +527,7 @@ @ cdecl _tell(long) msvcrt._tell @ cdecl -ret64 _telli64(long) msvcrt._telli64 @ cdecl _tempnam(str str) msvcrt._tempnam -@ stub _time64 +@ cdecl _time64(ptr) msvcrt._time64 @ extern _timezone msvcrt._timezone @ cdecl _tolower(long) msvcrt._tolower @ cdecl _toupper(long) msvcrt._toupper diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h index 337a17cb0d7..1de0c7ba216 100644 --- a/dlls/msvcrt/msvcrt.h +++ b/dlls/msvcrt/msvcrt.h @@ -64,8 +64,8 @@ typedef unsigned int MSVCRT__dev_t; typedef int MSVCRT__off_t; typedef int MSVCRT_clock_t; typedef int MSVCRT___time32_t; -typedef __int64 MSVCRT___time64_t; -typedef __int64 MSVCRT_fpos_t; +typedef __int64 DECLSPEC_ALIGN(8) MSVCRT___time64_t; +typedef __int64 DECLSPEC_ALIGN(8) MSVCRT_fpos_t; typedef void (*__cdecl MSVCRT_terminate_handler)(void); typedef void (*__cdecl MSVCRT_terminate_function)(void); @@ -316,7 +316,7 @@ struct MSVCRT__finddata32i64_t { MSVCRT___time32_t time_create; MSVCRT___time32_t time_access; MSVCRT___time32_t time_write; - __int64 size; + __int64 DECLSPEC_ALIGN(8) size; char name[260]; }; @@ -334,7 +334,7 @@ struct MSVCRT__finddata64_t { MSVCRT___time64_t time_create; MSVCRT___time64_t time_access; MSVCRT___time64_t time_write; - __int64 size; + __int64 DECLSPEC_ALIGN(8) size; char name[260]; }; @@ -352,7 +352,7 @@ struct MSVCRT__wfinddata32i64_t { MSVCRT___time32_t time_create; MSVCRT___time32_t time_access; MSVCRT___time32_t time_write; - __int64 size; + __int64 DECLSPEC_ALIGN(8) size; MSVCRT_wchar_t name[260]; }; @@ -370,7 +370,7 @@ struct MSVCRT__wfinddata64_t { MSVCRT___time64_t time_create; MSVCRT___time64_t time_access; MSVCRT___time64_t time_write; - __int64 size; + __int64 DECLSPEC_ALIGN(8) size; MSVCRT_wchar_t name[260]; }; diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec index ad8fa94544b..c6c749d6b6d 100644 --- a/dlls/msvcrt/msvcrt.spec +++ b/dlls/msvcrt/msvcrt.spec @@ -271,6 +271,7 @@ @ cdecl _ftime32(ptr) MSVCRT__ftime32 @ cdecl _ftime64(ptr) MSVCRT__ftime64 @ cdecl -ret64 _ftol() ntdll._ftol +@ cdecl -ret64 _ftol2_sse() ntdll._ftol #FIXME: SSE variant should be implemented @ cdecl _fullpath(ptr str long) @ cdecl _futime(long ptr) @ cdecl _futime32(long ptr) @@ -548,6 +549,7 @@ @ cdecl _wcsrev(wstr) @ cdecl _wcsset(wstr long) @ cdecl _wcsupr(wstr) ntdll._wcsupr +@ cdecl _wcsupr_s(wstr long) MSVCRT__wcsupr_s @ cdecl _wctime(ptr) MSVCRT__wctime @ cdecl _wctime32(ptr) MSVCRT__wctime32 @ cdecl _wctime64(ptr) MSVCRT__wctime64 diff --git a/dlls/msvcrt/scanf.h b/dlls/msvcrt/scanf.h index 3eb705b2376..953c133ebc8 100644 --- a/dlls/msvcrt/scanf.h +++ b/dlls/msvcrt/scanf.h @@ -266,7 +266,7 @@ _FUNCTION_ { } /* handle decimals */ if (width!=0 && nch == '.') { - float dec = 1; + long double dec = 1; nch = _GETC_(file); if (width>0) width--; while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) { diff --git a/dlls/msvcrt/tests/cpp.c b/dlls/msvcrt/tests/cpp.c index d640d674e3e..106ef73ce27 100644 --- a/dlls/msvcrt/tests/cpp.c +++ b/dlls/msvcrt/tests/cpp.c @@ -1032,6 +1032,8 @@ static void test_demangle(void) /* 111 */ {"?f@T@@QAEHQCY1BE@BO@D@Z", "public: int __thiscall T::f(char (volatile * const)[20][30])"}, /* 112 */ {"?f@T@@QAEHQAY2BE@BO@CI@D@Z", "public: int __thiscall T::f(char (* const)[20][30][40])"}, /* 113 */ {"?f@T@@QAEHQAY1BE@BO@$$CBD@Z", "public: int __thiscall T::f(char const (* const)[20][30])"}, +/* 114 */ {"??0?$Foo@U?$vector_c@H$00$01$0?1$0A@$0A@$0HPPPPPPP@$0HPPPPPPP@$0HPPPPPPP@$0HPPPPPPP@$0HPPPPPPP@$0HPPPPPPP@$0HPPPPPPP@$0HPPPPPPP@$0HPPPPPPP@$0HPPPPPPP@$0HPPPPPPP@$0HPPPPPPP@$0HPPPPPPP@$0HPPPPPPP@$0HPPPPPPP@@mpl@boost@@@@QAE@XZ", + "public: __thiscall Foo >::Foo >(void)"}, }; int i, num_test = (sizeof(test)/sizeof(test[0])); diff --git a/dlls/msvcrt/tests/string.c b/dlls/msvcrt/tests/string.c index fc2ad3c57ab..85447355027 100644 --- a/dlls/msvcrt/tests/string.c +++ b/dlls/msvcrt/tests/string.c @@ -51,6 +51,7 @@ static int (__cdecl *pstrcpy_s)(char *dst, size_t len, const char *src); static int (__cdecl *pstrcat_s)(char *dst, size_t len, const char *src); static int (__cdecl *p_mbsnbcpy_s)(unsigned char * dst, size_t size, const unsigned char * src, size_t count); static int (__cdecl *p_wcscpy_s)(wchar_t *wcDest, size_t size, const wchar_t *wcSrc); +static int (__cdecl *p_wcsupr_s)(wchar_t *str, size_t size); static int *p__mb_cur_max; static unsigned char *p_mbctype; @@ -597,6 +598,93 @@ static void test_wcscpy_s(void) ok(szDestShort[0] == 0, "szDestShort[0] not 0\n"); } +static void test__wcsupr_s(void) +{ + static const WCHAR mixedString[] = {'M', 'i', 'X', 'e', 'D', 'l', 'o', 'w', + 'e', 'r', 'U', 'P', 'P', 'E', 'R', 0}; + static const WCHAR expectedString[] = {'M', 'I', 'X', 'E', 'D', 'L', 'O', + 'W', 'E', 'R', 'U', 'P', 'P', 'E', + 'R', 0}; + WCHAR testBuffer[2*sizeof(mixedString)/sizeof(WCHAR)]; + int ret; + + if (!p_wcsupr_s) + { + win_skip("_wcsupr_s not found\n"); + return; + } + + /* Test NULL input string and invalid size. */ + errno = EBADF; + ret = p_wcsupr_s(NULL, 0); + ok(ret == EINVAL, "Expected _wcsupr_s to fail with EINVAL, got %d\n", ret); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + + /* Test NULL input string and valid size. */ + errno = EBADF; + ret = p_wcsupr_s(NULL, sizeof(testBuffer)/sizeof(WCHAR)); + ok(ret == EINVAL, "Expected _wcsupr_s to fail with EINVAL, got %d\n", ret); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + + /* Test empty string with zero size. */ + errno = EBADF; + testBuffer[0] = '\0'; + ret = p_wcsupr_s(testBuffer, 0); + ok(ret == EINVAL, "Expected _wcsupr_s to fail with EINVAL, got %d\n", ret); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + ok(testBuffer[0] == '\0', "Expected the buffer to be unchanged\n"); + + /* Test empty string with size of one. */ + testBuffer[0] = '\0'; + ret = p_wcsupr_s(testBuffer, 1); + ok(ret == 0, "Expected _wcsupr_s to succeed, got %d\n", ret); + ok(testBuffer[0] == '\0', "Expected the buffer to be unchanged\n"); + + /* Test one-byte buffer with zero size. */ + errno = EBADF; + testBuffer[0] = 'x'; + ret = p_wcsupr_s(testBuffer, 0); + ok(ret == EINVAL, "Expected _wcsupr_s to fail with EINVAL, got %d\n", ret); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + ok(testBuffer[0] == '\0', "Expected the first buffer character to be null\n"); + + /* Test one-byte buffer with size of one. */ + errno = EBADF; + testBuffer[0] = 'x'; + ret = p_wcsupr_s(testBuffer, 1); + ok(ret == EINVAL, "Expected _wcsupr_s to fail with EINVAL, got %d\n", ret); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + ok(testBuffer[0] == '\0', "Expected the first buffer character to be null\n"); + + /* Test invalid size. */ + wcscpy(testBuffer, mixedString); + errno = EBADF; + ret = p_wcsupr_s(testBuffer, 0); + ok(ret == EINVAL, "Expected _wcsupr_s to fail with EINVAL, got %d\n", ret); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + ok(testBuffer[0] == '\0', "Expected the first buffer character to be null\n"); + + /* Test normal string uppercasing. */ + wcscpy(testBuffer, mixedString); + ret = p_wcsupr_s(testBuffer, sizeof(mixedString)/sizeof(WCHAR)); + ok(ret == 0, "Expected _wcsupr_s to succeed, got %d\n", ret); + ok(!wcscmp(testBuffer, expectedString), "Expected the string to be fully upper-case\n"); + + /* Test uppercasing with a shorter buffer size count. */ + wcscpy(testBuffer, mixedString); + errno = EBADF; + ret = p_wcsupr_s(testBuffer, sizeof(mixedString)/sizeof(WCHAR) - 1); + ok(ret == EINVAL, "Expected _wcsupr_s to fail with EINVAL, got %d\n", ret); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + ok(testBuffer[0] == '\0', "Expected the first buffer character to be null\n"); + + /* Test uppercasing with a longer buffer size count. */ + wcscpy(testBuffer, mixedString); + ret = p_wcsupr_s(testBuffer, sizeof(testBuffer)/sizeof(WCHAR)); + ok(ret == 0, "Expected _wcsupr_s to succeed, got %d\n", ret); + ok(!wcscmp(testBuffer, expectedString), "Expected the string to be fully upper-case\n"); +} + static void test_mbcjisjms(void) { /* List of value-pairs to test. The test assumes the last pair to be {0, ..} */ @@ -721,6 +809,7 @@ START_TEST(string) pstrcat_s = (void *)GetProcAddress( hMsvcrt,"strcat_s" ); p_mbsnbcpy_s = (void *)GetProcAddress( hMsvcrt,"_mbsnbcpy_s" ); p_wcscpy_s = (void *)GetProcAddress( hMsvcrt,"wcscpy_s" ); + p_wcsupr_s = (void *)GetProcAddress( hMsvcrt,"_wcsupr_s" ); /* MSVCRT memcpy behaves like memmove for overlapping moves, MFC42 CString::Insert seems to rely on that behaviour */ @@ -746,5 +835,6 @@ START_TEST(string) test_mbcjisjms(); test_strtok(); test_wcscpy_s(); + test__wcsupr_s(); test_strtol(); } diff --git a/dlls/msvcrt/undname.c b/dlls/msvcrt/undname.c index d825cfc7f72..670873d586d 100644 --- a/dlls/msvcrt/undname.c +++ b/dlls/msvcrt/undname.c @@ -73,13 +73,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); * */ -#define MAX_ARRAY_ELTS 32 struct array { unsigned start; /* first valid reference in array */ unsigned num; /* total number of used elts */ unsigned max; - char* elts[MAX_ARRAY_ELTS]; + unsigned alloc; + char** elts; }; /* Structure holding a parsed symbol */ @@ -174,19 +174,36 @@ static void und_free_all(struct parsed_symbol* sym) */ static void str_array_init(struct array* a) { - a->start = a->num = a->max = 0; + a->start = a->num = a->max = a->alloc = 0; + a->elts = NULL; } /****************************************************************** * str_array_push * Adding a new string to an array */ -static void str_array_push(struct parsed_symbol* sym, const char* ptr, int len, +static BOOL str_array_push(struct parsed_symbol* sym, const char* ptr, int len, struct array* a) { + char** new; + assert(ptr); assert(a); - assert(a->num < MAX_ARRAY_ELTS); + + if (!a->alloc) + { + new = und_alloc(sym, (a->alloc = 32) * sizeof(a->elts[0])); + if (!new) return FALSE; + a->elts = new; + } + else if (a->max >= a->alloc) + { + new = und_alloc(sym, (a->alloc * 2) * sizeof(a->elts[0])); + if (!new) return FALSE; + memcpy(new, a->elts, a->alloc * sizeof(a->elts[0])); + a->alloc *= 2; + a->elts = new; + } if (len == -1) len = strlen(ptr); a->elts[a->num] = und_alloc(sym, len + 1); assert(a->elts[a->num]); @@ -205,6 +222,8 @@ static void str_array_push(struct parsed_symbol* sym, const char* ptr, int len, TRACE("%p\t%d%c %s\n", a, i, c, a->elts[i]); } } + + return TRUE; } /****************************************************************** @@ -348,6 +367,7 @@ static char* get_args(struct parsed_symbol* sym, struct array* pmt_ref, BOOL z_t struct datatype_t ct; struct array arg_collect; char* args_str = NULL; + char* last; unsigned int i; str_array_init(&arg_collect); @@ -365,8 +385,9 @@ static char* get_args(struct parsed_symbol* sym, struct array* pmt_ref, BOOL z_t return NULL; /* 'void' terminates an argument list in a function */ if (z_term && !strcmp(ct.left, "void")) break; - str_array_push(sym, str_printf(sym, "%s%s", ct.left, ct.right), -1, - &arg_collect); + if (!str_array_push(sym, str_printf(sym, "%s%s", ct.left, ct.right), -1, + &arg_collect)) + return NULL; if (!strcmp(ct.left, "...")) break; } /* Functions are always terminated by 'Z'. If we made it this far and @@ -382,7 +403,8 @@ static char* get_args(struct parsed_symbol* sym, struct array* pmt_ref, BOOL z_t args_str = str_printf(sym, "%s,%s", args_str, arg_collect.elts[i]); } - if (close_char == '>' && args_str && args_str[strlen(args_str) - 1] == '>') + last = args_str ? args_str : arg_collect.elts[0]; + if (close_char == '>' && last[strlen(last) - 1] == '>') args_str = str_printf(sym, "%c%s%s %c", open_char, arg_collect.elts[0], args_str, close_char); else @@ -496,7 +518,8 @@ static char* get_literal_string(struct parsed_symbol* sym) } } while (*++sym->current != '@'); sym->current++; - str_array_push(sym, ptr, sym->current - 1 - ptr, &sym->names); + if (!str_array_push(sym, ptr, sym->current - 1 - ptr, &sym->names)) + return NULL; return str_array_get_ref(&sym->names, sym->names.num - sym->names.start - 1); } @@ -564,17 +587,17 @@ static BOOL get_class(struct parsed_symbol* sym) if (*++sym->current == '$') { sym->current++; - if ((name = get_template_name(sym))) - str_array_push(sym, name, -1, &sym->names); + if ((name = get_template_name(sym)) && + !str_array_push(sym, name, -1, &sym->names)) + return FALSE; } break; default: name = get_literal_string(sym); break; } - if (!name) + if (!name || !str_array_push(sym, name, -1, &sym->stack)) return FALSE; - str_array_push(sym, name, -1, &sym->stack); } sym->current++; return TRUE; @@ -918,8 +941,9 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, if (add_pmt && pmt_ref && in_args) { /* left and right are pushed as two separate strings */ - str_array_push(sym, ct->left ? ct->left : "", -1, pmt_ref); - str_array_push(sym, ct->right ? ct->right : "", -1, pmt_ref); + if (!str_array_push(sym, ct->left ? ct->left : "", -1, pmt_ref) || + !str_array_push(sym, ct->right ? ct->right : "", -1, pmt_ref)) + return FALSE; } done: @@ -1326,15 +1350,16 @@ static BOOL symbol_demangle(struct parsed_symbol* sym) switch (do_after) { case 1: case 2: - sym->stack.num = sym->stack.max = 1; - sym->stack.elts[0] = dashed_null; + if (!str_array_push(sym, dashed_null, -1, &sym->stack)) + return FALSE; break; case 4: sym->result = (char*)function_name; ret = TRUE; goto done; default: - str_array_push(sym, function_name, -1, &sym->stack); + if (!str_array_push(sym, function_name, -1, &sym->stack)) + return FALSE; break; } } diff --git a/dlls/msvcrt/wcs.c b/dlls/msvcrt/wcs.c index d83dd9458b3..0f3e9eecf25 100644 --- a/dlls/msvcrt/wcs.c +++ b/dlls/msvcrt/wcs.c @@ -90,6 +90,35 @@ MSVCRT_wchar_t* CDECL _wcsset( MSVCRT_wchar_t* str, MSVCRT_wchar_t c ) return ret; } +/****************************************************************** + * _wcsupr_s (MSVCRT.@) + * + */ +INT CDECL MSVCRT__wcsupr_s( MSVCRT_wchar_t* str, MSVCRT_size_t n ) +{ + MSVCRT_wchar_t* ptr = str; + + if (!str || !n) + { + if (str) *str = '\0'; + *MSVCRT__errno() = MSVCRT_EINVAL; + return MSVCRT_EINVAL; + } + + while (n--) + { + if (!*ptr) return 0; + *ptr = toupperW(*ptr); + ptr++; + } + + /* MSDN claims that the function should return and set errno to + * ERANGE, which doesn't seem to be true based on the tests. */ + *str = '\0'; + *MSVCRT__errno() = MSVCRT_EINVAL; + return MSVCRT_EINVAL; +} + /********************************************************************* * wcstod (MSVCRT.@) */ diff --git a/dlls/msvidc32/msvideo1.c b/dlls/msvidc32/msvideo1.c index ab51e4cbbe0..3052964a835 100644 --- a/dlls/msvidc32/msvideo1.c +++ b/dlls/msvidc32/msvideo1.c @@ -132,7 +132,7 @@ msvideo1_decode_8bit( int width, int height, const unsigned char *buf, int buf_s for (pixel_y = 0; pixel_y < 4; pixel_y++) { for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1) { -#if ORIGINAL +#ifdef ORIGINAL pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1]; #else pixels[width*(height-(pixel_ptr/width)-1) + @@ -154,7 +154,7 @@ msvideo1_decode_8bit( int width, int height, const unsigned char *buf, int buf_s for (pixel_y = 0; pixel_y < 4; pixel_y++) { for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1) { -#if ORIGINAL +#ifdef ORIGINAL pixels[pixel_ptr++] = colors[((pixel_y & 0x2) << 1) + (pixel_x & 0x2) + ((flags & 0x1) ^ 1)]; @@ -175,7 +175,7 @@ msvideo1_decode_8bit( int width, int height, const unsigned char *buf, int buf_s for (pixel_y = 0; pixel_y < 4; pixel_y++) { for (pixel_x = 0; pixel_x < 4; pixel_x++) { -#if ORIGINAL +#ifdef ORIGINAL pixels[pixel_ptr++] = colors[0]; #else pixels[width*(height-(pixel_ptr/width)-1) + diff --git a/dlls/msxml3/node.c b/dlls/msxml3/node.c index 93d80320958..ed6c8c6c0aa 100644 --- a/dlls/msxml3/node.c +++ b/dlls/msxml3/node.c @@ -944,36 +944,219 @@ static HRESULT WINAPI xmlnode_get_definition( return E_NOTIMPL; } +static HRESULT WINAPI xmlnode_get_dataType(IXMLDOMNode*, VARIANT*); + +static inline BYTE hex_to_byte(xmlChar c) +{ + if(c <= '9') return c-'0'; + if(c <= 'F') return c-'A'+10; + return c-'a'+10; +} + +static inline BYTE base64_to_byte(xmlChar c) +{ + if(c == '+') return 62; + if(c == '/') return 63; + if(c <= '9') return c-'0'+52; + if(c <= 'Z') return c-'A'; + return c-'a'+26; +} + +static inline HRESULT VARIANT_from_xmlChar(xmlChar *str, VARIANT *v, BSTR type) +{ + if(!type || !lstrcmpiW(type, szString) || + !lstrcmpiW(type, szNumber) || !lstrcmpiW(type, szUUID)) + { + V_VT(v) = VT_BSTR; + V_BSTR(v) = bstr_from_xmlChar(str); + + if(!V_BSTR(v)) + return E_OUTOFMEMORY; + } + else if(!lstrcmpiW(type, szDateTime) || !lstrcmpiW(type, szDateTimeTZ) || + !lstrcmpiW(type, szDate) || !lstrcmpiW(type, szTime) || + !lstrcmpiW(type, szTimeTZ)) + { + VARIANT src; + WCHAR *p, *e; + SYSTEMTIME st; + DOUBLE date = 0.0; + + st.wYear = 1899; + st.wMonth = 12; + st.wDay = 30; + st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0; + + V_VT(&src) = VT_BSTR; + V_BSTR(&src) = bstr_from_xmlChar(str); + + if(!V_BSTR(&src)) + return E_OUTOFMEMORY; + + p = V_BSTR(&src); + e = p + SysStringLen(V_BSTR(&src)); + + if(p+4pvData)[i] = (hex_to_byte(str[2*i])<<4) + + hex_to_byte(str[2*i+1]); + } + else if(!lstrcmpiW(type, szBinBase64)) + { + SAFEARRAYBOUND sab; + int i, len; + + len = xmlStrlen(str); + if(str[len-2] == '=') i = 2; + else if(str[len-1] == '=') i = 1; + else i = 0; + + sab.lLbound = 0; + sab.cElements = len/4*3-i; + + V_VT(v) = (VT_ARRAY|VT_UI1); + V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab); + + if(!V_ARRAY(v)) + return E_OUTOFMEMORY; + + for(i=0; ipvData)[3*i] = (base64_to_byte(str[4*i])<<2) + + (base64_to_byte(str[4*i+1])>>4); + if(3*i+1 < sab.cElements) + ((BYTE*)V_ARRAY(v)->pvData)[3*i+1] = (base64_to_byte(str[4*i+1])<<4) + + (base64_to_byte(str[4*i+2])>>2); + if(3*i+2 < sab.cElements) + ((BYTE*)V_ARRAY(v)->pvData)[3*i+2] = (base64_to_byte(str[4*i+2])<<6) + + base64_to_byte(str[4*i+3]); + } + } + else + { + VARIANT src; + HRESULT hres; + + if(!lstrcmpiW(type, szInt) || !lstrcmpiW(type, szI4)) + V_VT(v) = VT_I4; + else if(!lstrcmpiW(type, szFixed)) + V_VT(v) = VT_CY; + else if(!lstrcmpiW(type, szBoolean)) + V_VT(v) = VT_BOOL; + else if(!lstrcmpiW(type, szI1)) + V_VT(v) = VT_I1; + else if(!lstrcmpiW(type, szI2)) + V_VT(v) = VT_I2; + else if(!lstrcmpiW(type, szIU1)) + V_VT(v) = VT_UI1; + else if(!lstrcmpiW(type, szIU2)) + V_VT(v) = VT_UI2; + else if(!lstrcmpiW(type, szIU4)) + V_VT(v) = VT_UI4; + else if(!lstrcmpiW(type, szR4)) + V_VT(v) = VT_R4; + else if(!lstrcmpiW(type, szR8) || !lstrcmpiW(type, szFloat)) + V_VT(v) = VT_R8; + else + { + FIXME("Type handling not yet implemented\n"); + V_VT(v) = VT_BSTR; + } + + V_VT(&src) = VT_BSTR; + V_BSTR(&src) = bstr_from_xmlChar(str); + + if(!V_BSTR(&src)) + return E_OUTOFMEMORY; + + hres = VariantChangeType(v, &src, 0, V_VT(v)); + VariantClear(&src); + return hres; + } + + return S_OK; +} + static HRESULT WINAPI xmlnode_get_nodeTypedValue( IXMLDOMNode *iface, VARIANT* typedValue) { xmlnode *This = impl_from_IXMLDOMNode( iface ); - HRESULT r = S_FALSE; + VARIANT type; + xmlChar *content; + HRESULT hres = S_FALSE; - FIXME("ignoring data type %p %p\n", This, typedValue); + TRACE("iface %p\n", iface); if(!typedValue) return E_INVALIDARG; V_VT(typedValue) = VT_NULL; - switch ( This->node->type ) - { - case XML_ELEMENT_NODE: - { - xmlChar *content = xmlNodeGetContent(This->node); - V_VT(typedValue) = VT_BSTR; - V_BSTR(typedValue) = bstr_from_xmlChar( content ); - xmlFree(content); - r = S_OK; - break; - } - default: - r = xmlnode_get_nodeValue(iface, typedValue); - } + if(This->node->type == XML_ELEMENT_NODE || + This->node->type == XML_TEXT_NODE || + This->node->type == XML_ENTITY_REF_NODE) + hres = xmlnode_get_dataType(iface, &type); - return r; + if(hres != S_OK && This->node->type != XML_ELEMENT_NODE) + return xmlnode_get_nodeValue(iface, typedValue); + + content = xmlNodeGetContent(This->node); + hres = VARIANT_from_xmlChar(content, typedValue, + hres==S_OK ? V_BSTR(&type) : NULL); + xmlFree(content); + VariantClear(&type); + + return hres; } static HRESULT WINAPI xmlnode_put_nodeTypedValue( diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c index 469a4f94492..43a90d770e9 100644 --- a/dlls/msxml3/tests/domdoc.c +++ b/dlls/msxml3/tests/domdoc.c @@ -147,8 +147,33 @@ static const CHAR szTransformOutput[] = ""; static const CHAR szTypeValueXML[] = -"" -"Wine"; +"\n" +"\n" +" Wine\n" +" String\n" +" 12.44\n" +" -3.71e3\n" +" -13\n" +" 7322.9371\n" +" 1\n" +" 2009-11-18T03:21:33.12\n" +" 2003-07-11T11:13:57+03:00\n" +" 3721-11-01\n" +" \n" +" 23:21:01.13+03:21\n" +" -13\n" +" 31915\n" +" -312232\n" +" 123\n" +" 48282\n" +" 949281\n" +" 213124.0\n" +" 0.412\n" +" 41221.421\n" +" 333C7BC4-460F-11D0-BC04-0080C7055a83\n" +" fffca012003c\n" +" YmFzZTY0IHRlc3Q=\n" +""; static const CHAR szBasicTransformSSXMLPart1[] = "" @@ -244,6 +269,8 @@ static WCHAR szStrangeChars[] = {'&','x',' ',0x2103, 0}; ok(r == (expect), #expr " returned %x, expected %x\n", r, expect); \ } +#define double_eq(x, y) ok((x)-(y)<=1e-14*(x) && (x)-(y)>=-1e-14*(x), "expected %.16g, got %.16g\n", x, y) + static BSTR alloc_str_from_narrow(const char *str) { int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); @@ -1003,6 +1030,10 @@ static void test_domnode( void ) CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (LPVOID*)&doc ); if( r != S_OK ) return; + if (!doc) { + ok( FALSE, "no document\n"); + return; + } b = FALSE; str = SysAllocString( szComplete4 ); @@ -1011,19 +1042,14 @@ static void test_domnode( void ) ok( b == VARIANT_TRUE, "failed to load XML string\n"); SysFreeString( str ); - if (doc) - { - b = 1; - r = IXMLDOMNode_hasChildNodes( doc, &b ); - ok( r == S_OK, "hasChildNoes bad return\n"); - ok( b == VARIANT_TRUE, "hasChildNoes wrong result\n"); + b = 1; + r = IXMLDOMNode_hasChildNodes( doc, &b ); + ok( r == S_OK, "hasChildNoes bad return\n"); + ok( b == VARIANT_TRUE, "hasChildNoes wrong result\n"); - r = IXMLDOMDocument_get_documentElement( doc, &element ); - ok( r == S_OK, "should be a document element\n"); - ok( element != NULL, "should be an element\n"); - } - else - ok( FALSE, "no document\n"); + r = IXMLDOMDocument_get_documentElement( doc, &element ); + ok( r == S_OK, "should be a document element\n"); + ok( element != NULL, "should be an element\n"); VariantInit(&var); ok( V_VT(&var) == VT_EMPTY, "variant init failed\n"); @@ -1412,8 +1438,7 @@ todo_wine if (element) IXMLDOMElement_Release( element ); - if (doc) - ok(IXMLDOMDocument_Release( doc ) == 0, "document is not destroyed\n"); + ok(IXMLDOMDocument_Release( doc ) == 0, "document is not destroyed\n"); } static void test_refs(void) @@ -3972,7 +3997,7 @@ static void test_NodeTypeValue(void) hr = IXMLDOMDocument2_get_nodeTypedValue(doc, &v); ok(hr == S_FALSE, "ret %08x\n", hr ); - hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("string"), &pNode); + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/string"), &pNode); ok(hr == S_OK, "ret %08x\n", hr ); if(hr == S_OK) { @@ -3987,11 +4012,318 @@ static void test_NodeTypeValue(void) hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_BSTR, "incorrect type\n"); ok(!lstrcmpW( V_BSTR(&v), _bstr_("Wine") ), "incorrect value\n"); VariantClear( &v ); IXMLDOMNode_Release(pNode); } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/string2"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_BSTR, "incorrect type\n"); + ok(!lstrcmpW( V_BSTR(&v), _bstr_("String") ), "incorrect value\n"); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/number"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_BSTR, "incorrect type\n"); + ok(!lstrcmpW( V_BSTR(&v), _bstr_("12.44") ), "incorrect value\n"); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/number2"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_BSTR, "incorrect type\n"); + ok(!lstrcmpW( V_BSTR(&v), _bstr_("-3.71e3") ), "incorrect value\n"); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/int"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_I4, "incorrect type\n"); + ok(V_I4(&v) == -13, "incorrect value\n"); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/fixed"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_CY, "incorrect type\n"); + VariantClear(&v); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/bool"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_BOOL, "incorrect type\n"); + ok(V_BOOL(&v) == VARIANT_TRUE, "incorrect value\n"); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/datetime"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_DATE, "incorrect type\n"); + double_eq(40135.13996527778, V_DATE(&v)); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/datetimetz"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_DATE, "incorrect type\n"); + double_eq(37813.59302083334, V_DATE(&v)); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/date"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_DATE, "incorrect type\n"); + double_eq(665413.0, V_DATE(&v)); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/time"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_DATE, "incorrect type\n"); + double_eq(0.5813888888888888, V_DATE(&v)); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/timetz"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_DATE, "incorrect type\n"); + double_eq(1.112511574074074, V_DATE(&v)); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/i1"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_I1, "incorrect type\n"); + ok(V_I1(&v) == -13, "incorrect value\n"); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/i2"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_I2, "incorrect type\n"); + ok(V_I2(&v) == 31915, "incorrect value\n"); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/i4"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_I4, "incorrect type\n"); + ok(V_I4(&v) == -312232, "incorrect value\n"); + VariantClear(&v); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/ui1"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_UI1, "incorrect type\n"); + ok(V_UI1(&v) == 123, "incorrect value\n"); + VariantClear(&v); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/ui2"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_UI2, "incorrect type\n"); + ok(V_UI2(&v) == 48282, "incorrect value\n"); + VariantClear(&v); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/ui4"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_UI4, "incorrect type\n"); + ok(V_UI4(&v) == 949281, "incorrect value\n"); + VariantClear(&v); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/r4"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_R4, "incorrect type\n"); + double_eq(213124.0, V_R4(&v)); + VariantClear(&v); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/r8"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_R8, "incorrect type\n"); + double_eq(0.412, V_R8(&v)); + VariantClear(&v); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/float"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_R8, "incorrect type\n"); + double_eq(41221.421, V_R8(&v)); + VariantClear(&v); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/uuid"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_BSTR, "incorrect type\n"); + ok(!lstrcmpW(V_BSTR(&v), _bstr_("333C7BC4-460F-11D0-BC04-0080C7055a83")), "incorrect value\n"); + VariantClear(&v); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/binhex"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + BYTE bytes[] = {0xff,0xfc,0xa0,0x12,0x00,0x3c}; + + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == (VT_ARRAY|VT_UI1), "incorrect type\n"); + ok(V_ARRAY(&v)->rgsabound[0].cElements == 6, "incorrect array size\n"); + if(V_ARRAY(&v)->rgsabound[0].cElements == 6) + ok(!memcmp(bytes, V_ARRAY(&v)->pvData, sizeof(bytes)), "incorrect value\n"); + VariantClear(&v); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/binbase64"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + BYTE bytes[] = {0x62,0x61,0x73,0x65,0x36,0x34,0x20,0x74,0x65,0x73,0x74}; + + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == (VT_ARRAY|VT_UI1), "incorrect type\n"); + ok(V_ARRAY(&v)->rgsabound[0].cElements == 11, "incorrect array size\n"); + if(V_ARRAY(&v)->rgsabound[0].cElements == 11) + ok(!memcmp(bytes, V_ARRAY(&v)->pvData, sizeof(bytes)), "incorrect value\n"); + VariantClear(&v); + + IXMLDOMNode_Release(pNode); + } } IXMLDOMDocument2_Release(doc); diff --git a/dlls/netapi32/tests/access.c b/dlls/netapi32/tests/access.c index 7886b36e9ec..2f296844e6f 100644 --- a/dlls/netapi32/tests/access.c +++ b/dlls/netapi32/tests/access.c @@ -155,7 +155,10 @@ static void run_usergetinfo_tests(void) todo_wine { /* FIXME - Currently Wine can't verify whether the network path is good or bad */ rc=pNetUserGetInfo(sBadNetPath, sTestUserName, 0, (LPBYTE *)&ui0); - ok(rc == ERROR_BAD_NETPATH || rc == ERROR_NETWORK_UNREACHABLE || rc == RPC_S_SERVER_UNAVAILABLE, + ok(rc == ERROR_BAD_NETPATH || + rc == ERROR_NETWORK_UNREACHABLE || + rc == RPC_S_SERVER_UNAVAILABLE || + rc == RPC_S_INVALID_NET_ADDR, /* Some Win7 */ "Bad Network Path: rc=%d\n",rc); } rc=pNetUserGetInfo(sEmptyStr, sTestUserName, 0, (LPBYTE *)&ui0); diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c index e7f1dd45f05..a09aab163a0 100644 --- a/dlls/ntdll/directory.c +++ b/dlls/ntdll/directory.c @@ -148,7 +148,15 @@ struct file_identity static struct file_identity ignored_files[MAX_IGNORED_FILES]; static int ignored_files_count; -static const unsigned int max_dir_info_size = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, FileName[MAX_DIR_ENTRY_LEN] ); +union file_directory_info +{ + ULONG next; + FILE_DIRECTORY_INFORMATION dir; + FILE_BOTH_DIRECTORY_INFORMATION both; + FILE_FULL_DIRECTORY_INFORMATION full; + FILE_ID_BOTH_DIRECTORY_INFORMATION id_both; + FILE_ID_FULL_DIRECTORY_INFORMATION id_full; +}; static int show_dot_files = -1; @@ -215,6 +223,31 @@ static inline BOOL is_ignored_file( const struct stat *st ) return FALSE; } +static inline unsigned int dir_info_size( FILE_INFORMATION_CLASS class, unsigned int len ) +{ + switch (class) + { + case FileDirectoryInformation: + return (FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, FileName[len] ) + 3) & ~3; + case FileBothDirectoryInformation: + return (FIELD_OFFSET( FILE_BOTH_DIRECTORY_INFORMATION, FileName[len] ) + 3) & ~3; + case FileFullDirectoryInformation: + return (FIELD_OFFSET( FILE_FULL_DIRECTORY_INFORMATION, FileName[len] ) + 3) & ~3; + case FileIdBothDirectoryInformation: + return (FIELD_OFFSET( FILE_ID_BOTH_DIRECTORY_INFORMATION, FileName[len] ) + 3) & ~3; + case FileIdFullDirectoryInformation: + return (FIELD_OFFSET( FILE_ID_FULL_DIRECTORY_INFORMATION, FileName[len] ) + 3) & ~3; + default: + assert(0); + } +} + +static inline unsigned int max_dir_info_size( FILE_INFORMATION_CLASS class ) +{ + return dir_info_size( class, MAX_DIR_ENTRY_LEN ); +} + + /*********************************************************************** * get_default_com_device * @@ -923,17 +956,20 @@ static BOOLEAN match_filename( const UNICODE_STRING *name_str, const UNICODE_STR * * helper for NtQueryDirectoryFile */ -static FILE_BOTH_DIR_INFORMATION *append_entry( void *info_ptr, ULONG_PTR *pos, ULONG max_length, +static union file_directory_info *append_entry( void *info_ptr, IO_STATUS_BLOCK *io, ULONG max_length, const char *long_name, const char *short_name, - const UNICODE_STRING *mask ) + const UNICODE_STRING *mask, FILE_INFORMATION_CLASS class ) { - FILE_BOTH_DIR_INFORMATION *info; + union file_directory_info *info; int i, long_len, short_len, total_len; struct stat st; WCHAR long_nameW[MAX_DIR_ENTRY_LEN]; WCHAR short_nameW[12]; + WCHAR *filename; UNICODE_STRING str; + ULONG attributes = 0; + io->u.Status = STATUS_SUCCESS; long_len = ntdll_umbstowcs( 0, long_name, strlen(long_name), long_nameW, MAX_DIR_ENTRY_LEN ); if (long_len == -1) return NULL; @@ -968,58 +1004,73 @@ static FILE_BOTH_DIR_INFORMATION *append_entry( void *info_ptr, ULONG_PTR *pos, if (!match_filename( &str, mask )) return NULL; } - total_len = (sizeof(*info) - sizeof(info->FileName) + long_len*sizeof(WCHAR) + 3) & ~3; - info = (FILE_BOTH_DIR_INFORMATION *)((char *)info_ptr + *pos); - - if (*pos + total_len > max_length) total_len = max_length - *pos; - - info->FileAttributes = 0; if (lstat( long_name, &st ) == -1) return NULL; if (S_ISLNK( st.st_mode )) { if (stat( long_name, &st ) == -1) return NULL; - if (S_ISDIR( st.st_mode )) info->FileAttributes |= FILE_ATTRIBUTE_REPARSE_POINT; + if (S_ISDIR( st.st_mode )) attributes |= FILE_ATTRIBUTE_REPARSE_POINT; } if (is_ignored_file( &st )) { TRACE( "ignoring file %s\n", long_name ); return NULL; } - - info->NextEntryOffset = total_len; - info->FileIndex = 0; /* NTFS always has 0 here, so let's not bother with it */ - - RtlSecondsSince1970ToTime( st.st_mtime, &info->CreationTime ); - RtlSecondsSince1970ToTime( st.st_mtime, &info->LastWriteTime ); - RtlSecondsSince1970ToTime( st.st_atime, &info->LastAccessTime ); - RtlSecondsSince1970ToTime( st.st_ctime, &info->ChangeTime ); - - if (S_ISDIR(st.st_mode)) - { - info->EndOfFile.QuadPart = info->AllocationSize.QuadPart = 0; - info->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; - } - else - { - info->EndOfFile.QuadPart = st.st_size; - info->AllocationSize.QuadPart = (ULONGLONG)st.st_blocks * 512; - info->FileAttributes |= FILE_ATTRIBUTE_ARCHIVE; - } - - if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) - info->FileAttributes |= FILE_ATTRIBUTE_READONLY; - if (!show_dot_files && long_name[0] == '.' && long_name[1] && (long_name[1] != '.' || long_name[2])) - info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; - - info->EaSize = 0; /* FIXME */ - info->ShortNameLength = short_len * sizeof(WCHAR); - for (i = 0; i < short_len; i++) info->ShortName[i] = toupperW(short_nameW[i]); - info->FileNameLength = long_len * sizeof(WCHAR); - memcpy( info->FileName, long_nameW, - min( info->FileNameLength, total_len-sizeof(*info)+sizeof(info->FileName) )); - - *pos += total_len; + attributes |= FILE_ATTRIBUTE_HIDDEN; + + total_len = dir_info_size( class, long_len ); + if (io->Information + total_len > max_length) + { + total_len = max_length - io->Information; + io->u.Status = STATUS_BUFFER_OVERFLOW; + } + info = (union file_directory_info *)((char *)info_ptr + io->Information); + /* all the structures start with a FileDirectoryInformation layout */ + fill_stat_info( &st, info, class ); + info->dir.NextEntryOffset = total_len; + info->dir.FileIndex = 0; /* NTFS always has 0 here, so let's not bother with it */ + info->dir.FileAttributes |= attributes; + + switch (class) + { + case FileDirectoryInformation: + info->dir.FileNameLength = long_len * sizeof(WCHAR); + filename = info->dir.FileName; + break; + + case FileFullDirectoryInformation: + info->full.EaSize = 0; /* FIXME */ + info->full.FileNameLength = long_len * sizeof(WCHAR); + filename = info->full.FileName; + break; + + case FileIdFullDirectoryInformation: + info->id_full.EaSize = 0; /* FIXME */ + info->id_full.FileNameLength = long_len * sizeof(WCHAR); + filename = info->id_full.FileName; + break; + + case FileBothDirectoryInformation: + info->both.EaSize = 0; /* FIXME */ + info->both.ShortNameLength = short_len * sizeof(WCHAR); + for (i = 0; i < short_len; i++) info->both.ShortName[i] = toupperW(short_nameW[i]); + info->both.FileNameLength = long_len * sizeof(WCHAR); + filename = info->both.FileName; + break; + + case FileIdBothDirectoryInformation: + info->id_both.EaSize = 0; /* FIXME */ + info->id_both.ShortNameLength = short_len * sizeof(WCHAR); + for (i = 0; i < short_len; i++) info->id_both.ShortName[i] = toupperW(short_nameW[i]); + info->id_both.FileNameLength = long_len * sizeof(WCHAR); + filename = info->id_both.FileName; + break; + + default: + assert(0); + } + memcpy( filename, long_nameW, total_len - ((char *)filename - (char *)info) ); + io->Information += total_len; return info; } @@ -1074,18 +1125,18 @@ static KERNEL_DIRENT *start_vfat_ioctl( int fd ) */ static int read_directory_vfat( int fd, IO_STATUS_BLOCK *io, void *buffer, ULONG length, BOOLEAN single_entry, const UNICODE_STRING *mask, - BOOLEAN restart_scan ) + BOOLEAN restart_scan, FILE_INFORMATION_CLASS class ) { size_t len; KERNEL_DIRENT *de; - FILE_BOTH_DIR_INFORMATION *info, *last_info = NULL; + union file_directory_info *info, *last_info = NULL; io->u.Status = STATUS_SUCCESS; if (restart_scan) lseek( fd, 0, SEEK_SET ); - if (length < max_dir_info_size) /* we may have to return a partial entry here */ + if (length < max_dir_info_size(class)) /* we may have to return a partial entry here */ { off_t old_pos = lseek( fd, 0, SEEK_CUR ); @@ -1100,19 +1151,14 @@ static int read_directory_vfat( int fd, IO_STATUS_BLOCK *io, void *buffer, ULONG de[1].d_name[len] = 0; if (de[1].d_name[0]) - info = append_entry( buffer, &io->Information, length, - de[1].d_name, de[0].d_name, mask ); + info = append_entry( buffer, io, length, de[1].d_name, de[0].d_name, mask, class ); else - info = append_entry( buffer, &io->Information, length, - de[0].d_name, NULL, mask ); + info = append_entry( buffer, io, length, de[0].d_name, NULL, mask, class ); if (info) { last_info = info; - if ((char *)info->FileName + info->FileNameLength > (char *)buffer + length) - { - io->u.Status = STATUS_BUFFER_OVERFLOW; + if (io->u.Status == STATUS_BUFFER_OVERFLOW) lseek( fd, old_pos, SEEK_SET ); /* restore pos to previous entry */ - } break; } old_pos = lseek( fd, 0, SEEK_CUR ); @@ -1132,23 +1178,21 @@ static int read_directory_vfat( int fd, IO_STATUS_BLOCK *io, void *buffer, ULONG de[1].d_name[len] = 0; if (de[1].d_name[0]) - info = append_entry( buffer, &io->Information, length, - de[1].d_name, de[0].d_name, mask ); + info = append_entry( buffer, io, length, de[1].d_name, de[0].d_name, mask, class ); else - info = append_entry( buffer, &io->Information, length, - de[0].d_name, NULL, mask ); + info = append_entry( buffer, io, length, de[0].d_name, NULL, mask, class ); if (info) { last_info = info; if (single_entry) break; /* check if we still have enough space for the largest possible entry */ - if (io->Information + max_dir_info_size > length) break; + if (io->Information + max_dir_info_size(class) > length) break; } if (ioctl( fd, VFAT_IOCTL_READDIR_BOTH, (long)de ) == -1) break; } } - if (last_info) last_info->NextEntryOffset = 0; + if (last_info) last_info->next = 0; else io->u.Status = restart_scan ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES; return 0; } @@ -1163,14 +1207,14 @@ static int read_directory_vfat( int fd, IO_STATUS_BLOCK *io, void *buffer, ULONG #ifdef USE_GETDENTS static int read_directory_getdents( int fd, IO_STATUS_BLOCK *io, void *buffer, ULONG length, BOOLEAN single_entry, const UNICODE_STRING *mask, - BOOLEAN restart_scan ) + BOOLEAN restart_scan, FILE_INFORMATION_CLASS class ) { off_t old_pos = 0; size_t size = length; int res, fake_dot_dot = 1; char *data, local_buffer[8192]; KERNEL_DIRENT64 *de; - FILE_BOTH_DIR_INFORMATION *info, *last_info = NULL; + union file_directory_info *info, *last_info = NULL; if (size <= sizeof(local_buffer) || !(data = RtlAllocateHeap( GetProcessHeap(), 0, size ))) { @@ -1179,7 +1223,7 @@ static int read_directory_getdents( int fd, IO_STATUS_BLOCK *io, void *buffer, U } if (restart_scan) lseek( fd, 0, SEEK_SET ); - else if (length < max_dir_info_size) /* we may have to return a partial entry here */ + else if (length < max_dir_info_size(class)) /* we may have to return a partial entry here */ { old_pos = lseek( fd, 0, SEEK_CUR ); if (old_pos == -1 && errno == ENOENT) @@ -1219,8 +1263,7 @@ static int read_directory_getdents( int fd, IO_STATUS_BLOCK *io, void *buffer, U /* make sure we have enough room for both entries */ if (fake_dot_dot) { - static const ULONG min_info_size = (FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName[1]) + - FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName[2]) + 3) & ~3; + const ULONG min_info_size = dir_info_size( class, 1 ) + dir_info_size( class, 2 ); if (length < min_info_size || single_entry) { FIXME( "not enough room %u/%u for fake . and .. entries\n", length, single_entry ); @@ -1230,13 +1273,13 @@ static int read_directory_getdents( int fd, IO_STATUS_BLOCK *io, void *buffer, U if (fake_dot_dot) { - if ((info = append_entry( buffer, &io->Information, length, ".", NULL, mask ))) + if ((info = append_entry( buffer, io, length, ".", NULL, mask, class ))) last_info = info; - if ((info = append_entry( buffer, &io->Information, length, "..", NULL, mask ))) + if ((info = append_entry( buffer, io, length, "..", NULL, mask, class ))) last_info = info; /* check if we still have enough space for the largest possible entry */ - if (last_info && io->Information + max_dir_info_size > length) + if (last_info && io->Information + max_dir_info_size(class) > length) { lseek( fd, 0, SEEK_SET ); /* reset pos to first entry */ res = 0; @@ -1249,17 +1292,16 @@ static int read_directory_getdents( int fd, IO_STATUS_BLOCK *io, void *buffer, U res -= de->d_reclen; if (de->d_ino && !(fake_dot_dot && (!strcmp( de->d_name, "." ) || !strcmp( de->d_name, ".." ))) && - (info = append_entry( buffer, &io->Information, length, de->d_name, NULL, mask ))) + (info = append_entry( buffer, io, length, de->d_name, NULL, mask, class ))) { last_info = info; - if ((char *)info->FileName + info->FileNameLength > (char *)buffer + length) + if (io->u.Status == STATUS_BUFFER_OVERFLOW) { - io->u.Status = STATUS_BUFFER_OVERFLOW; lseek( fd, old_pos, SEEK_SET ); /* restore pos to previous entry */ break; } /* check if we still have enough space for the largest possible entry */ - if (single_entry || io->Information + max_dir_info_size > length) + if (single_entry || io->Information + max_dir_info_size(class) > length) { if (res > 0) lseek( fd, de->d_off, SEEK_SET ); /* set pos to next entry */ break; @@ -1275,7 +1317,7 @@ static int read_directory_getdents( int fd, IO_STATUS_BLOCK *io, void *buffer, U } } - if (last_info) last_info->NextEntryOffset = 0; + if (last_info) last_info->next = 0; else io->u.Status = restart_scan ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES; res = 0; done: @@ -1336,7 +1378,7 @@ static inline int wine_getdirentries(int fd, char *buf, int nbytes, long *basep) */ static int read_directory_getdirentries( int fd, IO_STATUS_BLOCK *io, void *buffer, ULONG length, BOOLEAN single_entry, const UNICODE_STRING *mask, - BOOLEAN restart_scan ) + BOOLEAN restart_scan, FILE_INFORMATION_CLASS class ) { long restart_pos; ULONG_PTR restart_info_pos = 0; @@ -1344,7 +1386,7 @@ static int read_directory_getdirentries( int fd, IO_STATUS_BLOCK *io, void *buff int res, fake_dot_dot = 1; char *data, local_buffer[8192]; struct dirent *de; - FILE_BOTH_DIR_INFORMATION *info, *last_info = NULL, *restart_last_info = NULL; + union file_directory_info *info, *last_info = NULL, *restart_last_info = NULL; size = initial_size; data = local_buffer; @@ -1383,8 +1425,7 @@ static int read_directory_getdirentries( int fd, IO_STATUS_BLOCK *io, void *buff /* make sure we have enough room for both entries */ if (fake_dot_dot) { - static const ULONG min_info_size = (FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName[1]) + - FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName[2]) + 3) & ~3; + const ULONG min_info_size = dir_info_size( class, 1 ) + dir_info_size( class, 2 ); if (length < min_info_size || single_entry) { FIXME( "not enough room %u/%u for fake . and .. entries\n", length, single_entry ); @@ -1394,16 +1435,16 @@ static int read_directory_getdirentries( int fd, IO_STATUS_BLOCK *io, void *buff if (fake_dot_dot) { - if ((info = append_entry( buffer, &io->Information, length, ".", NULL, mask ))) + if ((info = append_entry( buffer, io, length, ".", NULL, mask, class ))) last_info = info; - if ((info = append_entry( buffer, &io->Information, length, "..", NULL, mask ))) + if ((info = append_entry( buffer, io, length, "..", NULL, mask, class ))) last_info = info; restart_last_info = last_info; restart_info_pos = io->Information; /* check if we still have enough space for the largest possible entry */ - if (last_info && io->Information + max_dir_info_size > length) + if (last_info && io->Information + max_dir_info_size(class) > length) { lseek( fd, 0, SEEK_SET ); /* reset pos to first entry */ res = 0; @@ -1416,31 +1457,28 @@ static int read_directory_getdirentries( int fd, IO_STATUS_BLOCK *io, void *buff res -= de->d_reclen; if (de->d_fileno && !(fake_dot_dot && (!strcmp( de->d_name, "." ) || !strcmp( de->d_name, ".." ))) && - ((info = append_entry( buffer, &io->Information, length, de->d_name, NULL, mask )))) + ((info = append_entry( buffer, io, length, de->d_name, NULL, mask, class )))) { last_info = info; - if ((char *)info->FileName + info->FileNameLength > (char *)buffer + length) + if (io->u.Status == STATUS_BUFFER_OVERFLOW) { lseek( fd, (unsigned long)restart_pos, SEEK_SET ); if (restart_info_pos) /* if we have a complete read already, return it */ { + io->u.Status = STATUS_SUCCESS; io->Information = restart_info_pos; last_info = restart_last_info; break; } /* otherwise restart from the start with a smaller size */ size = (char *)de - data; - if (!size) - { - io->u.Status = STATUS_BUFFER_OVERFLOW; - break; - } + if (!size) break; io->Information = 0; last_info = NULL; goto restart; } /* if we have to return but the buffer contains more data, restart with a smaller size */ - if (res > 0 && (single_entry || io->Information + max_dir_info_size > length)) + if (res > 0 && (single_entry || io->Information + max_dir_info_size(class) > length)) { lseek( fd, (unsigned long)restart_pos, SEEK_SET ); size = (char *)de - data; @@ -1458,7 +1496,7 @@ static int read_directory_getdirentries( int fd, IO_STATUS_BLOCK *io, void *buff if (size < initial_size) break; /* already restarted once, give up now */ size = min( size, length - io->Information ); /* if size is too small don't bother to continue */ - if (size < max_dir_info_size && last_info) break; + if (size < max_dir_info_size(class) && last_info) break; restart_last_info = last_info; restart_info_pos = io->Information; restart: @@ -1466,7 +1504,7 @@ static int read_directory_getdirentries( int fd, IO_STATUS_BLOCK *io, void *buff de = (struct dirent *)data; } - if (last_info) last_info->NextEntryOffset = 0; + if (last_info) last_info->next = 0; else io->u.Status = restart_scan ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES; res = 0; done: @@ -1489,12 +1527,12 @@ done: */ static void read_directory_readdir( int fd, IO_STATUS_BLOCK *io, void *buffer, ULONG length, BOOLEAN single_entry, const UNICODE_STRING *mask, - BOOLEAN restart_scan ) + BOOLEAN restart_scan, FILE_INFORMATION_CLASS class ) { DIR *dir; off_t i, old_pos = 0; struct dirent *de; - FILE_BOTH_DIR_INFORMATION *info, *last_info = NULL; + union file_directory_info *info, *last_info = NULL; if (!(dir = opendir( "." ))) { @@ -1521,13 +1559,13 @@ static void read_directory_readdir( int fd, IO_STATUS_BLOCK *io, void *buffer, U for (;;) { if (old_pos == 0) - info = append_entry( buffer, &io->Information, length, ".", NULL, mask ); + info = append_entry( buffer, io, length, ".", NULL, mask, class ); else if (old_pos == 1) - info = append_entry( buffer, &io->Information, length, "..", NULL, mask ); + info = append_entry( buffer, io, length, "..", NULL, mask, class ); else if ((de = readdir( dir ))) { if (strcmp( de->d_name, "." ) && strcmp( de->d_name, ".." )) - info = append_entry( buffer, &io->Information, length, de->d_name, NULL, mask ); + info = append_entry( buffer, io, length, de->d_name, NULL, mask, class ); else info = NULL; } @@ -1537,22 +1575,21 @@ static void read_directory_readdir( int fd, IO_STATUS_BLOCK *io, void *buffer, U if (info) { last_info = info; - if ((char *)info->FileName + info->FileNameLength > (char *)buffer + length) + if (io->u.Status == STATUS_BUFFER_OVERFLOW) { - io->u.Status = STATUS_BUFFER_OVERFLOW; old_pos--; /* restore pos to previous entry */ break; } if (single_entry) break; /* check if we still have enough space for the largest possible entry */ - if (io->Information + max_dir_info_size > length) break; + if (io->Information + max_dir_info_size(class) > length) break; } } lseek( fd, old_pos, SEEK_SET ); /* store dir offset as filepos for fd */ closedir( dir ); - if (last_info) last_info->NextEntryOffset = 0; + if (last_info) last_info->next = 0; else io->u.Status = restart_scan ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES; } @@ -1564,7 +1601,7 @@ static void read_directory_readdir( int fd, IO_STATUS_BLOCK *io, void *buffer, U */ static int read_directory_stat( int fd, IO_STATUS_BLOCK *io, void *buffer, ULONG length, BOOLEAN single_entry, const UNICODE_STRING *mask, - BOOLEAN restart_scan ) + BOOLEAN restart_scan, FILE_INFORMATION_CLASS class ) { int unix_len, ret, used_default; char *unix_name; @@ -1597,14 +1634,11 @@ static int read_directory_stat( int fd, IO_STATUS_BLOCK *io, void *buffer, ULONG ret = stat( unix_name, &st ); if (!ret) { - FILE_BOTH_DIR_INFORMATION *info = append_entry( buffer, &io->Information, length, unix_name, NULL, NULL ); + union file_directory_info *info = append_entry( buffer, io, length, unix_name, NULL, NULL, class ); if (info) { - info->NextEntryOffset = 0; - if ((char *)info->FileName + info->FileNameLength > (char *)buffer + length) - io->u.Status = STATUS_BUFFER_OVERFLOW; - else - lseek( fd, 1, SEEK_CUR ); + info->next = 0; + if (io->u.Status != STATUS_BUFFER_OVERFLOW) lseek( fd, 1, SEEK_CUR ); } else io->u.Status = STATUS_NO_MORE_FILES; } @@ -1648,15 +1682,21 @@ NTSTATUS WINAPI NtQueryDirectoryFile( HANDLE handle, HANDLE event, length, info_class, single_entry, debugstr_us(mask), restart_scan); - if (length < sizeof(FILE_BOTH_DIR_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH; - if (event || apc_routine) { FIXME( "Unsupported yet option\n" ); return io->u.Status = STATUS_NOT_IMPLEMENTED; } - if (info_class != FileBothDirectoryInformation) + switch (info_class) { + case FileDirectoryInformation: + case FileBothDirectoryInformation: + case FileFullDirectoryInformation: + case FileIdBothDirectoryInformation: + case FileIdFullDirectoryInformation: + if (length < dir_info_size( info_class, 1 )) return io->u.Status = STATUS_INFO_LENGTH_MISMATCH; + break; + default: FIXME( "Unsupported file info class %d\n", info_class ); return io->u.Status = STATUS_NOT_IMPLEMENTED; } @@ -1674,20 +1714,20 @@ NTSTATUS WINAPI NtQueryDirectoryFile( HANDLE handle, HANDLE event, if (fchdir( fd ) != -1) { #ifdef VFAT_IOCTL_READDIR_BOTH - if ((read_directory_vfat( fd, io, buffer, length, single_entry, mask, restart_scan )) != -1) - goto done; + if ((read_directory_vfat( fd, io, buffer, length, single_entry, + mask, restart_scan, info_class )) != -1) goto done; #endif if (mask && !mempbrkW( mask->Buffer, wszWildcards, mask->Length / sizeof(WCHAR) ) && - read_directory_stat( fd, io, buffer, length, single_entry, mask, restart_scan ) != -1) - goto done; + read_directory_stat( fd, io, buffer, length, single_entry, + mask, restart_scan, info_class ) != -1) goto done; #ifdef USE_GETDENTS - if ((read_directory_getdents( fd, io, buffer, length, single_entry, mask, restart_scan )) != -1) - goto done; + if ((read_directory_getdents( fd, io, buffer, length, single_entry, + mask, restart_scan, info_class )) != -1) goto done; #elif defined HAVE_GETDIRENTRIES - if ((read_directory_getdirentries( fd, io, buffer, length, single_entry, mask, restart_scan )) != -1) - goto done; + if ((read_directory_getdirentries( fd, io, buffer, length, single_entry, + mask, restart_scan, info_class )) != -1) goto done; #endif - read_directory_readdir( fd, io, buffer, length, single_entry, mask, restart_scan ); + read_directory_readdir( fd, io, buffer, length, single_entry, mask, restart_scan, info_class ); done: if (cwd == -1 || fchdir( cwd ) == -1) chdir( "/" ); diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index b62c7c290b3..32e5f93a0e5 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -1486,6 +1486,125 @@ NTSTATUS WINAPI NtSetVolumeInformationFile( return 0; } +static inline void get_file_times( const struct stat *st, LARGE_INTEGER *mtime, LARGE_INTEGER *ctime, + LARGE_INTEGER *atime, LARGE_INTEGER *creation ) +{ + RtlSecondsSince1970ToTime( st->st_mtime, mtime ); + RtlSecondsSince1970ToTime( st->st_ctime, ctime ); + RtlSecondsSince1970ToTime( st->st_atime, atime ); +#ifdef HAVE_STRUCT_STAT_ST_MTIM + mtime->QuadPart += st->st_mtim.tv_nsec / 100; +#endif +#ifdef HAVE_STRUCT_STAT_ST_CTIM + ctime->QuadPart += st->st_ctim.tv_nsec / 100; +#endif +#ifdef HAVE_STRUCT_STAT_ST_ATIM + atime->QuadPart += st->st_atim.tv_nsec / 100; +#endif + *creation = *mtime; +} + +/* fill in the file information that depends on the stat info */ +NTSTATUS fill_stat_info( const struct stat *st, void *ptr, FILE_INFORMATION_CLASS class ) +{ + switch (class) + { + case FileBasicInformation: + { + FILE_BASIC_INFORMATION *info = ptr; + + get_file_times( st, &info->LastWriteTime, &info->ChangeTime, + &info->LastAccessTime, &info->CreationTime ); + if (S_ISDIR(st->st_mode)) info->FileAttributes = FILE_ATTRIBUTE_DIRECTORY; + else info->FileAttributes = FILE_ATTRIBUTE_ARCHIVE; + if (!(st->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) + info->FileAttributes |= FILE_ATTRIBUTE_READONLY; + } + break; + case FileStandardInformation: + { + FILE_STANDARD_INFORMATION *info = ptr; + + if ((info->Directory = S_ISDIR(st->st_mode))) + { + info->AllocationSize.QuadPart = 0; + info->EndOfFile.QuadPart = 0; + info->NumberOfLinks = 1; + } + else + { + info->AllocationSize.QuadPart = (ULONGLONG)st->st_blocks * 512; + info->EndOfFile.QuadPart = st->st_size; + info->NumberOfLinks = st->st_nlink; + } + } + break; + case FileInternalInformation: + { + FILE_INTERNAL_INFORMATION *info = ptr; + info->IndexNumber.QuadPart = st->st_ino; + } + break; + case FileEndOfFileInformation: + { + FILE_END_OF_FILE_INFORMATION *info = ptr; + info->EndOfFile.QuadPart = S_ISDIR(st->st_mode) ? 0 : st->st_size; + } + break; + case FileAllInformation: + { + FILE_ALL_INFORMATION *info = ptr; + fill_stat_info( st, &info->BasicInformation, FileBasicInformation ); + fill_stat_info( st, &info->StandardInformation, FileStandardInformation ); + fill_stat_info( st, &info->InternalInformation, FileInternalInformation ); + } + break; + /* all directory structures start with the FileDirectoryInformation layout */ + case FileBothDirectoryInformation: + case FileFullDirectoryInformation: + case FileDirectoryInformation: + { + FILE_DIRECTORY_INFORMATION *info = ptr; + + get_file_times( st, &info->LastWriteTime, &info->ChangeTime, + &info->LastAccessTime, &info->CreationTime ); + if (S_ISDIR(st->st_mode)) + { + info->AllocationSize.QuadPart = 0; + info->EndOfFile.QuadPart = 0; + info->FileAttributes = FILE_ATTRIBUTE_DIRECTORY; + } + else + { + info->AllocationSize.QuadPart = (ULONGLONG)st->st_blocks * 512; + info->EndOfFile.QuadPart = st->st_size; + info->FileAttributes = FILE_ATTRIBUTE_ARCHIVE; + } + if (!(st->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) + info->FileAttributes |= FILE_ATTRIBUTE_READONLY; + } + break; + case FileIdFullDirectoryInformation: + { + FILE_ID_FULL_DIRECTORY_INFORMATION *info = ptr; + info->FileId.QuadPart = st->st_ino; + fill_stat_info( st, info, FileDirectoryInformation ); + } + break; + case FileIdBothDirectoryInformation: + { + FILE_ID_BOTH_DIRECTORY_INFORMATION *info = ptr; + info->FileId.QuadPart = st->st_ino; + fill_stat_info( st, info, FileDirectoryInformation ); + } + break; + + default: + return STATUS_INVALID_INFO_CLASS; + } + return STATUS_SUCCESS; +} + static NTSTATUS server_get_unix_name( HANDLE handle, ANSI_STRING *unix_name ) { data_size_t size = 1024; @@ -1578,7 +1697,25 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io, 0, /* FileReparsePointInformation */ 0, /* FileNetworkOpenInformation */ 0, /* FileAttributeTagInformation */ - 0 /* FileTrackingInformation */ + 0, /* FileTrackingInformation */ + 0, /* FileIdBothDirectoryInformation */ + 0, /* FileIdFullDirectoryInformation */ + 0, /* FileValidDataLengthInformation */ + 0, /* FileShortNameInformation */ + 0, + 0, + 0, + 0, /* FileSfioReserveInformation */ + 0, /* FileSfioVolumeInformation */ + 0, /* FileHardLinkInformation */ + 0, + 0, /* FileNormalizedNameInformation */ + 0, + 0, /* FileIdGlobalTxDirectoryInformation */ + 0, + 0, + 0, + 0 /* FileStandardLinkInformation */ }; struct stat st; @@ -1607,35 +1744,12 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io, switch (class) { case FileBasicInformation: - { - FILE_BASIC_INFORMATION *info = ptr; - - if (fstat( fd, &st ) == -1) - io->u.Status = FILE_GetNtStatus(); - else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) - io->u.Status = STATUS_INVALID_INFO_CLASS; - else - { - if (S_ISDIR(st.st_mode)) info->FileAttributes = FILE_ATTRIBUTE_DIRECTORY; - else info->FileAttributes = FILE_ATTRIBUTE_ARCHIVE; - if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) - info->FileAttributes |= FILE_ATTRIBUTE_READONLY; - RtlSecondsSince1970ToTime( st.st_mtime, &info->CreationTime); - 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 - } - } + if (fstat( fd, &st ) == -1) + io->u.Status = FILE_GetNtStatus(); + else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) + io->u.Status = STATUS_INVALID_INFO_CLASS; + else + fill_stat_info( &st, ptr, class ); break; case FileStandardInformation: { @@ -1644,20 +1758,8 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io, if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus(); else { - if ((info->Directory = S_ISDIR(st.st_mode))) - { - info->AllocationSize.QuadPart = 0; - info->EndOfFile.QuadPart = 0; - info->NumberOfLinks = 1; - info->DeletePending = FALSE; - } - else - { - info->AllocationSize.QuadPart = (ULONGLONG)st.st_blocks * 512; - info->EndOfFile.QuadPart = st.st_size; - info->NumberOfLinks = st.st_nlink; - info->DeletePending = FALSE; /* FIXME */ - } + fill_stat_info( &st, info, class ); + info->DeletePending = FALSE; /* FIXME */ } } break; @@ -1670,12 +1772,8 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io, } break; case FileInternalInformation: - { - FILE_INTERNAL_INFORMATION *info = ptr; - - if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus(); - else info->IndexNumber.QuadPart = st.st_ino; - } + if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus(); + else fill_stat_info( &st, ptr, class ); break; case FileEaInformation: { @@ -1684,12 +1782,8 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io, } break; case FileEndOfFileInformation: - { - FILE_END_OF_FILE_INFORMATION *info = ptr; - - if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus(); - else info->EndOfFile.QuadPart = S_ISDIR(st.st_mode) ? 0 : st.st_size; - } + if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus(); + else fill_stat_info( &st, ptr, class ); break; case FileAllInformation: { @@ -1700,39 +1794,8 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io, io->u.Status = STATUS_INVALID_INFO_CLASS; else { - if ((info->StandardInformation.Directory = S_ISDIR(st.st_mode))) - { - info->BasicInformation.FileAttributes = FILE_ATTRIBUTE_DIRECTORY; - info->StandardInformation.AllocationSize.QuadPart = 0; - info->StandardInformation.EndOfFile.QuadPart = 0; - info->StandardInformation.NumberOfLinks = 1; - info->StandardInformation.DeletePending = FALSE; - } - else - { - info->BasicInformation.FileAttributes = FILE_ATTRIBUTE_ARCHIVE; - info->StandardInformation.AllocationSize.QuadPart = (ULONGLONG)st.st_blocks * 512; - info->StandardInformation.EndOfFile.QuadPart = st.st_size; - info->StandardInformation.NumberOfLinks = st.st_nlink; - info->StandardInformation.DeletePending = FALSE; /* FIXME */ - } - if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) - info->BasicInformation.FileAttributes |= FILE_ATTRIBUTE_READONLY; - RtlSecondsSince1970ToTime( st.st_mtime, &info->BasicInformation.CreationTime); - 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; + fill_stat_info( &st, info, FileAllInformation ); + info->StandardInformation.DeletePending = FALSE; /* FIXME */ info->EaInformation.EaSize = 0; info->AccessInformation.AccessFlags = 0; /* FIXME */ info->PositionInformation.CurrentByteOffset.QuadPart = lseek( fd, 0, SEEK_CUR ); @@ -2036,10 +2099,10 @@ NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io, /****************************************************************************** - * FILE_QueryFullAttributesFile (internal) + * NtQueryFullAttributesFile (NTDLL.@) */ -static NTSTATUS FILE_QueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr, - FILE_NETWORK_OPEN_INFORMATION *info ) +NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr, + FILE_NETWORK_OPEN_INFORMATION *info ) { ANSI_STRING unix_name; NTSTATUS status; @@ -2055,24 +2118,19 @@ static NTSTATUS FILE_QueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr, status = STATUS_INVALID_INFO_CLASS; else { - if (S_ISDIR(st.st_mode)) - { - info->FileAttributes = FILE_ATTRIBUTE_DIRECTORY; - info->AllocationSize.QuadPart = 0; - info->EndOfFile.QuadPart = 0; - } - else - { - info->FileAttributes = FILE_ATTRIBUTE_ARCHIVE; - info->AllocationSize.QuadPart = (ULONGLONG)st.st_blocks * 512; - info->EndOfFile.QuadPart = st.st_size; - } - if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) - info->FileAttributes |= FILE_ATTRIBUTE_READONLY; - RtlSecondsSince1970ToTime( st.st_mtime, &info->CreationTime ); - RtlSecondsSince1970ToTime( st.st_mtime, &info->LastWriteTime ); - RtlSecondsSince1970ToTime( st.st_ctime, &info->ChangeTime ); - RtlSecondsSince1970ToTime( st.st_atime, &info->LastAccessTime ); + FILE_BASIC_INFORMATION basic; + FILE_STANDARD_INFORMATION std; + + fill_stat_info( &st, &basic, FileBasicInformation ); + fill_stat_info( &st, &std, FileStandardInformation ); + + info->CreationTime = basic.CreationTime; + info->LastAccessTime = basic.LastAccessTime; + info->LastWriteTime = basic.LastWriteTime; + info->ChangeTime = basic.ChangeTime; + info->AllocationSize = std.AllocationSize; + info->EndOfFile = std.EndOfFile; + info->FileAttributes = basic.FileAttributes; if (DIR_is_hidden_file( attr->ObjectName )) info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; } @@ -2082,15 +2140,6 @@ static NTSTATUS FILE_QueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr, return status; } -/****************************************************************************** - * NtQueryFullAttributesFile (NTDLL.@) - */ -NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr, - FILE_NETWORK_OPEN_INFORMATION *info ) -{ - return FILE_QueryFullAttributesFile( attr, info ); -} - /****************************************************************************** * NtQueryAttributesFile (NTDLL.@) @@ -2098,17 +2147,27 @@ NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr, */ NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC_INFORMATION *info ) { - FILE_NETWORK_OPEN_INFORMATION full_info; + ANSI_STRING unix_name; NTSTATUS status; - if (!(status = FILE_QueryFullAttributesFile( attr, &full_info ))) + if (!(status = wine_nt_to_unix_file_name( attr->ObjectName, &unix_name, FILE_OPEN, + !(attr->Attributes & OBJ_CASE_INSENSITIVE) ))) { - info->CreationTime.QuadPart = full_info.CreationTime.QuadPart; - info->LastAccessTime.QuadPart = full_info.LastAccessTime.QuadPart; - info->LastWriteTime.QuadPart = full_info.LastWriteTime.QuadPart; - info->ChangeTime.QuadPart = full_info.ChangeTime.QuadPart; - info->FileAttributes = full_info.FileAttributes; + struct stat st; + + if (stat( unix_name.Buffer, &st ) == -1) + status = FILE_GetNtStatus(); + else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) + status = STATUS_INVALID_INFO_CLASS; + else + { + status = fill_stat_info( &st, info, FileBasicInformation ); + if (DIR_is_hidden_file( attr->ObjectName )) + info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; + } + RtlFreeAnsiString( &unix_name ); } + else WARN("%s not found (%x)\n", debugstr_us(attr->ObjectName), status ); return status; } diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c index b29a8ae0797..bc01a4f3d5e 100644 --- a/dlls/ntdll/nt.c +++ b/dlls/ntdll/nt.c @@ -257,12 +257,6 @@ NTSTATUS WINAPI NtQueryInformationToken( switch (tokeninfoclass) { - case TokenOwner: - len = sizeof(TOKEN_OWNER) + sizeof(SID); - break; - case TokenPrimaryGroup: - len = sizeof(TOKEN_PRIMARY_GROUP); - break; case TokenSource: len = sizeof(TOKEN_SOURCE); break; @@ -287,16 +281,17 @@ NTSTATUS WINAPI NtQueryInformationToken( switch (tokeninfoclass) { case TokenUser: - SERVER_START_REQ( get_token_user ) + SERVER_START_REQ( get_token_sid ) { TOKEN_USER * tuser = tokeninfo; PSID sid = tuser + 1; DWORD sid_len = tokeninfolength < sizeof(TOKEN_USER) ? 0 : tokeninfolength - sizeof(TOKEN_USER); req->handle = wine_server_obj_handle( token ); + req->which_sid = tokeninfoclass; wine_server_set_reply( req, sid, sid_len ); status = wine_server_call( req ); - if (retlen) *retlen = reply->user_len + sizeof(TOKEN_USER); + if (retlen) *retlen = reply->sid_len + sizeof(TOKEN_USER); if (status == STATUS_SUCCESS) { tuser->User.Sid = sid; @@ -372,17 +367,21 @@ NTSTATUS WINAPI NtQueryInformationToken( break; } case TokenPrimaryGroup: - if (tokeninfo) + SERVER_START_REQ( get_token_sid ) { TOKEN_PRIMARY_GROUP *tgroup = tokeninfo; - SID_IDENTIFIER_AUTHORITY sid = {SECURITY_NT_AUTHORITY}; - RtlAllocateAndInitializeSid( &sid, - 2, - SECURITY_BUILTIN_DOMAIN_RID, - DOMAIN_ALIAS_RID_ADMINS, - 0, 0, 0, 0, 0, 0, - &(tgroup->PrimaryGroup)); + PSID sid = tgroup + 1; + DWORD sid_len = tokeninfolength < sizeof(TOKEN_PRIMARY_GROUP) ? 0 : tokeninfolength - sizeof(TOKEN_PRIMARY_GROUP); + + req->handle = wine_server_obj_handle( token ); + req->which_sid = tokeninfoclass; + wine_server_set_reply( req, sid, sid_len ); + status = wine_server_call( req ); + if (retlen) *retlen = reply->sid_len + sizeof(TOKEN_PRIMARY_GROUP); + if (status == STATUS_SUCCESS) + tgroup->PrimaryGroup = sid; } + SERVER_END_REQ; break; case TokenPrivileges: SERVER_START_REQ( get_token_privileges ) @@ -398,15 +397,21 @@ NTSTATUS WINAPI NtQueryInformationToken( SERVER_END_REQ; break; case TokenOwner: - if (tokeninfo) + SERVER_START_REQ( get_token_sid ) { - TOKEN_OWNER *owner = tokeninfo; - PSID sid = owner + 1; - SID_IDENTIFIER_AUTHORITY localSidAuthority = {SECURITY_NT_AUTHORITY}; - RtlInitializeSid(sid, &localSidAuthority, 1); - *(RtlSubAuthoritySid(sid, 0)) = SECURITY_INTERACTIVE_RID; - owner->Owner = sid; + TOKEN_OWNER *towner = tokeninfo; + PSID sid = towner + 1; + DWORD sid_len = tokeninfolength < sizeof(TOKEN_OWNER) ? 0 : tokeninfolength - sizeof(TOKEN_OWNER); + + req->handle = wine_server_obj_handle( token ); + req->which_sid = tokeninfoclass; + wine_server_set_reply( req, sid, sid_len ); + status = wine_server_call( req ); + if (retlen) *retlen = reply->sid_len + sizeof(TOKEN_OWNER); + if (status == STATUS_SUCCESS) + towner->Owner = sid; } + SERVER_END_REQ; break; case TokenImpersonationLevel: SERVER_START_REQ( get_token_impersonation_level ) diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index b3842e03965..1150f47d398 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -59,9 +59,10 @@ extern NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handl const LARGE_INTEGER *timeout, HANDLE signal_object ); /* init routines */ +extern NTSTATUS signal_alloc_thread( TEB **teb ); +extern void signal_free_thread( TEB *teb ); extern void signal_init_thread( TEB *teb ); extern void signal_init_process(void); -extern size_t get_signal_stack_total_size(void); extern void version_init( const WCHAR *appname ); extern void debug_init(void); extern HANDLE thread_init(void); @@ -138,7 +139,9 @@ extern NTSTATUS TAPE_DeviceIoControl(HANDLE hDevice, LPVOID lpOutBuffer, DWORD nOutBufferSize); /* file I/O */ +struct stat; extern NTSTATUS FILE_GetNtStatus(void); +extern NTSTATUS fill_stat_info( const struct stat *st, void *ptr, FILE_INFORMATION_CLASS class ); extern void DIR_init_windows_dir( const WCHAR *windir, const WCHAR *sysdir ); extern BOOL DIR_is_hidden_file( const UNICODE_STRING *name ); extern NTSTATUS DIR_unmount_device( HANDLE handle ); @@ -196,40 +199,30 @@ struct debug_info /* thread private data, stored in NtCurrentTeb()->SystemReserved2 */ struct ntdll_thread_data { - DWORD fs; /* 1d4/300 TEB selector */ - DWORD gs; /* 1d8/304 libc selector; update winebuild if you move this! */ - struct debug_info *debug_info; /* 1dc/308 info for debugstr functions */ - int request_fd; /* 1e0/310 fd for sending server requests */ - int reply_fd; /* 1e4/314 fd for receiving server replies */ - int wait_fd[2]; /* 1e8/318 fd for sleeping server requests */ - BOOL wow64_redir; /* 1f0/320 Wow64 filesystem redirection flag */ #ifdef __i386__ - void *vm86_ptr; /* 1f4/328 data for vm86 mode */ + DWORD dr0; /* 1bc Debug registers */ + DWORD dr1; /* 1c0 */ + DWORD dr2; /* 1c4 */ + DWORD dr3; /* 1c8 */ + DWORD dr6; /* 1cc */ + DWORD dr7; /* 1d0 */ + DWORD fs; /* 1d4 TEB selector */ + DWORD gs; /* 1d8 libc selector; update winebuild if you move this! */ + void *vm86_ptr; /* 1dc data for vm86 mode */ #else - void *exit_frame; /* 1f4/328 exit frame pointer */ + void *exit_frame; /* /2e8 exit frame pointer */ #endif - pthread_t pthread_id; /* 1f8/330 pthread thread id */ + struct debug_info *debug_info; /* 1e0/2f0 info for debugstr functions */ + int request_fd; /* 1e4/2f8 fd for sending server requests */ + int reply_fd; /* 1e8/2fc fd for receiving server replies */ + int wait_fd[2]; /* 1ec/300 fd for sleeping server requests */ + BOOL wow64_redir; /* 1f4/308 Wow64 filesystem redirection flag */ + pthread_t pthread_id; /* 1f8/310 pthread thread id */ }; static inline struct ntdll_thread_data *ntdll_get_thread_data(void) { - return (struct ntdll_thread_data *)NtCurrentTeb()->SystemReserved2; -} - -/* thread debug_registers, stored in NtCurrentTeb()->SpareBytes1 */ -struct ntdll_thread_regs -{ - DWORD dr0; - DWORD dr1; - DWORD dr2; - DWORD dr3; - DWORD dr6; - DWORD dr7; -}; - -static inline struct ntdll_thread_regs *ntdll_get_thread_regs(void) -{ - return (struct ntdll_thread_regs *)NtCurrentTeb()->SpareBytes1; + return (struct ntdll_thread_data *)NtCurrentTeb()->SpareBytes1; } /* Register functions */ diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index 79e38062955..a4bb95d23a8 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -847,7 +847,7 @@ static void wine_sigacthandler( int signal, siginfo_t *siginfo, void *sigcontext __asm__ __volatile__("mov %ss,%ax; mov %ax,%ds; mov %ax,%es"); - thread_data = (struct ntdll_thread_data *)get_current_teb()->SystemReserved2; + thread_data = (struct ntdll_thread_data *)get_current_teb()->SpareBytes1; wine_set_fs( thread_data->fs ); wine_set_gs( thread_data->gs ); @@ -898,7 +898,7 @@ static inline void *init_handler( const SIGCONTEXT *sigcontext, WORD *fs, WORD * #ifndef __sun /* see above for Solaris handling */ { - struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SystemReserved2; + struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SpareBytes1; wine_set_fs( thread_data->fs ); wine_set_gs( thread_data->gs ); } @@ -1042,7 +1042,7 @@ static void fpux_to_fpu( FLOATING_SAVE_AREA *fpu, const XMM_SAVE_AREA32 *fpux ) */ static inline void save_context( CONTEXT *context, const SIGCONTEXT *sigcontext, WORD fs, WORD gs ) { - struct ntdll_thread_regs * const regs = ntdll_get_thread_regs(); + struct ntdll_thread_data * const regs = ntdll_get_thread_data(); FLOATING_SAVE_AREA *fpu = FPU_sig(sigcontext); XMM_SAVE_AREA32 *fpux = FPUX_sig(sigcontext); @@ -1094,7 +1094,7 @@ static inline void save_context( CONTEXT *context, const SIGCONTEXT *sigcontext, */ static inline void restore_context( const CONTEXT *context, SIGCONTEXT *sigcontext ) { - struct ntdll_thread_regs * const regs = ntdll_get_thread_regs(); + struct ntdll_thread_data * const regs = ntdll_get_thread_data(); FLOATING_SAVE_AREA *fpu = FPU_sig(sigcontext); XMM_SAVE_AREA32 *fpux = FPUX_sig(sigcontext); @@ -1161,13 +1161,12 @@ void set_cpu_context( const CONTEXT *context ) if (flags & CONTEXT_DEBUG_REGISTERS) { - struct ntdll_thread_regs * const regs = ntdll_get_thread_regs(); - regs->dr0 = context->Dr0; - regs->dr1 = context->Dr1; - regs->dr2 = context->Dr2; - regs->dr3 = context->Dr3; - regs->dr6 = context->Dr6; - regs->dr7 = context->Dr7; + ntdll_get_thread_data()->dr0 = context->Dr0; + ntdll_get_thread_data()->dr1 = context->Dr1; + ntdll_get_thread_data()->dr2 = context->Dr2; + ntdll_get_thread_data()->dr3 = context->Dr3; + ntdll_get_thread_data()->dr6 = context->Dr6; + ntdll_get_thread_data()->dr7 = context->Dr7; } if (flags & CONTEXT_FULL) { @@ -1694,13 +1693,11 @@ static void WINAPI raise_trap_exception( EXCEPTION_RECORD *rec, CONTEXT *context if (rec->ExceptionCode == EXCEPTION_SINGLE_STEP) { - struct ntdll_thread_regs * const regs = ntdll_get_thread_regs(); - /* when single stepping can't tell whether this is a hw bp or a * single step interrupt. try to avoid as much overhead as possible * and only do a server call if there is any hw bp enabled. */ - if( !(context->EFlags & 0x100) || (regs->dr7 & 0xff) ) + if( !(context->EFlags & 0x100) || (ntdll_get_thread_data()->dr7 & 0xff) ) { /* (possible) hardware breakpoint, fetch the debug registers */ context->ContextFlags = CONTEXT_DEBUG_REGISTERS; @@ -1995,35 +1992,87 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext ) } +/*********************************************************************** + * __wine_set_signal_handler (NTDLL.@) + */ +int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh) +{ + if (sig >= sizeof(handlers) / sizeof(handlers[0])) return -1; + if (handlers[sig] != NULL) return -2; + handlers[sig] = wsh; + return 0; +} + + /********************************************************************** - * get_signal_stack_total_size - * - * Retrieve the size to allocate for the signal stack, including the TEB at the bottom. - * Must be a power of two. + * signal_alloc_thread */ -size_t get_signal_stack_total_size(void) +NTSTATUS signal_alloc_thread( TEB **teb ) { - if (!signal_stack_size) + static size_t sigstack_zero_bits; + struct ntdll_thread_data *thread_data; + struct ntdll_thread_data *parent_data = NULL; + SIZE_T size; + void *addr = NULL; + NTSTATUS status; + + if (!sigstack_zero_bits) { - size_t size = 8192, min_size = teb_size + max( MINSIGSTKSZ, 8192 ); + size_t min_size = teb_size + max( MINSIGSTKSZ, 8192 ); /* find the first power of two not smaller than min_size */ - while (size < min_size) size *= 2; - signal_stack_mask = size - 1; - signal_stack_size = size - teb_size; + sigstack_zero_bits = 12; + while ((1u << sigstack_zero_bits) < min_size) sigstack_zero_bits++; + signal_stack_mask = (1 << sigstack_zero_bits) - 1; + signal_stack_size = (1 << sigstack_zero_bits) - teb_size; } - return signal_stack_size + teb_size; + else parent_data = ntdll_get_thread_data(); + + size = signal_stack_mask + 1; + if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), &addr, sigstack_zero_bits, + &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE ))) + { + *teb = addr; + (*teb)->Tib.Self = &(*teb)->Tib; + (*teb)->Tib.ExceptionList = (void *)~0UL; + thread_data = (struct ntdll_thread_data *)(*teb)->SpareBytes1; + if (!(thread_data->fs = wine_ldt_alloc_fs())) + { + size = 0; + NtFreeVirtualMemory( NtCurrentProcess(), &addr, &size, MEM_RELEASE ); + status = STATUS_TOO_MANY_THREADS; + } + if (parent_data) + { + /* inherit debug registers from parent thread */ + thread_data->dr0 = parent_data->dr0; + thread_data->dr1 = parent_data->dr1; + thread_data->dr2 = parent_data->dr2; + thread_data->dr3 = parent_data->dr3; + thread_data->dr6 = parent_data->dr6; + thread_data->dr7 = parent_data->dr7; + } + + } + return status; } -/*********************************************************************** - * __wine_set_signal_handler (NTDLL.@) +/********************************************************************** + * signal_free_thread */ -int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh) +void signal_free_thread( TEB *teb ) { - if (sig >= sizeof(handlers) / sizeof(handlers[0])) return -1; - if (handlers[sig] != NULL) return -2; - handlers[sig] = wsh; - return 0; + SIZE_T size; + struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SpareBytes1; + + if (thread_data) wine_ldt_free_fs( thread_data->fs ); + if (teb->DeallocationStack) + { + size = 0; + NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE ); + } + size = 0; + NtFreeVirtualMemory( NtCurrentProcess(), (void **)&teb, &size, MEM_RELEASE ); } @@ -2032,7 +2081,7 @@ int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh) */ void signal_init_thread( TEB *teb ) { - struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SystemReserved2; + struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SpareBytes1; LDT_ENTRY fs_entry; stack_t ss; diff --git a/dlls/ntdll/signal_powerpc.c b/dlls/ntdll/signal_powerpc.c index a1a6ccc3f91..662d97ba91d 100644 --- a/dlls/ntdll/signal_powerpc.c +++ b/dlls/ntdll/signal_powerpc.c @@ -965,19 +965,6 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext ) } -/********************************************************************** - * get_signal_stack_total_size - * - * Retrieve the size to allocate for the signal stack, including the TEB at the bottom. - * Must be a power of two. - */ -size_t get_signal_stack_total_size(void) -{ - assert( sizeof(TEB) <= getpagesize() ); - return getpagesize(); /* this is just for the TEB, we don't need a signal stack */ -} - - /*********************************************************************** * __wine_set_signal_handler (NTDLL.@) */ @@ -991,6 +978,52 @@ int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh) /********************************************************************** + * signal_alloc_thread + */ +NTSTATUS signal_alloc_thread( TEB **teb ) +{ + static size_t sigstack_zero_bits; + SIZE_T size; + NTSTATUS status; + + if (!sigstack_zero_bits) + { + size_t min_size = getpagesize(); /* this is just for the TEB, we don't use a signal stack yet */ + /* find the first power of two not smaller than min_size */ + while ((1u << sigstack_zero_bits) < min_size) sigstack_zero_bits++; + assert( sizeof(TEB) <= min_size ); + } + + size = 1 << sigstack_zero_bits; + *teb = NULL; + if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)teb, sigstack_zero_bits, + &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE ))) + { + (*teb)->Tib.Self = &(*teb)->Tib; + (*teb)->Tib.ExceptionList = (void *)~0UL; + } + return status; +} + + +/********************************************************************** + * signal_free_thread + */ +void signal_free_thread( TEB *teb ) +{ + SIZE_T size; + + if (teb->DeallocationStack) + { + size = 0; + NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE ); + } + size = 0; + NtFreeVirtualMemory( NtCurrentProcess(), (void **)&teb, &size, MEM_RELEASE ); +} + + +/********************************************************************** * signal_init_thread */ void signal_init_thread( TEB *teb ) diff --git a/dlls/ntdll/signal_sparc.c b/dlls/ntdll/signal_sparc.c index 2952f8ed4a6..660bc9c89d1 100644 --- a/dlls/ntdll/signal_sparc.c +++ b/dlls/ntdll/signal_sparc.c @@ -700,19 +700,6 @@ static void usr1_handler( int signal, struct siginfo *info, void *ucontext ) } -/********************************************************************** - * get_signal_stack_total_size - * - * Retrieve the size to allocate for the signal stack, including the TEB at the bottom. - * Must be a power of two. - */ -size_t get_signal_stack_total_size(void) -{ - assert( sizeof(TEB) <= getpagesize() ); - return getpagesize(); /* this is just for the TEB, we don't need a signal stack */ -} - - /*********************************************************************** * __wine_set_signal_handler (NTDLL.@) */ @@ -726,6 +713,52 @@ int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh) /********************************************************************** + * signal_alloc_thread + */ +NTSTATUS signal_alloc_thread( TEB **teb ) +{ + static size_t sigstack_zero_bits; + SIZE_T size; + NTSTATUS status; + + if (!sigstack_zero_bits) + { + size_t min_size = getpagesize(); /* this is just for the TEB, we don't use a signal stack yet */ + /* find the first power of two not smaller than min_size */ + while ((1u << sigstack_zero_bits) < min_size) sigstack_zero_bits++; + assert( sizeof(TEB) <= min_size ); + } + + size = 1 << sigstack_zero_bits; + *teb = NULL; + if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)teb, sigstack_zero_bits, + &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE ))) + { + (*teb)->Tib.Self = &(*teb)->Tib; + (*teb)->Tib.ExceptionList = (void *)~0UL; + } + return status; +} + + +/********************************************************************** + * signal_free_thread + */ +void signal_free_thread( TEB *teb ) +{ + SIZE_T size; + + if (teb->DeallocationStack) + { + size = 0; + NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE ); + } + size = 0; + NtFreeVirtualMemory( NtCurrentProcess(), (void **)&teb, &size, MEM_RELEASE ); +} + + +/********************************************************************** * signal_init_thread */ void signal_init_thread( TEB *teb ) diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index 7e6c6347858..94ec742f162 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -2191,35 +2191,63 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *ucontext ) } +/*********************************************************************** + * __wine_set_signal_handler (NTDLL.@) + */ +int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh) +{ + if (sig > sizeof(handlers) / sizeof(handlers[0])) return -1; + if (handlers[sig] != NULL) return -2; + handlers[sig] = wsh; + return 0; +} + + /********************************************************************** - * get_signal_stack_total_size - * - * Retrieve the size to allocate for the signal stack, including the TEB at the bottom. - * Must be a power of two. + * signal_alloc_thread */ -size_t get_signal_stack_total_size(void) +NTSTATUS signal_alloc_thread( TEB **teb ) { - assert( sizeof(TEB) <= teb_size ); - if (!signal_stack_size) + static size_t sigstack_zero_bits; + SIZE_T size; + NTSTATUS status; + + if (!sigstack_zero_bits) { - size_t size = 8192, min_size = teb_size + max( MINSIGSTKSZ, 8192 ); + size_t min_size = teb_size + max( MINSIGSTKSZ, 8192 ); /* find the first power of two not smaller than min_size */ - while (size < min_size) size *= 2; - signal_stack_size = size - teb_size; + sigstack_zero_bits = 12; + while ((1u << sigstack_zero_bits) < min_size) sigstack_zero_bits++; + signal_stack_size = (1 << sigstack_zero_bits) - teb_size; + assert( sizeof(TEB) <= teb_size ); } - return signal_stack_size + teb_size; + + size = 1 << sigstack_zero_bits; + *teb = NULL; + if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)teb, sigstack_zero_bits, + &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE ))) + { + (*teb)->Tib.Self = &(*teb)->Tib; + (*teb)->Tib.ExceptionList = (void *)~0UL; + } + return status; } -/*********************************************************************** - * __wine_set_signal_handler (NTDLL.@) +/********************************************************************** + * signal_free_thread */ -int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh) +void signal_free_thread( TEB *teb ) { - if (sig > sizeof(handlers) / sizeof(handlers[0])) return -1; - if (handlers[sig] != NULL) return -2; - handlers[sig] = wsh; - return 0; + SIZE_T size; + + if (teb->DeallocationStack) + { + size = 0; + NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE ); + } + size = 0; + NtFreeVirtualMemory( NtCurrentProcess(), (void **)&teb, &size, MEM_RELEASE ); } diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 06e35b4ed01..8eff7d3a721 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -41,10 +41,13 @@ #endif static BOOL (WINAPI * pGetVolumePathNameW)(LPCWSTR, LPWSTR, DWORD); +static UINT (WINAPI *pGetSystemWow64DirectoryW)( LPWSTR, UINT ); static NTSTATUS (WINAPI *pRtlFreeUnicodeString)( PUNICODE_STRING ); static VOID (WINAPI *pRtlInitUnicodeString)( PUNICODE_STRING, LPCWSTR ); static BOOL (WINAPI *pRtlDosPathNameToNtPathName_U)( LPCWSTR, PUNICODE_STRING, PWSTR*, CURDIR* ); +static NTSTATUS (WINAPI *pRtlWow64EnableFsRedirectionEx)( ULONG, ULONG * ); + static NTSTATUS (WINAPI *pNtCreateMailslotFile)( PHANDLE, ULONG, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, ULONG, ULONG, ULONG, PLARGE_INTEGER ); static NTSTATUS (WINAPI *pNtDeleteFile)(POBJECT_ATTRIBUTES ObjectAttributes); @@ -945,6 +948,7 @@ static void test_file_name_information(void) { WCHAR *file_name, *volume_prefix, *expected; FILE_NAME_INFORMATION *info; + ULONG old_redir = 1, tmp; UINT file_name_size; IO_STATUS_BLOCK io; UINT info_size; @@ -980,9 +984,11 @@ static void test_file_name_information(void) info_size = sizeof(*info) + (file_name_size * sizeof(WCHAR)); info = HeapAlloc( GetProcessHeap(), 0, info_size ); + if (pRtlWow64EnableFsRedirectionEx) pRtlWow64EnableFsRedirectionEx( TRUE, &old_redir ); h = CreateFileW( file_name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + if (pRtlWow64EnableFsRedirectionEx) pRtlWow64EnableFsRedirectionEx( old_redir, &tmp ); ok(h != INVALID_HANDLE_VALUE, "Failed to open file.\n"); hr = pNtQueryInformationFile( h, &io, info, sizeof(*info) - 1, FileNameInformation ); @@ -1021,6 +1027,51 @@ static void test_file_name_information(void) HeapFree( GetProcessHeap(), 0, info ); HeapFree( GetProcessHeap(), 0, expected ); HeapFree( GetProcessHeap(), 0, volume_prefix ); + + if (old_redir || !pGetSystemWow64DirectoryW || !(file_name_size = pGetSystemWow64DirectoryW( NULL, 0 ))) + { + skip("Not running on WoW64, skipping test.\n"); + HeapFree( GetProcessHeap(), 0, file_name ); + return; + } + + h = CreateFileW( file_name, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok(h != INVALID_HANDLE_VALUE, "Failed to open file.\n"); + HeapFree( GetProcessHeap(), 0, file_name ); + + file_name = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*file_name) ); + volume_prefix = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*volume_prefix) ); + expected = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*expected) ); + + len = pGetSystemWow64DirectoryW( file_name, file_name_size ); + ok(len == file_name_size - 1, + "GetSystemWow64DirectoryW returned %u, expected %u.\n", + len, file_name_size - 1); + + len = pGetVolumePathNameW( file_name, volume_prefix, file_name_size ); + ok(len, "GetVolumePathNameW failed.\n"); + + len = lstrlenW( volume_prefix ); + if (len && volume_prefix[len - 1] == '\\') --len; + memcpy( expected, file_name + len, (file_name_size - len - 1) * sizeof(WCHAR) ); + expected[file_name_size - len - 1] = '\0'; + + info_size = sizeof(*info) + (file_name_size * sizeof(WCHAR)); + info = HeapAlloc( GetProcessHeap(), 0, info_size ); + + memset( info, 0xcc, info_size ); + hr = pNtQueryInformationFile( h, &io, info, info_size, FileNameInformation ); + ok(hr == STATUS_SUCCESS, "NtQueryInformationFile returned %#x, expected %#x.\n", hr, STATUS_SUCCESS); + info->FileName[info->FileNameLength / sizeof(WCHAR)] = '\0'; + ok(!lstrcmpiW( info->FileName, expected ), "info->FileName is %s, expected %s.\n", + wine_dbgstr_w( info->FileName ), wine_dbgstr_w( expected )); + + CloseHandle( h ); + HeapFree( GetProcessHeap(), 0, info ); + HeapFree( GetProcessHeap(), 0, expected ); + HeapFree( GetProcessHeap(), 0, volume_prefix ); HeapFree( GetProcessHeap(), 0, file_name ); } @@ -1035,10 +1086,12 @@ START_TEST(file) } pGetVolumePathNameW = (void *)GetProcAddress(hkernel32, "GetVolumePathNameW"); + pGetSystemWow64DirectoryW = (void *)GetProcAddress(hkernel32, "GetSystemWow64DirectoryW"); pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll, "RtlFreeUnicodeString"); pRtlInitUnicodeString = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString"); pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(hntdll, "RtlDosPathNameToNtPathName_U"); + pRtlWow64EnableFsRedirectionEx = (void *)GetProcAddress(hntdll, "RtlWow64EnableFsRedirectionEx"); pNtCreateMailslotFile = (void *)GetProcAddress(hntdll, "NtCreateMailslotFile"); pNtDeleteFile = (void *)GetProcAddress(hntdll, "NtDeleteFile"); pNtReadFile = (void *)GetProcAddress(hntdll, "NtReadFile"); diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index 30a299db0e0..b9529bdfb44 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -64,8 +64,6 @@ static RTL_BITMAP tls_bitmap; static RTL_BITMAP tls_expansion_bitmap; static RTL_BITMAP fls_bitmap; static LIST_ENTRY tls_links; -static size_t sigstack_total_size; -static ULONG sigstack_zero_bits; static int nb_threads = 1; static RTL_CRITICAL_SECTION ldt_section; @@ -103,29 +101,6 @@ static void ldt_unlock(void) /*********************************************************************** - * init_teb - */ -static inline NTSTATUS init_teb( TEB *teb ) -{ - struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SystemReserved2; - - teb->Tib.ExceptionList = (void *)~0UL; - teb->Tib.StackBase = (void *)~0UL; - teb->Tib.Self = &teb->Tib; - teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer; - teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); - - if (!(thread_data->fs = wine_ldt_alloc_fs())) return STATUS_TOO_MANY_THREADS; - thread_data->request_fd = -1; - thread_data->reply_fd = -1; - thread_data->wait_fd[0] = -1; - thread_data->wait_fd[1] = -1; - - return STATUS_SUCCESS; -} - - -/*********************************************************************** * get_unicode_string * * Copy a unicode string from the startup info. @@ -297,19 +272,17 @@ HANDLE thread_init(void) /* allocate and initialize the initial TEB */ - sigstack_total_size = get_signal_stack_total_size(); - while (1U << sigstack_zero_bits < sigstack_total_size) sigstack_zero_bits++; - assert( 1U << sigstack_zero_bits == sigstack_total_size ); /* must be a power of 2 */ - assert( sigstack_total_size >= sizeof(TEB) + sizeof(struct startup_info) ); - - addr = NULL; - size = sigstack_total_size; - NtAllocateVirtualMemory( NtCurrentProcess(), &addr, sigstack_zero_bits, - &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE ); - teb = addr; + signal_alloc_thread( &teb ); teb->Peb = peb; - init_teb( teb ); - thread_data = (struct ntdll_thread_data *)teb->SystemReserved2; + teb->Tib.StackBase = (void *)~0UL; + teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer; + teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); + + thread_data = (struct ntdll_thread_data *)teb->SpareBytes1; + thread_data->request_fd = -1; + thread_data->reply_fd = -1; + thread_data->wait_fd[0] = -1; + thread_data->wait_fd[1] = -1; thread_data->debug_info = &debug_info; InsertHeadList( &tls_links, &teb->TlsLinks ); @@ -416,15 +389,10 @@ void exit_thread( int status ) if ((teb = interlocked_xchg_ptr( &prev_teb, NtCurrentTeb() ))) { - struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SystemReserved2; - SIZE_T size; + struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SpareBytes1; pthread_join( thread_data->pthread_id, NULL ); - wine_ldt_free_fs( thread_data->fs ); - size = 0; - NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE ); - size = 0; - NtFreeVirtualMemory( GetCurrentProcess(), (void **)&teb, &size, MEM_RELEASE ); + signal_free_thread( teb ); } close( ntdll_get_thread_data()->wait_fd[0] ); @@ -443,7 +411,7 @@ void exit_thread( int status ) static void start_thread( struct startup_info *info ) { TEB *teb = info->teb; - struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SystemReserved2; + struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SpareBytes1; PRTL_THREAD_START_ROUTINE func = info->entry_point; void *arg = info->entry_arg; struct debug_info debug_info; @@ -482,16 +450,13 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR * sigset_t sigset; pthread_t pthread_id; pthread_attr_t attr; - struct ntdll_thread_data *thread_data = NULL; - struct ntdll_thread_regs *thread_regs; + struct ntdll_thread_data *thread_data; struct startup_info *info = NULL; - void *addr = NULL; HANDLE handle = 0; - TEB *teb; + TEB *teb = NULL; DWORD tid = 0; int request_pipe[2]; NTSTATUS status; - SIZE_T size; if (process != NtCurrentProcess()) { @@ -544,34 +509,24 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR * pthread_sigmask( SIG_BLOCK, &server_block_set, &sigset ); - addr = NULL; - size = sigstack_total_size; - if ((status = NtAllocateVirtualMemory( NtCurrentProcess(), &addr, sigstack_zero_bits, - &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE ))) - goto error; - teb = addr; + if ((status = signal_alloc_thread( &teb ))) goto error; + teb->Peb = NtCurrentTeb()->Peb; + teb->ClientId.UniqueProcess = ULongToHandle(GetCurrentProcessId()); + teb->ClientId.UniqueThread = ULongToHandle(tid); + teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer; + teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); + info = (struct startup_info *)(teb + 1); info->teb = teb; info->entry_point = start; info->entry_arg = param; - if ((status = init_teb( teb ))) goto error; - - teb->ClientId.UniqueProcess = ULongToHandle(GetCurrentProcessId()); - teb->ClientId.UniqueThread = ULongToHandle(tid); - - thread_data = (struct ntdll_thread_data *)teb->SystemReserved2; - thread_regs = (struct ntdll_thread_regs *)teb->SpareBytes1; + thread_data = (struct ntdll_thread_data *)teb->SpareBytes1; thread_data->request_fd = request_pipe[1]; - - /* inherit debug registers from parent thread */ - thread_regs->dr0 = ntdll_get_thread_regs()->dr0; - thread_regs->dr1 = ntdll_get_thread_regs()->dr1; - thread_regs->dr2 = ntdll_get_thread_regs()->dr2; - thread_regs->dr3 = ntdll_get_thread_regs()->dr3; - thread_regs->dr6 = ntdll_get_thread_regs()->dr6; - thread_regs->dr7 = ntdll_get_thread_regs()->dr7; + thread_data->reply_fd = -1; + thread_data->wait_fd[0] = -1; + thread_data->wait_fd[1] = -1; if ((status = virtual_alloc_thread_stack( teb, stack_reserve, stack_commit ))) goto error; @@ -584,8 +539,6 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR * { interlocked_xchg_add( &nb_threads, -1 ); pthread_attr_destroy( &attr ); - size = 0; - NtFreeVirtualMemory( NtCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE ); status = STATUS_NO_MEMORY; goto error; } @@ -599,12 +552,7 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR * return STATUS_SUCCESS; error: - if (thread_data) wine_ldt_free_fs( thread_data->fs ); - if (addr) - { - size = 0; - NtFreeVirtualMemory( NtCurrentProcess(), &addr, &size, MEM_RELEASE ); - } + if (teb) signal_free_thread( teb ); if (handle) NtClose( handle ); pthread_sigmask( SIG_SETMASK, &sigset, NULL ); close( request_pipe[1] ); @@ -756,10 +704,12 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context ) self = (handle == GetCurrentThread()); if (self && (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386))) { - struct ntdll_thread_regs * const regs = ntdll_get_thread_regs(); - self = (regs->dr0 == context->Dr0 && regs->dr1 == context->Dr1 && - regs->dr2 == context->Dr2 && regs->dr3 == context->Dr3 && - regs->dr6 == context->Dr6 && regs->dr7 == context->Dr7); + self = (ntdll_get_thread_data()->dr0 == context->Dr0 && + ntdll_get_thread_data()->dr1 == context->Dr1 && + ntdll_get_thread_data()->dr2 == context->Dr2 && + ntdll_get_thread_data()->dr3 == context->Dr3 && + ntdll_get_thread_data()->dr6 == context->Dr6 && + ntdll_get_thread_data()->dr7 == context->Dr7); } #endif @@ -914,13 +864,12 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) /* update the cached version of the debug registers */ if (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)) { - struct ntdll_thread_regs * const regs = ntdll_get_thread_regs(); - regs->dr0 = context->Dr0; - regs->dr1 = context->Dr1; - regs->dr2 = context->Dr2; - regs->dr3 = context->Dr3; - regs->dr6 = context->Dr6; - regs->dr7 = context->Dr7; + ntdll_get_thread_data()->dr0 = context->Dr0; + ntdll_get_thread_data()->dr1 = context->Dr1; + ntdll_get_thread_data()->dr2 = context->Dr2; + ntdll_get_thread_data()->dr3 = context->Dr3; + ntdll_get_thread_data()->dr6 = context->Dr6; + ntdll_get_thread_data()->dr7 = context->Dr7; } #endif } diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index 93d72a644a2..06971ad3d02 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -1117,6 +1117,25 @@ PVOID WINAPI MmAllocateNonCachedMemory( SIZE_T size ) return VirtualAlloc( NULL, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE|PAGE_NOCACHE ); } +/*********************************************************************** + * MmAllocateContiguousMemory (NTOSKRNL.EXE.@) + */ +PVOID WINAPI MmAllocateContiguousMemory( SIZE_T size, PHYSICAL_ADDRESS highest_valid_address ) +{ + FIXME( "%lu, %s stub\n", size, wine_dbgstr_longlong(highest_valid_address.QuadPart) ); + return NULL; +} + +/*********************************************************************** + * MmAllocatePagesForMdl (NTOSKRNL.EXE.@) + */ +PMDL WINAPI MmAllocatePagesForMdl(PHYSICAL_ADDRESS lowaddress, PHYSICAL_ADDRESS highaddress, + PHYSICAL_ADDRESS skipbytes, SIZE_T size) +{ + FIXME("%s %s %s %lu: stub\n", wine_dbgstr_longlong(lowaddress.QuadPart), wine_dbgstr_longlong(highaddress.QuadPart), + wine_dbgstr_longlong(skipbytes.QuadPart), size); + return NULL; +} /*********************************************************************** * MmFreeNonCachedMemory (NTOSKRNL.EXE.@) diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec index fa793eb11c5..b85fcb9bd83 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec +++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec @@ -655,11 +655,11 @@ @ stub MmAddVerifierThunks @ stub MmAdjustWorkingSetSize @ stub MmAdvanceMdl -@ stub MmAllocateContiguousMemory +@ stdcall MmAllocateContiguousMemory(long double) @ stub MmAllocateContiguousMemorySpecifyCache @ stub MmAllocateMappingAddress @ stdcall MmAllocateNonCachedMemory(long) -@ stub MmAllocatePagesForMdl +@ stdcall MmAllocatePagesForMdl(double double double long) @ stub MmBuildMdlForNonPagedPool @ stub MmCanFileBeTruncated @ stub MmCommitSessionMappedView diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index c8c48081d40..321f2e9c3cf 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -2130,7 +2130,7 @@ HRESULT WINAPI CoRegisterClassObject( FIXME("Failed to create stream on hglobal, %x\n", hr); return hr; } - hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory, + hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IUnknown, newClass->classObject, MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG); if (hr) { @@ -2380,7 +2380,7 @@ HRESULT WINAPI CoGetClassObject( if (CLSCTX_REMOTE_SERVER & dwClsContext) { FIXME ("CLSCTX_REMOTE_SERVER not supported\n"); - hres = E_NOINTERFACE; + hres = REGDB_E_CLASSNOTREG; } if (FAILED(hres)) @@ -4106,6 +4106,33 @@ HRESULT WINAPI CoGetContextToken( ULONG_PTR *token ) return S_OK; } +HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) +{ + static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0}; + HKEY hkey; + HRESULT hres; + + hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey); + if (SUCCEEDED(hres)) + { + WCHAR dllpath[MAX_PATH+1]; + + if (COM_RegReadPath(hkey, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS) + { + static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0}; + if (!strcmpiW(dllpath, wszOle32)) + { + RegCloseKey(hkey); + return HandlerCF_Create(rclsid, riid, ppv); + } + } + else + WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath)); + RegCloseKey(hkey); + } + + return CLASS_E_CLASSNOTAVAILABLE; +} /*********************************************************************** * DllMain (OLE32.@) diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h index fb059349f8c..076d845c85a 100644 --- a/dlls/ole32/compobj_private.h +++ b/dlls/ole32/compobj_private.h @@ -313,6 +313,9 @@ extern HRESULT WINAPI OLE32_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID extern HRESULT WINAPI OLE32_DllRegisterServer(void) DECLSPEC_HIDDEN; extern HRESULT WINAPI OLE32_DllUnregisterServer(void) DECLSPEC_HIDDEN; +extern HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv); +extern HRESULT HandlerCF_Create(REFCLSID rclsid, REFIID riid, LPVOID *ppv); + /* Exported non-interface Data Advise Holder functions */ HRESULT DataAdviseHolder_OnConnect(IDataAdviseHolder *iface, IDataObject *pDelegate); void DataAdviseHolder_OnDisconnect(IDataAdviseHolder *iface); diff --git a/dlls/ole32/defaulthandler.c b/dlls/ole32/defaulthandler.c index 4102d50845b..5130513d57f 100644 --- a/dlls/ole32/defaulthandler.c +++ b/dlls/ole32/defaulthandler.c @@ -1960,9 +1960,21 @@ static DefaultHandler* DefaultHandler_Construct( &IID_IUnknown, (void**)&This->dataCache); if(SUCCEEDED(hr)) + { hr = IUnknown_QueryInterface(This->dataCache, &IID_IPersistStorage, (void**)&This->dataCache_PersistStg); + /* keeping a reference to This->dataCache_PersistStg causes us to keep a + * reference on the outer object */ + if (SUCCEEDED(hr)) + IUnknown_Release(This->outerUnknown); + else + IUnknown_Release(This->dataCache); + } if(FAILED(hr)) + { ERR("Unexpected error creating data cache\n"); + HeapFree(GetProcessHeap(), 0, This); + return NULL; + } This->clsid = *clsid; This->clientSite = NULL; @@ -2009,6 +2021,13 @@ static DefaultHandler* DefaultHandler_Construct( static void DefaultHandler_Destroy( DefaultHandler* This) { + TRACE("(%p)\n", This); + + /* AddRef/Release may be called on this object during destruction. + * Prevent the object being destroyed recursively by artificially raising + * the reference count. */ + This->ref = 10000; + /* release delegates */ DefaultHandler_Stop(This); release_delegates(This); @@ -2020,6 +2039,9 @@ static void DefaultHandler_Destroy( if (This->dataCache) { + /* to balance out the release of dataCache_PersistStg which will result + * in a reference being released from the outer unknown */ + IUnknown_AddRef(This->outerUnknown); IPersistStorage_Release(This->dataCache_PersistStg); IUnknown_Release(This->dataCache); This->dataCache_PersistStg = NULL; @@ -2122,3 +2144,77 @@ HRESULT WINAPI OleCreateDefaultHandler(REFCLSID clsid, LPUNKNOWN pUnkOuter, return OleCreateEmbeddingHelper(clsid, pUnkOuter, EMBDHLP_INPROC_HANDLER | EMBDHLP_CREATENOW, NULL, riid, ppvObj); } + +typedef struct HandlerCF +{ + const IClassFactoryVtbl *lpVtbl; + LONG refs; + CLSID clsid; +} HandlerCF; + +static HRESULT WINAPI +HandlerCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid,&IID_IUnknown) || + IsEqualIID(riid,&IID_IClassFactory)) + { + *ppv = iface; + IClassFactory_AddRef(iface); + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI HandlerCF_AddRef(LPCLASSFACTORY iface) +{ + HandlerCF *This = (HandlerCF *)iface; + return InterlockedIncrement(&This->refs); +} + +static ULONG WINAPI HandlerCF_Release(LPCLASSFACTORY iface) +{ + HandlerCF *This = (HandlerCF *)iface; + ULONG refs = InterlockedDecrement(&This->refs); + if (!refs) + HeapFree(GetProcessHeap(), 0, This); + return refs; +} + +static HRESULT WINAPI +HandlerCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pUnk, + REFIID riid, LPVOID *ppv) +{ + HandlerCF *This = (HandlerCF *)iface; + return OleCreateDefaultHandler(&This->clsid, pUnk, riid, ppv); +} + +static HRESULT WINAPI HandlerCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) +{ + FIXME("(%d), stub!\n",fLock); + return S_OK; +} + +static const IClassFactoryVtbl HandlerClassFactoryVtbl = { + HandlerCF_QueryInterface, + HandlerCF_AddRef, + HandlerCF_Release, + HandlerCF_CreateInstance, + HandlerCF_LockServer +}; + +HRESULT HandlerCF_Create(REFCLSID rclsid, REFIID riid, LPVOID *ppv) +{ + HRESULT hr; + HandlerCF *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + if (!This) return E_OUTOFMEMORY; + This->lpVtbl = &HandlerClassFactoryVtbl; + This->refs = 0; + This->clsid = *rclsid; + + hr = IUnknown_QueryInterface((IUnknown *)&This->lpVtbl, riid, ppv); + if (FAILED(hr)) + HeapFree(GetProcessHeap(), 0, This); + + return hr; +} diff --git a/dlls/ole32/filemoniker.c b/dlls/ole32/filemoniker.c index 9decfaf124d..ff543aa7f7b 100644 --- a/dlls/ole32/filemoniker.c +++ b/dlls/ole32/filemoniker.c @@ -960,20 +960,32 @@ FileMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** p if(mkSys==MKSYS_FILEMONIKER){ HRESULT ret; - CreateBindCtx(0,&pbind); + ret = CreateBindCtx(0,&pbind); + if (FAILED(ret)) + return ret; /* create a string based on common part of the two paths */ - IMoniker_GetDisplayName(iface,pbind,NULL,&pathThis); - IMoniker_GetDisplayName(pmkOther,pbind,NULL,&pathOther); + ret = IMoniker_GetDisplayName(iface,pbind,NULL,&pathThis); + if (FAILED(ret)) + return ret; + ret = IMoniker_GetDisplayName(pmkOther,pbind,NULL,&pathOther); + if (FAILED(ret)) + return ret; nb1=FileMonikerImpl_DecomposePath(pathThis,&stringTable1); + if (FAILED(nb1)) + return nb1; nb2=FileMonikerImpl_DecomposePath(pathOther,&stringTable2); + if (FAILED(nb2)) + return nb2; if (nb1==0 || nb2==0) return MK_E_NOPREFIX; commonPath=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(min(lstrlenW(pathThis),lstrlenW(pathOther))+1)); + if (!commonPath) + return E_OUTOFMEMORY; *commonPath=0; @@ -1036,7 +1048,7 @@ int FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable) TRACE("%s, %p\n", debugstr_w(str), *stringTable); - strgtable = CoTaskMemAlloc(len*sizeof(WCHAR)); + strgtable = CoTaskMemAlloc(len*sizeof(*strgtable)); if (strgtable==NULL) return E_OUTOFMEMORY; diff --git a/dlls/ole32/marshal.c b/dlls/ole32/marshal.c index 821cb87e955..54a3a87b2b6 100644 --- a/dlls/ole32/marshal.c +++ b/dlls/ole32/marshal.c @@ -1336,7 +1336,7 @@ StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, v /* unref the ifstub. FIXME: only do this on success? */ if (!stub_manager_is_table_marshaled(stubmgr, &stdobjref.ipid)) - stub_manager_ext_release(stubmgr, stdobjref.cPublicRefs, stdobjref.flags & SORFP_TABLEWEAK, TRUE); + stub_manager_ext_release(stubmgr, stdobjref.cPublicRefs, stdobjref.flags & SORFP_TABLEWEAK, FALSE); stub_manager_int_release(stubmgr); return hres; diff --git a/dlls/ole32/ole2.c b/dlls/ole32/ole2.c index c612f335e9d..6bf79fdb507 100644 --- a/dlls/ole32/ole2.c +++ b/dlls/ole32/ole2.c @@ -190,6 +190,9 @@ HRESULT WINAPI OleInitialize(LPVOID reserved) if (FAILED(hr)) return hr; + if (!COM_CurrentInfo()->ole_inits) + hr = S_OK; + /* * Then, it has to initialize the OLE specific modules. * This includes: diff --git a/dlls/ole32/oleproxy.c b/dlls/ole32/oleproxy.c index 11a3ad12d8b..184aca13437 100644 --- a/dlls/ole32/oleproxy.c +++ b/dlls/ole32/oleproxy.c @@ -46,6 +46,8 @@ */ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv) { + HRESULT hr; + *ppv = NULL; if (IsEqualIID(rclsid,&CLSID_DfMarshal)&&( IsEqualIID(iid,&IID_IClassFactory) || @@ -70,5 +72,9 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv) if (IsEqualGUID(rclsid, &CLSID_StdComponentCategoriesMgr)) return ComCatCF_Create(iid, ppv); - return OLE32_DllGetClassObject(rclsid, iid, ppv); + hr = OLE32_DllGetClassObject(rclsid, iid, ppv); + if (SUCCEEDED(hr)) + return hr; + + return Handler_DllGetClassObject(rclsid, iid, ppv); } diff --git a/dlls/ole32/stg_prop.c b/dlls/ole32/stg_prop.c index 1c77c9e2d3c..bc45cea70c9 100644 --- a/dlls/ole32/stg_prop.c +++ b/dlls/ole32/stg_prop.c @@ -1735,7 +1735,7 @@ static HRESULT PropertyStorage_WritePropertyToStream(PropertyStorage_impl *This, hr = IStream_Write(This->stm, cf_hdr, sizeof(cf_hdr), &count); if (FAILED(hr)) goto end; - hr = IStream_Write(This->stm, &var->u.pclipdata->pClipData, len, &count); + hr = IStream_Write(This->stm, var->u.pclipdata->pClipData, len, &count); if (FAILED(hr)) goto end; bytesWritten = count + sizeof cf_hdr; diff --git a/dlls/ole32/stg_stream.c b/dlls/ole32/stg_stream.c index 4cc114aa2c7..332ee8ab7b2 100644 --- a/dlls/ole32/stg_stream.c +++ b/dlls/ole32/stg_stream.c @@ -180,14 +180,14 @@ static ULONG WINAPI StgStreamImpl_Release( } /*** - * This method will open the block chain pointed by the property + * This method will open the block chain pointed by the directory entry * that describes the stream. * If the stream's size is null, no chain is opened. */ static void StgStreamImpl_OpenBlockChain( StgStreamImpl* This) { - DirEntry curProperty; + DirEntry currentEntry; BOOL readSuccessful; /* @@ -206,22 +206,22 @@ static void StgStreamImpl_OpenBlockChain( } /* - * Read the information from the property. + * Read the information from the directory entry. */ readSuccessful = StorageImpl_ReadDirEntry(This->parentStorage->ancestorStorage, - This->ownerProperty, - &curProperty); + This->dirEntry, + ¤tEntry); if (readSuccessful) { - This->streamSize = curProperty.size; + This->streamSize = currentEntry.size; /* * This code supports only streams that are <32 bits in size. */ assert(This->streamSize.u.HighPart == 0); - if(curProperty.startingBlock == BLOCK_END_OF_CHAIN) + if(currentEntry.startingBlock == BLOCK_END_OF_CHAIN) { assert( (This->streamSize.u.HighPart == 0) && (This->streamSize.u.LowPart == 0) ); } @@ -233,14 +233,14 @@ static void StgStreamImpl_OpenBlockChain( This->smallBlockChain = SmallBlockChainStream_Construct( This->parentStorage->ancestorStorage, NULL, - This->ownerProperty); + This->dirEntry); } else { This->bigBlockChain = BlockChainStream_Construct( This->parentStorage->ancestorStorage, NULL, - This->ownerProperty); + This->dirEntry); } } } @@ -545,7 +545,7 @@ static HRESULT WINAPI StgStreamImpl_SetSize( { StgStreamImpl* const This=(StgStreamImpl*)iface; - DirEntry curProperty; + DirEntry currentEntry; BOOL Success; TRACE("(%p, %d)\n", iface, libNewSize.u.LowPart); @@ -591,28 +591,28 @@ static HRESULT WINAPI StgStreamImpl_SetSize( This->smallBlockChain = SmallBlockChainStream_Construct( This->parentStorage->ancestorStorage, NULL, - This->ownerProperty); + This->dirEntry); } else { This->bigBlockChain = BlockChainStream_Construct( This->parentStorage->ancestorStorage, NULL, - This->ownerProperty); + This->dirEntry); } } /* - * Read this stream's property to see if it's small blocks or big blocks + * Read this stream's size to see if it's small blocks or big blocks */ Success = StorageImpl_ReadDirEntry(This->parentStorage->ancestorStorage, - This->ownerProperty, - &curProperty); + This->dirEntry, + ¤tEntry); /* * Determine if we have to switch from small to big blocks or vice versa */ if ( (This->smallBlockChain!=0) && - (curProperty.size.u.LowPart < LIMIT_TO_USE_SMALL_BLOCK) ) + (currentEntry.size.u.LowPart < LIMIT_TO_USE_SMALL_BLOCK) ) { if (libNewSize.u.LowPart >= LIMIT_TO_USE_SMALL_BLOCK) { @@ -625,7 +625,7 @@ static HRESULT WINAPI StgStreamImpl_SetSize( } } else if ( (This->bigBlockChain!=0) && - (curProperty.size.u.LowPart >= LIMIT_TO_USE_SMALL_BLOCK) ) + (currentEntry.size.u.LowPart >= LIMIT_TO_USE_SMALL_BLOCK) ) { if (libNewSize.u.LowPart < LIMIT_TO_USE_SMALL_BLOCK) { @@ -648,20 +648,20 @@ static HRESULT WINAPI StgStreamImpl_SetSize( } /* - * Write the new information about this stream to the property + * Write the new information about this stream to the directory entry */ Success = StorageImpl_ReadDirEntry(This->parentStorage->ancestorStorage, - This->ownerProperty, - &curProperty); + This->dirEntry, + ¤tEntry); - curProperty.size.u.HighPart = libNewSize.u.HighPart; - curProperty.size.u.LowPart = libNewSize.u.LowPart; + currentEntry.size.u.HighPart = libNewSize.u.HighPart; + currentEntry.size.u.LowPart = libNewSize.u.LowPart; if (Success) { StorageImpl_WriteDirEntry(This->parentStorage->ancestorStorage, - This->ownerProperty, - &curProperty); + This->dirEntry, + ¤tEntry); } This->streamSize = libNewSize; @@ -834,7 +834,7 @@ static HRESULT WINAPI StgStreamImpl_Stat( { StgStreamImpl* const This=(StgStreamImpl*)iface; - DirEntry curProperty; + DirEntry currentEntry; BOOL readSuccessful; TRACE("%p %p %d\n", This, pstatstg, grfStatFlag); @@ -850,18 +850,19 @@ static HRESULT WINAPI StgStreamImpl_Stat( } /* - * Read the information from the property. + * Read the information from the directory entry. */ readSuccessful = StorageImpl_ReadDirEntry(This->parentStorage->ancestorStorage, - This->ownerProperty, - &curProperty); + This->dirEntry, + ¤tEntry); if (readSuccessful) { StorageImpl *root = This->parentStorage->ancestorStorage; - StorageUtl_CopyDirEntryToSTATSTG(pstatstg, - &curProperty, + StorageUtl_CopyDirEntryToSTATSTG(root, + pstatstg, + ¤tEntry, grfStatFlag); pstatstg->grfMode = This->grfMode; @@ -873,7 +874,7 @@ static HRESULT WINAPI StgStreamImpl_Stat( return S_OK; } - WARN("failed to read properties\n"); + WARN("failed to read entry\n"); return E_FAIL; } @@ -910,7 +911,7 @@ static HRESULT WINAPI StgStreamImpl_Clone( if ( ppstm == 0 ) return STG_E_INVALIDPOINTER; - new_stream = StgStreamImpl_Construct (This->parentStorage, This->grfMode, This->ownerProperty); + new_stream = StgStreamImpl_Construct (This->parentStorage, This->grfMode, This->dirEntry); if (!new_stream) return STG_E_INSUFFICIENTMEMORY; /* Currently the only reason for new_stream=0 */ @@ -957,12 +958,12 @@ static const IStreamVtbl StgStreamImpl_Vtbl = * * Params: * parentStorage - Pointer to the storage that contains the stream to open - * ownerProperty - Index of the property that points to this stream. + * dirEntry - Index of the directory entry that points to this stream. */ StgStreamImpl* StgStreamImpl_Construct( StorageBaseImpl* parentStorage, DWORD grfMode, - ULONG ownerProperty) + DirRef dirEntry) { StgStreamImpl* newStream; @@ -991,7 +992,7 @@ StgStreamImpl* StgStreamImpl_Construct( */ newStream->grfMode = grfMode; - newStream->ownerProperty = ownerProperty; + newStream->dirEntry = dirEntry; /* * Start the stream at the beginning. @@ -1008,7 +1009,7 @@ StgStreamImpl* StgStreamImpl_Construct( newStream->smallBlockChain = 0; /* - * Read the size from the property and determine if the blocks forming + * Read the size from the directory entry and determine if the blocks forming * this stream are large or small. */ StgStreamImpl_OpenBlockChain(newStream); diff --git a/dlls/ole32/storage32.c b/dlls/ole32/storage32.c index 898695ce9c2..089206dc830 100644 --- a/dlls/ole32/storage32.c +++ b/dlls/ole32/storage32.c @@ -65,7 +65,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(storage); static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1}; static const BYTE STORAGE_oldmagic[8] ={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d}; -static const char rootPropertyName[] = "Root Entry"; +static const char rootEntryName[] = "Root Entry"; /**************************************************************************** * Storage32InternalImpl definitions. @@ -77,15 +77,17 @@ static const char rootPropertyName[] = "Root Entry"; struct StorageInternalImpl { struct StorageBaseImpl base; + /* - * There is no specific data for this class. + * Entry in the parent's stream tracking list */ + struct list ParentListEntry; }; typedef struct StorageInternalImpl StorageInternalImpl; /* Method definitions for the Storage32InternalImpl class. */ static StorageInternalImpl* StorageInternalImpl_Construct(StorageImpl* ancestorStorage, - DWORD openFlags, ULONG rootTropertyIndex); + DWORD openFlags, DirRef storageDirEntry); static void StorageImpl_Destroy(StorageBaseImpl* iface); static BOOL StorageImpl_ReadBigBlock(StorageImpl* This, ULONG blockIndex, void* buffer); static BOOL StorageImpl_WriteBigBlock(StorageImpl* This, ULONG blockIndex, const void* buffer); @@ -110,6 +112,10 @@ static BOOL StorageImpl_WriteDWordToBigBlock( StorageImpl* This, static BOOL StorageImpl_ReadDWordFromBigBlock( StorageImpl* This, ULONG blockIndex, ULONG offset, DWORD* value); +static BOOL StorageBaseImpl_IsStreamOpen(StorageBaseImpl * stg, DirRef streamEntry); +static BOOL StorageBaseImpl_IsStorageOpen(StorageBaseImpl * stg, DirRef storageEntry); +static void StorageInternalImpl_Invalidate( StorageInternalImpl *This ); + /* OLESTREAM memory structure to use for Get and Put Routines */ /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */ typedef struct @@ -159,20 +165,20 @@ typedef struct /*********************************************************************** * Forward declaration of internal functions used by the method DestroyElement */ -static HRESULT deleteStorageProperty( +static HRESULT deleteStorageContents( StorageBaseImpl *parentStorage, - ULONG foundPropertyIndexToDelete, - DirEntry propertyToDelete); + DirRef indexToDelete, + DirEntry entryDataToDelete); -static HRESULT deleteStreamProperty( +static HRESULT deleteStreamContents( StorageBaseImpl *parentStorage, - ULONG foundPropertyIndexToDelete, - DirEntry propertyToDelete); + DirRef indexToDelete, + DirEntry entryDataToDelete); static HRESULT removeFromTree( StorageImpl *This, - ULONG parentStorageIndex, - ULONG deletedIndex); + DirRef parentStorageIndex, + DirRef deletedIndex); /*********************************************************************** * Declaration of the functions used to manipulate DirEntry @@ -181,33 +187,33 @@ static HRESULT removeFromTree( static HRESULT createDirEntry( StorageImpl *storage, const DirEntry *newData, - ULONG *index); + DirRef *index); static HRESULT destroyDirEntry( StorageImpl *storage, - ULONG index); + DirRef index); static HRESULT insertIntoTree( StorageImpl *This, - ULONG parentStorageIndex, - ULONG newPropertyIndex); + DirRef parentStorageIndex, + DirRef newEntryIndex); -static LONG propertyNameCmp( - const OLECHAR *newProperty, - const OLECHAR *currentProperty); +static LONG entryNameCmp( + const OLECHAR *name1, + const OLECHAR *name2); -static ULONG findElement( +static DirRef findElement( StorageImpl *storage, - ULONG storageEntry, + DirRef storageEntry, const OLECHAR *name, DirEntry *data); static HRESULT findTreeParent( StorageImpl *storage, - ULONG storageEntry, + DirRef storageEntry, const OLECHAR *childName, DirEntry *parentData, - ULONG *parentEntry, + DirRef *parentEntry, ULONG *relation); /*********************************************************************** @@ -236,25 +242,25 @@ struct IEnumSTATSTGImpl LONG ref; /* Reference count */ StorageImpl* parentStorage; /* Reference to the parent storage */ - ULONG firstPropertyNode; /* Index of the root of the storage to enumerate */ + DirRef storageDirEntry; /* Directory entry of the storage to enumerate */ /* * The current implementation of the IEnumSTATSTGImpl class uses a stack - * to walk the property sets to get the content of a storage. This stack + * to walk the directory entries to get the content of a storage. This stack * is implemented by the following 3 data members */ ULONG stackSize; ULONG stackMaxSize; - ULONG* stackToVisit; + DirRef* stackToVisit; #define ENUMSTATSGT_SIZE_INCREMENT 10 }; -static IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(StorageImpl* This, ULONG firstPropertyNode); +static IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(StorageImpl* This, DirRef storageDirEntry); static void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This); -static void IEnumSTATSTGImpl_PushSearchNode(IEnumSTATSTGImpl* This, ULONG nodeToPush); -static ULONG IEnumSTATSTGImpl_PopSearchNode(IEnumSTATSTGImpl* This, BOOL remove); +static void IEnumSTATSTGImpl_PushSearchNode(IEnumSTATSTGImpl* This, DirRef nodeToPush); +static DirRef IEnumSTATSTGImpl_PopSearchNode(IEnumSTATSTGImpl* This, BOOL remove); /************************************************************************ ** Block Functions @@ -395,8 +401,8 @@ static HRESULT WINAPI StorageBaseImpl_OpenStream( { StorageBaseImpl *This = (StorageBaseImpl *)iface; StgStreamImpl* newStream; - DirEntry currentProperty; - ULONG foundPropertyIndex; + DirEntry currentEntry; + DirRef streamEntryRef; HRESULT res = STG_E_UNKNOWN; TRACE("(%p, %s, %p, %x, %d, %p)\n", @@ -426,6 +432,12 @@ static HRESULT WINAPI StorageBaseImpl_OpenStream( goto end; } + if (!This->ancestorStorage) + { + res = STG_E_REVERTED; + goto end; + } + /* * Check that we're compatible with the parent's storage mode, but * only if we are not in transacted mode @@ -441,19 +453,26 @@ static HRESULT WINAPI StorageBaseImpl_OpenStream( /* * Search for the element with the given name */ - foundPropertyIndex = findElement( + streamEntryRef = findElement( This->ancestorStorage, - This->rootPropertySetIndex, + This->storageDirEntry, pwcsName, - ¤tProperty); + ¤tEntry); /* * If it was found, construct the stream object and return a pointer to it. */ - if ( (foundPropertyIndex!=DIRENTRY_NULL) && - (currentProperty.propertyType==STGTY_STREAM) ) + if ( (streamEntryRef!=DIRENTRY_NULL) && + (currentEntry.stgType==STGTY_STREAM) ) { - newStream = StgStreamImpl_Construct(This, grfMode, foundPropertyIndex); + if (StorageBaseImpl_IsStreamOpen(This, streamEntryRef)) + { + /* A single stream cannot be opened a second time. */ + res = STG_E_ACCESSDENIED; + goto end; + } + + newStream = StgStreamImpl_Construct(This, grfMode, streamEntryRef); if (newStream!=0) { @@ -497,8 +516,8 @@ static HRESULT WINAPI StorageBaseImpl_OpenStorage( { StorageBaseImpl *This = (StorageBaseImpl *)iface; StorageInternalImpl* newStorage; - DirEntry currentProperty; - ULONG foundPropertyIndex; + DirEntry currentEntry; + DirRef storageEntryRef; HRESULT res = STG_E_UNKNOWN; TRACE("(%p, %s, %p, %x, %p, %d, %p)\n", @@ -535,6 +554,9 @@ static HRESULT WINAPI StorageBaseImpl_OpenStorage( goto end; } + if (!This->ancestorStorage) + return STG_E_REVERTED; + /* * Check that we're compatible with the parent's storage mode, * but only if we are not transacted @@ -549,19 +571,26 @@ static HRESULT WINAPI StorageBaseImpl_OpenStorage( *ppstg = NULL; - foundPropertyIndex = findElement( + storageEntryRef = findElement( This->ancestorStorage, - This->rootPropertySetIndex, + This->storageDirEntry, pwcsName, - ¤tProperty); + ¤tEntry); - if ( (foundPropertyIndex!=DIRENTRY_NULL) && - (currentProperty.propertyType==STGTY_STORAGE) ) + if ( (storageEntryRef!=DIRENTRY_NULL) && + (currentEntry.stgType==STGTY_STORAGE) ) { + if (StorageBaseImpl_IsStorageOpen(This, storageEntryRef)) + { + /* A single storage cannot be opened a second time. */ + res = STG_E_ACCESSDENIED; + goto end; + } + newStorage = StorageInternalImpl_Construct( This->ancestorStorage, grfMode, - foundPropertyIndex); + storageEntryRef); if (newStorage != 0) { @@ -569,6 +598,8 @@ static HRESULT WINAPI StorageBaseImpl_OpenStorage( StorageBaseImpl_AddRef(*ppstg); + list_add_tail(&This->storageHead, &newStorage->ParentListEntry); + res = S_OK; goto end; } @@ -588,7 +619,7 @@ end: * Storage32BaseImpl_EnumElements (IStorage) * * This method will create an enumerator object that can be used to - * retrieve information about all the properties in the storage object. + * retrieve information about all the elements in the storage object. * * See Windows documentation for more details on IStorage methods. */ @@ -608,9 +639,12 @@ static HRESULT WINAPI StorageBaseImpl_EnumElements( if ( (This==0) || (ppenum==0)) return E_INVALIDARG; + if (!This->ancestorStorage) + return STG_E_REVERTED; + newEnum = IEnumSTATSTGImpl_Construct( This->ancestorStorage, - This->rootPropertySetIndex); + This->storageDirEntry); if (newEnum!=0) { @@ -637,7 +671,7 @@ static HRESULT WINAPI StorageBaseImpl_Stat( DWORD grfStatFlag) /* [in] */ { StorageBaseImpl *This = (StorageBaseImpl *)iface; - DirEntry curProperty; + DirEntry currentEntry; BOOL readSuccessful; HRESULT res = STG_E_UNKNOWN; @@ -650,16 +684,23 @@ static HRESULT WINAPI StorageBaseImpl_Stat( goto end; } + if (!This->ancestorStorage) + { + res = STG_E_REVERTED; + goto end; + } + readSuccessful = StorageImpl_ReadDirEntry( This->ancestorStorage, - This->rootPropertySetIndex, - &curProperty); + This->storageDirEntry, + ¤tEntry); if (readSuccessful) { StorageUtl_CopyDirEntryToSTATSTG( + This->ancestorStorage, pstatstg, - &curProperty, + ¤tEntry, grfStatFlag); pstatstg->grfMode = This->openFlags; @@ -693,21 +734,24 @@ static HRESULT WINAPI StorageBaseImpl_RenameElement( const OLECHAR* pwcsNewName) /* [in] */ { StorageBaseImpl *This = (StorageBaseImpl *)iface; - DirEntry currentProperty; - ULONG foundPropertyIndex; + DirEntry currentEntry; + DirRef currentEntryRef; TRACE("(%p, %s, %s)\n", iface, debugstr_w(pwcsOldName), debugstr_w(pwcsNewName)); - foundPropertyIndex = findElement(This->ancestorStorage, - This->rootPropertySetIndex, + if (!This->ancestorStorage) + return STG_E_REVERTED; + + currentEntryRef = findElement(This->ancestorStorage, + This->storageDirEntry, pwcsNewName, - ¤tProperty); + ¤tEntry); - if (foundPropertyIndex != DIRENTRY_NULL) + if (currentEntryRef != DIRENTRY_NULL) { /* - * There is already a property with the new name + * There is already an element with the new name */ return STG_E_FILEALREADYEXISTS; } @@ -715,31 +759,38 @@ static HRESULT WINAPI StorageBaseImpl_RenameElement( /* * Search for the old element name */ - foundPropertyIndex = findElement(This->ancestorStorage, - This->rootPropertySetIndex, + currentEntryRef = findElement(This->ancestorStorage, + This->storageDirEntry, pwcsOldName, - ¤tProperty); + ¤tEntry); - if (foundPropertyIndex != DIRENTRY_NULL) + if (currentEntryRef != DIRENTRY_NULL) { + if (StorageBaseImpl_IsStreamOpen(This, currentEntryRef) || + StorageBaseImpl_IsStorageOpen(This, currentEntryRef)) + { + WARN("Element is already open; cannot rename.\n"); + return STG_E_ACCESSDENIED; + } + /* Remove the element from its current position in the tree */ - removeFromTree(This->ancestorStorage, This->rootPropertySetIndex, - foundPropertyIndex); + removeFromTree(This->ancestorStorage, This->storageDirEntry, + currentEntryRef); /* Change the name of the element */ - strcpyW(currentProperty.name, pwcsNewName); + strcpyW(currentEntry.name, pwcsNewName); - StorageImpl_WriteDirEntry(This->ancestorStorage, foundPropertyIndex, - ¤tProperty); + StorageImpl_WriteDirEntry(This->ancestorStorage, currentEntryRef, + ¤tEntry); /* Insert the element in a new position in the tree */ - insertIntoTree(This->ancestorStorage, This->rootPropertySetIndex, - foundPropertyIndex); + insertIntoTree(This->ancestorStorage, This->storageDirEntry, + currentEntryRef); } else { /* - * There is no property with the old name + * There is no element with the old name */ return STG_E_FILENOTFOUND; } @@ -764,8 +815,8 @@ static HRESULT WINAPI StorageBaseImpl_CreateStream( { StorageBaseImpl *This = (StorageBaseImpl *)iface; StgStreamImpl* newStream; - DirEntry currentProperty, newStreamProperty; - ULONG foundPropertyIndex, newPropertyIndex; + DirEntry currentEntry, newStreamEntry; + DirRef currentEntryRef, newStreamEntryRef; TRACE("(%p, %s, %x, %d, %d, %p)\n", iface, debugstr_w(pwcsName), grfMode, @@ -786,6 +837,9 @@ static HRESULT WINAPI StorageBaseImpl_CreateStream( if (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE) return STG_E_INVALIDFLAG; + if (!This->ancestorStorage) + return STG_E_REVERTED; + /* * As documented. */ @@ -811,29 +865,18 @@ static HRESULT WINAPI StorageBaseImpl_CreateStream( *ppstm = 0; - foundPropertyIndex = findElement(This->ancestorStorage, - This->rootPropertySetIndex, + currentEntryRef = findElement(This->ancestorStorage, + This->storageDirEntry, pwcsName, - ¤tProperty); + ¤tEntry); - if (foundPropertyIndex != DIRENTRY_NULL) + if (currentEntryRef != DIRENTRY_NULL) { /* * An element with this name already exists */ if (STGM_CREATE_MODE(grfMode) == STGM_CREATE) { - StgStreamImpl *strm; - - LIST_FOR_EACH_ENTRY(strm, &This->strmHead, StgStreamImpl, StrmListEntry) - { - if (strm->ownerProperty == foundPropertyIndex) - { - TRACE("Stream deleted %p\n", strm); - strm->parentStorage = NULL; - list_remove(&strm->StrmListEntry); - } - } IStorage_DestroyElement(iface, pwcsName); } else @@ -846,51 +889,51 @@ static HRESULT WINAPI StorageBaseImpl_CreateStream( } /* - * memset the empty property + * memset the empty entry */ - memset(&newStreamProperty, 0, sizeof(DirEntry)); + memset(&newStreamEntry, 0, sizeof(DirEntry)); - newStreamProperty.sizeOfNameString = + newStreamEntry.sizeOfNameString = ( lstrlenW(pwcsName)+1 ) * sizeof(WCHAR); - if (newStreamProperty.sizeOfNameString > DIRENTRY_NAME_BUFFER_LEN) + if (newStreamEntry.sizeOfNameString > DIRENTRY_NAME_BUFFER_LEN) return STG_E_INVALIDNAME; - strcpyW(newStreamProperty.name, pwcsName); + strcpyW(newStreamEntry.name, pwcsName); - newStreamProperty.propertyType = STGTY_STREAM; - newStreamProperty.startingBlock = BLOCK_END_OF_CHAIN; - newStreamProperty.size.u.LowPart = 0; - newStreamProperty.size.u.HighPart = 0; + newStreamEntry.stgType = STGTY_STREAM; + newStreamEntry.startingBlock = BLOCK_END_OF_CHAIN; + newStreamEntry.size.u.LowPart = 0; + newStreamEntry.size.u.HighPart = 0; - newStreamProperty.leftChild = DIRENTRY_NULL; - newStreamProperty.rightChild = DIRENTRY_NULL; - newStreamProperty.dirRootEntry = DIRENTRY_NULL; + newStreamEntry.leftChild = DIRENTRY_NULL; + newStreamEntry.rightChild = DIRENTRY_NULL; + newStreamEntry.dirRootEntry = DIRENTRY_NULL; /* call CoFileTime to get the current time - newStreamProperty.ctime - newStreamProperty.mtime + newStreamEntry.ctime + newStreamEntry.mtime */ - /* newStreamProperty.propertyUniqueID */ + /* newStreamEntry.clsid */ /* - * Save the new property into a new property spot + * Create an entry with the new data */ - createDirEntry(This->ancestorStorage, &newStreamProperty, &newPropertyIndex); + createDirEntry(This->ancestorStorage, &newStreamEntry, &newStreamEntryRef); /* - * Find a spot in the property chain for our newly created property. + * Insert the new entry in the parent storage's tree. */ insertIntoTree( This->ancestorStorage, - This->rootPropertySetIndex, - newPropertyIndex); + This->storageDirEntry, + newStreamEntryRef); /* * Open the stream to return it. */ - newStream = StgStreamImpl_Construct(This, grfMode, newPropertyIndex); + newStream = StgStreamImpl_Construct(This, grfMode, newStreamEntryRef); if (newStream != 0) { @@ -909,7 +952,7 @@ static HRESULT WINAPI StorageBaseImpl_CreateStream( /************************************************************************ * Storage32BaseImpl_SetClass (IStorage) * - * This method will write the specified CLSID in the property of this + * This method will write the specified CLSID in the directory entry of this * storage. * * See Windows documentation for more details on IStorage methods. @@ -920,21 +963,24 @@ static HRESULT WINAPI StorageBaseImpl_SetClass( { StorageBaseImpl *This = (StorageBaseImpl *)iface; HRESULT hRes = E_FAIL; - DirEntry curProperty; + DirEntry currentEntry; BOOL success; TRACE("(%p, %p)\n", iface, clsid); + if (!This->ancestorStorage) + return STG_E_REVERTED; + success = StorageImpl_ReadDirEntry(This->ancestorStorage, - This->rootPropertySetIndex, - &curProperty); + This->storageDirEntry, + ¤tEntry); if (success) { - curProperty.propertyUniqueID = *clsid; + currentEntry.clsid = *clsid; success = StorageImpl_WriteDirEntry(This->ancestorStorage, - This->rootPropertySetIndex, - &curProperty); + This->storageDirEntry, + ¤tEntry); if (success) hRes = S_OK; } @@ -963,10 +1009,10 @@ static HRESULT WINAPI StorageBaseImpl_CreateStorage( { StorageBaseImpl* const This=(StorageBaseImpl*)iface; - DirEntry currentProperty; - DirEntry newProperty; - ULONG foundPropertyIndex; - ULONG newPropertyIndex; + DirEntry currentEntry; + DirEntry newEntry; + DirRef currentEntryRef; + DirRef newEntryRef; HRESULT hr; TRACE("(%p, %s, %x, %d, %d, %p)\n", @@ -988,6 +1034,9 @@ static HRESULT WINAPI StorageBaseImpl_CreateStorage( return STG_E_INVALIDFLAG; } + if (!This->ancestorStorage) + return STG_E_REVERTED; + /* * Check that we're compatible with the parent's storage mode */ @@ -997,12 +1046,12 @@ static HRESULT WINAPI StorageBaseImpl_CreateStorage( return STG_E_ACCESSDENIED; } - foundPropertyIndex = findElement(This->ancestorStorage, - This->rootPropertySetIndex, + currentEntryRef = findElement(This->ancestorStorage, + This->storageDirEntry, pwcsName, - ¤tProperty); + ¤tEntry); - if (foundPropertyIndex != DIRENTRY_NULL) + if (currentEntryRef != DIRENTRY_NULL) { /* * An element with this name already exists @@ -1026,49 +1075,46 @@ static HRESULT WINAPI StorageBaseImpl_CreateStorage( return STG_E_ACCESSDENIED; } - /* - * memset the empty property - */ - memset(&newProperty, 0, sizeof(DirEntry)); + memset(&newEntry, 0, sizeof(DirEntry)); - newProperty.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR); + newEntry.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR); - if (newProperty.sizeOfNameString > DIRENTRY_NAME_BUFFER_LEN) + if (newEntry.sizeOfNameString > DIRENTRY_NAME_BUFFER_LEN) { FIXME("name too long\n"); return STG_E_INVALIDNAME; } - strcpyW(newProperty.name, pwcsName); + strcpyW(newEntry.name, pwcsName); - newProperty.propertyType = STGTY_STORAGE; - newProperty.startingBlock = BLOCK_END_OF_CHAIN; - newProperty.size.u.LowPart = 0; - newProperty.size.u.HighPart = 0; + newEntry.stgType = STGTY_STORAGE; + newEntry.startingBlock = BLOCK_END_OF_CHAIN; + newEntry.size.u.LowPart = 0; + newEntry.size.u.HighPart = 0; - newProperty.leftChild = DIRENTRY_NULL; - newProperty.rightChild = DIRENTRY_NULL; - newProperty.dirRootEntry = DIRENTRY_NULL; + newEntry.leftChild = DIRENTRY_NULL; + newEntry.rightChild = DIRENTRY_NULL; + newEntry.dirRootEntry = DIRENTRY_NULL; /* call CoFileTime to get the current time - newProperty.ctime - newProperty.mtime + newEntry.ctime + newEntry.mtime */ - /* newStorageProperty.propertyUniqueID */ + /* newEntry.clsid */ /* - * Save the new property into a new property spot + * Create a new directory entry for the storage */ - createDirEntry(This->ancestorStorage, &newProperty, &newPropertyIndex); + createDirEntry(This->ancestorStorage, &newEntry, &newEntryRef); /* - * Find a spot in the property chain for our newly created property. + * Insert the new directory entry into the parent storage's tree */ insertIntoTree( This->ancestorStorage, - This->rootPropertySetIndex, - newPropertyIndex); + This->storageDirEntry, + newEntryRef); /* * Open it to get a pointer to return. @@ -1094,10 +1140,10 @@ static HRESULT WINAPI StorageBaseImpl_CreateStorage( static HRESULT createDirEntry( StorageImpl *storage, const DirEntry *newData, - ULONG *index) + DirRef *index) { - ULONG currentPropertyIndex = 0; - ULONG newPropertyIndex = DIRENTRY_NULL; + ULONG currentEntryIndex = 0; + ULONG newEntryIndex = DIRENTRY_NULL; HRESULT hr = S_OK; BYTE currentData[RAW_DIRENTRY_SIZE]; WORD sizeOfNameString; @@ -1105,7 +1151,7 @@ static HRESULT createDirEntry( do { hr = StorageImpl_ReadRawDirEntry(storage, - currentPropertyIndex, + currentEntryIndex, currentData); if (SUCCEEDED(hr)) @@ -1118,79 +1164,79 @@ static HRESULT createDirEntry( if (sizeOfNameString == 0) { /* - * The property existis and is available, we found it. + * The entry exists and is available, we found it. */ - newPropertyIndex = currentPropertyIndex; + newEntryIndex = currentEntryIndex; } } else { /* - * We exhausted the property list, we will create more space below + * We exhausted the directory entries, we will create more space below */ - newPropertyIndex = currentPropertyIndex; + newEntryIndex = currentEntryIndex; } - currentPropertyIndex++; + currentEntryIndex++; - } while (newPropertyIndex == DIRENTRY_NULL); + } while (newEntryIndex == DIRENTRY_NULL); /* - * grow the property chain + * grow the directory stream */ if (FAILED(hr)) { BYTE emptyData[RAW_DIRENTRY_SIZE]; ULARGE_INTEGER newSize; - ULONG propertyIndex; - ULONG lastProperty = 0; + ULONG entryIndex; + ULONG lastEntry = 0; ULONG blockCount = 0; /* - * obtain the new count of property blocks + * obtain the new count of blocks in the directory stream */ blockCount = BlockChainStream_GetCount( storage->rootBlockChain)+1; /* - * initialize the size used by the property stream + * initialize the size used by the directory stream */ newSize.u.HighPart = 0; newSize.u.LowPart = storage->bigBlockSize * blockCount; /* - * add a property block to the property chain + * add a block to the directory stream */ BlockChainStream_SetSize(storage->rootBlockChain, newSize); /* - * memset the empty property in order to initialize the unused newly - * created property + * memset the empty entry in order to initialize the unused newly + * created entries */ memset(&emptyData, 0, RAW_DIRENTRY_SIZE); /* * initialize them */ - lastProperty = storage->bigBlockSize / RAW_DIRENTRY_SIZE * blockCount; + lastEntry = storage->bigBlockSize / RAW_DIRENTRY_SIZE * blockCount; for( - propertyIndex = newPropertyIndex + 1; - propertyIndex < lastProperty; - propertyIndex++) + entryIndex = newEntryIndex + 1; + entryIndex < lastEntry; + entryIndex++) { StorageImpl_WriteRawDirEntry( storage, - propertyIndex, + entryIndex, emptyData); } } UpdateRawDirEntry(currentData, newData); - hr = StorageImpl_WriteRawDirEntry(storage, newPropertyIndex, currentData); + hr = StorageImpl_WriteRawDirEntry(storage, newEntryIndex, currentData); if (SUCCEEDED(hr)) - *index = newPropertyIndex; + *index = newEntryIndex; return hr; } @@ -1203,7 +1249,7 @@ static HRESULT createDirEntry( */ static HRESULT destroyDirEntry( StorageImpl *storage, - ULONG index) + DirRef index) { HRESULT hr; BYTE emptyData[RAW_DIRENTRY_SIZE]; @@ -1223,22 +1269,22 @@ static HRESULT destroyDirEntry( * Case insensitive comparison of DirEntry.name by first considering * their size. * - * Returns <0 when newProperty < currentProperty - * >0 when newProperty > currentProperty - * 0 when newProperty == currentProperty + * Returns <0 when name1 < name2 + * >0 when name1 > name2 + * 0 when name1 == name2 */ -static LONG propertyNameCmp( - const OLECHAR *newProperty, - const OLECHAR *currentProperty) +static LONG entryNameCmp( + const OLECHAR *name1, + const OLECHAR *name2) { - LONG diff = lstrlenW(newProperty) - lstrlenW(currentProperty); + LONG diff = lstrlenW(name1) - lstrlenW(name2); if (diff == 0) { /* * We compare the string themselves only when they are of the same length */ - diff = lstrcmpiW( newProperty, currentProperty); + diff = lstrcmpiW( name1, name2); } return diff; @@ -1248,58 +1294,58 @@ static LONG propertyNameCmp( * * Internal Method * - * Properly link this new element in the property chain. + * Add a directory entry to a storage */ static HRESULT insertIntoTree( StorageImpl *This, - ULONG parentStorageIndex, - ULONG newPropertyIndex) + DirRef parentStorageIndex, + DirRef newEntryIndex) { - DirEntry currentProperty; - DirEntry newProperty; + DirEntry currentEntry; + DirEntry newEntry; /* - * Read the inserted property + * Read the inserted entry */ StorageImpl_ReadDirEntry(This, - newPropertyIndex, - &newProperty); + newEntryIndex, + &newEntry); /* - * Read the root property + * Read the storage entry */ StorageImpl_ReadDirEntry(This, parentStorageIndex, - ¤tProperty); + ¤tEntry); - if (currentProperty.dirRootEntry != DIRENTRY_NULL) + if (currentEntry.dirRootEntry != DIRENTRY_NULL) { /* * The root storage contains some element, therefore, start the research * for the appropriate location. */ BOOL found = 0; - ULONG current, next, previous, currentPropertyId; + DirRef current, next, previous, currentEntryId; /* - * Keep the DirEntry sequence number of the storage first property + * Keep a reference to the root of the storage's element tree */ - currentPropertyId = currentProperty.dirRootEntry; + currentEntryId = currentEntry.dirRootEntry; /* * Read */ StorageImpl_ReadDirEntry(This, - currentProperty.dirRootEntry, - ¤tProperty); + currentEntry.dirRootEntry, + ¤tEntry); - previous = currentProperty.leftChild; - next = currentProperty.rightChild; - current = currentPropertyId; + previous = currentEntry.leftChild; + next = currentEntry.rightChild; + current = currentEntryId; while (found == 0) { - LONG diff = propertyNameCmp( newProperty.name, currentProperty.name); + LONG diff = entryNameCmp( newEntry.name, currentEntry.name); if (diff < 0) { @@ -1307,15 +1353,15 @@ static HRESULT insertIntoTree( { StorageImpl_ReadDirEntry(This, previous, - ¤tProperty); + ¤tEntry); current = previous; } else { - currentProperty.leftChild = newPropertyIndex; + currentEntry.leftChild = newEntryIndex; StorageImpl_WriteDirEntry(This, current, - ¤tProperty); + ¤tEntry); found = 1; } } @@ -1325,15 +1371,15 @@ static HRESULT insertIntoTree( { StorageImpl_ReadDirEntry(This, next, - ¤tProperty); + ¤tEntry); current = next; } else { - currentProperty.rightChild = newPropertyIndex; + currentEntry.rightChild = newEntryIndex; StorageImpl_WriteDirEntry(This, current, - ¤tProperty); + ¤tEntry); found = 1; } } @@ -1346,19 +1392,19 @@ static HRESULT insertIntoTree( return STG_E_FILEALREADYEXISTS; } - previous = currentProperty.leftChild; - next = currentProperty.rightChild; + previous = currentEntry.leftChild; + next = currentEntry.rightChild; } } else { /* - * The root storage is empty, link the new property to its dir property + * The storage is empty, make the new entry the root of its element tree */ - currentProperty.dirRootEntry = newPropertyIndex; + currentEntry.dirRootEntry = newEntryIndex; StorageImpl_WriteDirEntry(This, parentStorageIndex, - ¤tProperty); + ¤tEntry); } return S_OK; @@ -1370,10 +1416,10 @@ static HRESULT insertIntoTree( * * Find and read the element of a storage with the given name. */ -static ULONG findElement(StorageImpl *storage, ULONG storageEntry, +static DirRef findElement(StorageImpl *storage, DirRef storageEntry, const OLECHAR *name, DirEntry *data) { - ULONG currentEntry; + DirRef currentEntry; /* Read the storage entry to find the root of the tree. */ StorageImpl_ReadDirEntry(storage, storageEntry, data); @@ -1386,7 +1432,7 @@ static ULONG findElement(StorageImpl *storage, ULONG storageEntry, StorageImpl_ReadDirEntry(storage, currentEntry, data); - cmp = propertyNameCmp(name, data->name); + cmp = entryNameCmp(name, data->name); if (cmp == 0) /* found it */ @@ -1411,11 +1457,11 @@ static ULONG findElement(StorageImpl *storage, ULONG storageEntry, * If there is no such element, find a place where it could be inserted and * return STG_E_FILENOTFOUND. */ -static HRESULT findTreeParent(StorageImpl *storage, ULONG storageEntry, - const OLECHAR *childName, DirEntry *parentData, ULONG *parentEntry, +static HRESULT findTreeParent(StorageImpl *storage, DirRef storageEntry, + const OLECHAR *childName, DirEntry *parentData, DirRef *parentEntry, ULONG *relation) { - ULONG childEntry; + DirRef childEntry; DirEntry childData; /* Read the storage entry to find the root of the tree. */ @@ -1432,7 +1478,7 @@ static HRESULT findTreeParent(StorageImpl *storage, ULONG storageEntry, StorageImpl_ReadDirEntry(storage, childEntry, &childData); - cmp = propertyNameCmp(childName, childData.name); + cmp = entryNameCmp(childName, childData.name); if (cmp == 0) /* found it */ @@ -1721,8 +1767,8 @@ static HRESULT WINAPI StorageBaseImpl_DestroyElement( StorageBaseImpl* const This=(StorageBaseImpl*)iface; HRESULT hr = S_OK; - DirEntry propertyToDelete; - ULONG foundPropertyIndexToDelete; + DirEntry entryToDelete; + DirRef entryToDeleteRef; TRACE("(%p, %s)\n", iface, debugstr_w(pwcsName)); @@ -1730,52 +1776,55 @@ static HRESULT WINAPI StorageBaseImpl_DestroyElement( if (pwcsName==NULL) return STG_E_INVALIDPOINTER; + if (!This->ancestorStorage) + return STG_E_REVERTED; + if ( STGM_ACCESS_MODE( This->openFlags ) == STGM_READ ) return STG_E_ACCESSDENIED; - foundPropertyIndexToDelete = findElement( + entryToDeleteRef = findElement( This->ancestorStorage, - This->rootPropertySetIndex, + This->storageDirEntry, pwcsName, - &propertyToDelete); + &entryToDelete); - if ( foundPropertyIndexToDelete == DIRENTRY_NULL ) + if ( entryToDeleteRef == DIRENTRY_NULL ) { return STG_E_FILENOTFOUND; } - if ( propertyToDelete.propertyType == STGTY_STORAGE ) + if ( entryToDelete.stgType == STGTY_STORAGE ) { - hr = deleteStorageProperty( + hr = deleteStorageContents( This, - foundPropertyIndexToDelete, - propertyToDelete); + entryToDeleteRef, + entryToDelete); } - else if ( propertyToDelete.propertyType == STGTY_STREAM ) + else if ( entryToDelete.stgType == STGTY_STREAM ) { - hr = deleteStreamProperty( + hr = deleteStreamContents( This, - foundPropertyIndexToDelete, - propertyToDelete); + entryToDeleteRef, + entryToDelete); } if (hr!=S_OK) return hr; /* - * Adjust the property chain + * Remove the entry from its parent storage */ hr = removeFromTree( This->ancestorStorage, - This->rootPropertySetIndex, - foundPropertyIndexToDelete); + This->storageDirEntry, + entryToDeleteRef); /* - * Invalidate the property + * Invalidate the entry */ if (SUCCEEDED(hr)) destroyDirEntry(This->ancestorStorage, - foundPropertyIndexToDelete); + entryToDeleteRef); return hr; } @@ -1821,17 +1870,53 @@ void StorageBaseImpl_RemoveStream(StorageBaseImpl * stg, StgStreamImpl * strm) list_remove(&(strm->StrmListEntry)); } +static BOOL StorageBaseImpl_IsStreamOpen(StorageBaseImpl * stg, DirRef streamEntry) +{ + StgStreamImpl *strm; + + LIST_FOR_EACH_ENTRY(strm, &stg->strmHead, StgStreamImpl, StrmListEntry) + { + if (strm->dirEntry == streamEntry) + { + return TRUE; + } + } + + return FALSE; +} + +static BOOL StorageBaseImpl_IsStorageOpen(StorageBaseImpl * stg, DirRef storageEntry) +{ + StorageInternalImpl *childstg; + + LIST_FOR_EACH_ENTRY(childstg, &stg->storageHead, StorageInternalImpl, ParentListEntry) + { + if (childstg->base.storageDirEntry == storageEntry) + { + return TRUE; + } + } + + return FALSE; +} + static void StorageBaseImpl_DeleteAll(StorageBaseImpl * stg) { struct list *cur, *cur2; StgStreamImpl *strm=NULL; + StorageInternalImpl *childstg=NULL; LIST_FOR_EACH_SAFE(cur, cur2, &stg->strmHead) { strm = LIST_ENTRY(cur,StgStreamImpl,StrmListEntry); - TRACE("Streams deleted (stg=%p strm=%p next=%p prev=%p)\n", stg,strm,cur->next,cur->prev); + TRACE("Streams invalidated (stg=%p strm=%p next=%p prev=%p)\n", stg,strm,cur->next,cur->prev); strm->parentStorage = NULL; list_remove(cur); } + + LIST_FOR_EACH_SAFE(cur, cur2, &stg->storageHead) { + childstg = LIST_ENTRY(cur,StorageInternalImpl,ParentListEntry); + StorageInternalImpl_Invalidate( childstg ); + } } @@ -1839,26 +1924,36 @@ static void StorageBaseImpl_DeleteAll(StorageBaseImpl * stg) * * Internal Method * - * Perform the deletion of a complete storage node + * Delete the contents of a storage entry. * */ -static HRESULT deleteStorageProperty( +static HRESULT deleteStorageContents( StorageBaseImpl *parentStorage, - ULONG indexOfPropertyToDelete, - DirEntry propertyToDelete) + DirRef indexToDelete, + DirEntry entryDataToDelete) { IEnumSTATSTG *elements = 0; IStorage *childStorage = 0; STATSTG currentElement; HRESULT hr; HRESULT destroyHr = S_OK; + StorageInternalImpl *stg, *stg2; + + /* Invalidate any open storage objects. */ + LIST_FOR_EACH_ENTRY_SAFE(stg, stg2, &parentStorage->storageHead, StorageInternalImpl, ParentListEntry) + { + if (stg->base.storageDirEntry == indexToDelete) + { + StorageInternalImpl_Invalidate(stg); + } + } /* * Open the storage and enumerate it */ hr = StorageBaseImpl_OpenStorage( (IStorage*)parentStorage, - propertyToDelete.name, + entryDataToDelete.name, 0, STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, @@ -1906,23 +2001,35 @@ static HRESULT deleteStorageProperty( * * Internal Method * - * Perform the deletion of a stream node + * Perform the deletion of a stream's data * */ -static HRESULT deleteStreamProperty( +static HRESULT deleteStreamContents( StorageBaseImpl *parentStorage, - ULONG indexOfPropertyToDelete, - DirEntry propertyToDelete) + DirRef indexToDelete, + DirEntry entryDataToDelete) { IStream *pis; HRESULT hr; ULARGE_INTEGER size; + StgStreamImpl *strm, *strm2; + + /* Invalidate any open stream objects. */ + LIST_FOR_EACH_ENTRY_SAFE(strm, strm2, &parentStorage->strmHead, StgStreamImpl, StrmListEntry) + { + if (strm->dirEntry == indexToDelete) + { + TRACE("Stream deleted %p\n", strm); + strm->parentStorage = NULL; + list_remove(&strm->StrmListEntry); + } + } size.u.HighPart = 0; size.u.LowPart = 0; hr = StorageBaseImpl_OpenStream((IStorage*)parentStorage, - propertyToDelete.name, NULL, STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &pis); + entryDataToDelete.name, NULL, STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &pis); if (hr!=S_OK) { @@ -1947,18 +2054,18 @@ static HRESULT deleteStreamProperty( return S_OK; } -static void setPropertyLink(DirEntry *property, ULONG relation, ULONG new_target) +static void setEntryLink(DirEntry *entry, ULONG relation, DirRef new_target) { switch (relation) { case DIRENTRY_RELATION_PREVIOUS: - property->leftChild = new_target; + entry->leftChild = new_target; break; case DIRENTRY_RELATION_NEXT: - property->rightChild = new_target; + entry->rightChild = new_target; break; case DIRENTRY_RELATION_DIR: - property->dirRootEntry = new_target; + entry->dirRootEntry = new_target; break; default: assert(0); @@ -1974,74 +2081,74 @@ static void setPropertyLink(DirEntry *property, ULONG relation, ULONG new_target */ static HRESULT removeFromTree( StorageImpl *This, - ULONG parentStorageIndex, - ULONG deletedIndex) + DirRef parentStorageIndex, + DirRef deletedIndex) { HRESULT hr = S_OK; BOOL res = TRUE; - DirEntry propertyToDelete; - DirEntry parentProperty; - ULONG parentPropertyId; + DirEntry entryToDelete; + DirEntry parentEntry; + DirRef parentEntryRef; ULONG typeOfRelation; - res = StorageImpl_ReadDirEntry(This, deletedIndex, &propertyToDelete); + res = StorageImpl_ReadDirEntry(This, deletedIndex, &entryToDelete); /* - * Find the property that links to the one we want to delete. + * Find the element that links to the one we want to delete. */ - hr = findTreeParent(This, parentStorageIndex, propertyToDelete.name, - &parentProperty, &parentPropertyId, &typeOfRelation); + hr = findTreeParent(This, parentStorageIndex, entryToDelete.name, + &parentEntry, &parentEntryRef, &typeOfRelation); if (hr != S_OK) return hr; - if (propertyToDelete.leftChild != DIRENTRY_NULL) + if (entryToDelete.leftChild != DIRENTRY_NULL) { /* * Replace the deleted entry with its left child */ - setPropertyLink(&parentProperty, typeOfRelation, propertyToDelete.leftChild); + setEntryLink(&parentEntry, typeOfRelation, entryToDelete.leftChild); res = StorageImpl_WriteDirEntry( This, - parentPropertyId, - &parentProperty); + parentEntryRef, + &parentEntry); if(!res) { return E_FAIL; } - if (propertyToDelete.rightChild != DIRENTRY_NULL) + if (entryToDelete.rightChild != DIRENTRY_NULL) { /* * We need to reinsert the right child somewhere. We already know it and * its children are greater than everything in the left tree, so we * insert it at the rightmost point in the left tree. */ - ULONG newRightChildParent = propertyToDelete.leftChild; - DirEntry newRightChildParentProperty; + DirRef newRightChildParent = entryToDelete.leftChild; + DirEntry newRightChildParentEntry; do { res = StorageImpl_ReadDirEntry( This, newRightChildParent, - &newRightChildParentProperty); + &newRightChildParentEntry); if (!res) { return E_FAIL; } - if (newRightChildParentProperty.rightChild != DIRENTRY_NULL) - newRightChildParent = newRightChildParentProperty.rightChild; - } while (newRightChildParentProperty.rightChild != DIRENTRY_NULL); + if (newRightChildParentEntry.rightChild != DIRENTRY_NULL) + newRightChildParent = newRightChildParentEntry.rightChild; + } while (newRightChildParentEntry.rightChild != DIRENTRY_NULL); - newRightChildParentProperty.rightChild = propertyToDelete.rightChild; + newRightChildParentEntry.rightChild = entryToDelete.rightChild; res = StorageImpl_WriteDirEntry( This, newRightChildParent, - &newRightChildParentProperty); + &newRightChildParentEntry); if (!res) { return E_FAIL; @@ -2053,12 +2160,12 @@ static HRESULT removeFromTree( /* * Replace the deleted entry with its right child */ - setPropertyLink(&parentProperty, typeOfRelation, propertyToDelete.rightChild); + setEntryLink(&parentEntry, typeOfRelation, entryToDelete.rightChild); res = StorageImpl_WriteDirEntry( This, - parentPropertyId, - &parentProperty); + parentEntryRef, + &parentEntry); if(!res) { return E_FAIL; @@ -2092,6 +2199,10 @@ static HRESULT WINAPI StorageBaseImpl_SetStateBits( DWORD grfMask) /* [in] */ { StorageBaseImpl* const This = (StorageBaseImpl*)iface; + + if (!This->ancestorStorage) + return STG_E_REVERTED; + This->stateBits = (This->stateBits & ~grfMask) | (grfStateBits & grfMask); return S_OK; } @@ -2122,30 +2233,38 @@ static const IStorageVtbl Storage32Impl_Vtbl = }; static HRESULT StorageImpl_Construct( - StorageImpl* This, HANDLE hFile, LPCOLESTR pwcsName, ILockBytes* pLkbyt, DWORD openFlags, BOOL fileBased, - BOOL create) + BOOL create, + StorageImpl** result) { + StorageImpl* This; HRESULT hr = S_OK; - DirEntry currentProperty; + DirEntry currentEntry; BOOL readSuccessful; - ULONG currentPropertyIndex; + DirRef currentEntryRef; if ( FAILED( validateSTGM(openFlags) )) return STG_E_INVALIDFLAG; + This = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl)); + if (!This) + return E_OUTOFMEMORY; + memset(This, 0, sizeof(StorageImpl)); list_init(&This->base.strmHead); + list_init(&This->base.storageHead); + This->base.lpVtbl = &Storage32Impl_Vtbl; This->base.pssVtbl = &IPropertySetStorage_Vtbl; This->base.v_destructor = StorageImpl_Destroy; This->base.openFlags = (openFlags & ~STGM_CREATE); + This->base.ref = 1; This->create = create; /* @@ -2160,7 +2279,10 @@ static HRESULT StorageImpl_Construct( This->pwcsName = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(pwcsName)+1)*sizeof(WCHAR)); if (!This->pwcsName) - return STG_E_INSUFFICIENTMEMORY; + { + hr = STG_E_INSUFFICIENTMEMORY; + goto end; + } strcpyW(This->pwcsName, pwcsName); } @@ -2176,7 +2298,10 @@ static HRESULT StorageImpl_Construct( fileBased); if (This->bigBlockFile == 0) - return E_FAIL; + { + hr = E_FAIL; + goto end; + } if (create) { @@ -2186,7 +2311,7 @@ static HRESULT StorageImpl_Construct( /* * Initialize all header variables: * - The big block depot consists of one block and it is at block 0 - * - The properties start at block 1 + * - The directory table starts at block 1 * - There is no small block depot */ memset( This->bigBlockDepotStart, @@ -2205,7 +2330,7 @@ static HRESULT StorageImpl_Construct( StorageImpl_SaveFileHeader(This); /* - * Add one block for the big block depot and one block for the properties + * Add one block for the big block depot and one block for the directory table */ size.u.HighPart = 0; size.u.LowPart = This->bigBlockSize * 3; @@ -2228,9 +2353,7 @@ static HRESULT StorageImpl_Construct( if (FAILED(hr)) { - BIGBLOCKFILE_Destructor(This->bigBlockFile); - - return hr; + goto end; } } @@ -2249,74 +2372,91 @@ static HRESULT StorageImpl_Construct( */ if(!(This->rootBlockChain = BlockChainStream_Construct(This, &This->rootStartBlock, DIRENTRY_NULL))) - return STG_E_READFAULT; + { + hr = STG_E_READFAULT; + goto end; + } if(!(This->smallBlockDepotChain = BlockChainStream_Construct(This, &This->smallBlockDepotStart, DIRENTRY_NULL))) - return STG_E_READFAULT; + { + hr = STG_E_READFAULT; + goto end; + } /* - * Write the root property (memory only) + * Write the root storage entry (memory only) */ if (create) { - DirEntry rootProp; + DirEntry rootEntry; /* - * Initialize the property chain + * Initialize the directory table */ - memset(&rootProp, 0, sizeof(rootProp)); - MultiByteToWideChar( CP_ACP, 0, rootPropertyName, -1, rootProp.name, - sizeof(rootProp.name)/sizeof(WCHAR) ); - rootProp.sizeOfNameString = (strlenW(rootProp.name)+1) * sizeof(WCHAR); - rootProp.propertyType = STGTY_ROOT; - rootProp.leftChild = DIRENTRY_NULL; - rootProp.rightChild = DIRENTRY_NULL; - rootProp.dirRootEntry = DIRENTRY_NULL; - rootProp.startingBlock = BLOCK_END_OF_CHAIN; - rootProp.size.u.HighPart = 0; - rootProp.size.u.LowPart = 0; + memset(&rootEntry, 0, sizeof(rootEntry)); + MultiByteToWideChar( CP_ACP, 0, rootEntryName, -1, rootEntry.name, + sizeof(rootEntry.name)/sizeof(WCHAR) ); + rootEntry.sizeOfNameString = (strlenW(rootEntry.name)+1) * sizeof(WCHAR); + rootEntry.stgType = STGTY_ROOT; + rootEntry.leftChild = DIRENTRY_NULL; + rootEntry.rightChild = DIRENTRY_NULL; + rootEntry.dirRootEntry = DIRENTRY_NULL; + rootEntry.startingBlock = BLOCK_END_OF_CHAIN; + rootEntry.size.u.HighPart = 0; + rootEntry.size.u.LowPart = 0; - StorageImpl_WriteDirEntry(This, 0, &rootProp); + StorageImpl_WriteDirEntry(This, 0, &rootEntry); } /* - * Find the ID of the root in the property sets. + * Find the ID of the root storage. */ - currentPropertyIndex = 0; + currentEntryRef = 0; do { readSuccessful = StorageImpl_ReadDirEntry( This, - currentPropertyIndex, - ¤tProperty); + currentEntryRef, + ¤tEntry); if (readSuccessful) { - if ( (currentProperty.sizeOfNameString != 0 ) && - (currentProperty.propertyType == STGTY_ROOT) ) + if ( (currentEntry.sizeOfNameString != 0 ) && + (currentEntry.stgType == STGTY_ROOT) ) { - This->base.rootPropertySetIndex = currentPropertyIndex; + This->base.storageDirEntry = currentEntryRef; } } - currentPropertyIndex++; + currentEntryRef++; - } while (readSuccessful && (This->base.rootPropertySetIndex == DIRENTRY_NULL) ); + } while (readSuccessful && (This->base.storageDirEntry == DIRENTRY_NULL) ); if (!readSuccessful) { - /* TODO CLEANUP */ - return STG_E_READFAULT; + hr = STG_E_READFAULT; + goto end; } /* * Create the block chain abstraction for the small block root chain. */ if(!(This->smallBlockRootChain = - BlockChainStream_Construct(This, NULL, This->base.rootPropertySetIndex))) - return STG_E_READFAULT; + BlockChainStream_Construct(This, NULL, This->base.storageDirEntry))) + { + hr = STG_E_READFAULT; + } + +end: + if (FAILED(hr)) + { + IStorage_Release((IStorage*)This); + *result = NULL; + } + else + *result = This; return hr; } @@ -2334,7 +2474,8 @@ static void StorageImpl_Destroy(StorageBaseImpl* iface) BlockChainStream_Destroy(This->rootBlockChain); BlockChainStream_Destroy(This->smallBlockDepotChain); - BIGBLOCKFILE_Destructor(This->bigBlockFile); + if (This->bigBlockFile) + BIGBLOCKFILE_Destructor(This->bigBlockFile); HeapFree(GetProcessHeap(), 0, This); } @@ -2991,7 +3132,7 @@ static void StorageImpl_SaveFileHeader( * * This method will read the raw data from a directory entry in the file. * - * buffer must be PROPSET_BLOCK_SIZE bytes long. + * buffer must be RAW_DIRENTRY_SIZE bytes long. */ HRESULT StorageImpl_ReadRawDirEntry(StorageImpl *This, ULONG index, BYTE *buffer) { @@ -3017,7 +3158,7 @@ HRESULT StorageImpl_ReadRawDirEntry(StorageImpl *This, ULONG index, BYTE *buffer * * This method will write the raw data from a directory entry in the file. * - * buffer must be PROPSET_BLOCK_SIZE bytes long. + * buffer must be RAW_DIRENTRY_SIZE bytes long. */ HRESULT StorageImpl_WriteRawDirEntry(StorageImpl *This, ULONG index, const BYTE *buffer) { @@ -3043,7 +3184,7 @@ HRESULT StorageImpl_WriteRawDirEntry(StorageImpl *This, ULONG index, const BYTE * * Update raw directory entry data from the fields in newData. * - * buffer must be PROPSET_BLOCK_SIZE bytes long. + * buffer must be RAW_DIRENTRY_SIZE bytes long. */ void UpdateRawDirEntry(BYTE *buffer, const DirEntry *newData) { @@ -3054,7 +3195,7 @@ void UpdateRawDirEntry(BYTE *buffer, const DirEntry *newData) newData->name, DIRENTRY_NAME_BUFFER_LEN ); - memcpy(buffer + OFFSET_PS_STGTYPE, &newData->propertyType, 1); + memcpy(buffer + OFFSET_PS_STGTYPE, &newData->stgType, 1); StorageUtl_WriteWord( buffer, @@ -3079,7 +3220,7 @@ void UpdateRawDirEntry(BYTE *buffer, const DirEntry *newData) StorageUtl_WriteGUID( buffer, OFFSET_PS_GUID, - &newData->propertyUniqueID); + &newData->clsid); StorageUtl_WriteDWord( buffer, @@ -3113,87 +3254,83 @@ void UpdateRawDirEntry(BYTE *buffer, const DirEntry *newData) } /****************************************************************************** - * Storage32Impl_ReadProperty + * Storage32Impl_ReadDirEntry * - * This method will read the specified property from the property chain. + * This method will read the specified directory entry. */ BOOL StorageImpl_ReadDirEntry( StorageImpl* This, - ULONG index, + DirRef index, DirEntry* buffer) { - BYTE currentProperty[RAW_DIRENTRY_SIZE]; + BYTE currentEntry[RAW_DIRENTRY_SIZE]; HRESULT readRes; - readRes = StorageImpl_ReadRawDirEntry(This, index, currentProperty); + readRes = StorageImpl_ReadRawDirEntry(This, index, currentEntry); if (SUCCEEDED(readRes)) { - /* replace the name of root entry (often "Root Entry") by the file name */ - WCHAR *propName = (index == This->base.rootPropertySetIndex) ? - This->filename : (WCHAR *)currentProperty+OFFSET_PS_NAME; - memset(buffer->name, 0, sizeof(buffer->name)); memcpy( buffer->name, - propName, + (WCHAR *)currentEntry+OFFSET_PS_NAME, DIRENTRY_NAME_BUFFER_LEN ); TRACE("storage name: %s\n", debugstr_w(buffer->name)); - memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_STGTYPE, 1); + memcpy(&buffer->stgType, currentEntry + OFFSET_PS_STGTYPE, 1); StorageUtl_ReadWord( - currentProperty, + currentEntry, OFFSET_PS_NAMELENGTH, &buffer->sizeOfNameString); StorageUtl_ReadDWord( - currentProperty, + currentEntry, OFFSET_PS_LEFTCHILD, &buffer->leftChild); StorageUtl_ReadDWord( - currentProperty, + currentEntry, OFFSET_PS_RIGHTCHILD, &buffer->rightChild); StorageUtl_ReadDWord( - currentProperty, + currentEntry, OFFSET_PS_DIRROOT, &buffer->dirRootEntry); StorageUtl_ReadGUID( - currentProperty, + currentEntry, OFFSET_PS_GUID, - &buffer->propertyUniqueID); + &buffer->clsid); StorageUtl_ReadDWord( - currentProperty, + currentEntry, OFFSET_PS_CTIMELOW, &buffer->ctime.dwLowDateTime); StorageUtl_ReadDWord( - currentProperty, + currentEntry, OFFSET_PS_CTIMEHIGH, &buffer->ctime.dwHighDateTime); StorageUtl_ReadDWord( - currentProperty, + currentEntry, OFFSET_PS_MTIMELOW, &buffer->mtime.dwLowDateTime); StorageUtl_ReadDWord( - currentProperty, + currentEntry, OFFSET_PS_MTIMEHIGH, &buffer->mtime.dwHighDateTime); StorageUtl_ReadDWord( - currentProperty, + currentEntry, OFFSET_PS_STARTBLOCK, &buffer->startingBlock); StorageUtl_ReadDWord( - currentProperty, + currentEntry, OFFSET_PS_SIZE, &buffer->size.u.LowPart); @@ -3204,19 +3341,19 @@ BOOL StorageImpl_ReadDirEntry( } /********************************************************************* - * Write the specified property into the property chain + * Write the specified directory entry to the file */ BOOL StorageImpl_WriteDirEntry( StorageImpl* This, - ULONG index, + DirRef index, const DirEntry* buffer) { - BYTE currentProperty[RAW_DIRENTRY_SIZE]; + BYTE currentEntry[RAW_DIRENTRY_SIZE]; HRESULT writeRes; - UpdateRawDirEntry(currentProperty, buffer); + UpdateRawDirEntry(currentEntry, buffer); - writeRes = StorageImpl_WriteRawDirEntry(This, index, currentProperty); + writeRes = StorageImpl_WriteRawDirEntry(This, index, currentEntry); return SUCCEEDED(writeRes) ? TRUE : FALSE; } @@ -3301,17 +3438,17 @@ BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks( ULARGE_INTEGER size, offset; ULONG cbRead, cbWritten; ULARGE_INTEGER cbTotalRead; - ULONG propertyIndex; + DirRef streamEntryRef; HRESULT resWrite = S_OK; HRESULT resRead; - DirEntry chainProperty; + DirEntry streamEntry; BYTE *buffer; BlockChainStream *bbTempChain = NULL; BlockChainStream *bigBlockChain = NULL; /* * Create a temporary big block chain that doesn't have - * an associated property. This temporary chain will be + * an associated directory entry. This temporary chain will be * used to copy data from small blocks to big blocks. */ bbTempChain = BlockChainStream_Construct(This, @@ -3375,29 +3512,29 @@ BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks( /* * Destroy the small block chain. */ - propertyIndex = (*ppsbChain)->ownerPropertyIndex; + streamEntryRef = (*ppsbChain)->ownerDirEntry; SmallBlockChainStream_SetSize(*ppsbChain, size); SmallBlockChainStream_Destroy(*ppsbChain); *ppsbChain = 0; /* - * Change the property information. This chain is now a big block chain + * Change the directory entry. This chain is now a big block chain * and it doesn't reside in the small blocks chain anymore. */ - StorageImpl_ReadDirEntry(This, propertyIndex, &chainProperty); + StorageImpl_ReadDirEntry(This, streamEntryRef, &streamEntry); - chainProperty.startingBlock = bbHeadOfChain; + streamEntry.startingBlock = bbHeadOfChain; - StorageImpl_WriteDirEntry(This, propertyIndex, &chainProperty); + StorageImpl_WriteDirEntry(This, streamEntryRef, &streamEntry); /* - * Destroy the temporary propertyless big block chain. - * Create a new big block chain associated with this property. + * Destroy the temporary entryless big block chain. + * Create a new big block chain associated with this entry. */ BlockChainStream_Destroy(bbTempChain); bigBlockChain = BlockChainStream_Construct(This, NULL, - propertyIndex); + streamEntryRef); return bigBlockChain; } @@ -3413,9 +3550,10 @@ SmallBlockChainStream* Storage32Impl_BigBlocksToSmallBlocks( BlockChainStream** ppbbChain) { ULARGE_INTEGER size, offset, cbTotalRead; - ULONG cbRead, cbWritten, propertyIndex, sbHeadOfChain = BLOCK_END_OF_CHAIN; + ULONG cbRead, cbWritten, sbHeadOfChain = BLOCK_END_OF_CHAIN; + DirRef streamEntryRef; HRESULT resWrite = S_OK, resRead; - DirEntry chainProperty; + DirEntry streamEntry; BYTE* buffer; SmallBlockChainStream* sbTempChain; @@ -3470,23 +3608,39 @@ SmallBlockChainStream* Storage32Impl_BigBlocksToSmallBlocks( } /* destroy the original big block chain */ - propertyIndex = (*ppbbChain)->ownerPropertyIndex; + streamEntryRef = (*ppbbChain)->ownerDirEntry; BlockChainStream_SetSize(*ppbbChain, size); BlockChainStream_Destroy(*ppbbChain); *ppbbChain = NULL; - StorageImpl_ReadDirEntry(This, propertyIndex, &chainProperty); - chainProperty.startingBlock = sbHeadOfChain; - StorageImpl_WriteDirEntry(This, propertyIndex, &chainProperty); + StorageImpl_ReadDirEntry(This, streamEntryRef, &streamEntry); + streamEntry.startingBlock = sbHeadOfChain; + StorageImpl_WriteDirEntry(This, streamEntryRef, &streamEntry); SmallBlockChainStream_Destroy(sbTempChain); - return SmallBlockChainStream_Construct(This, NULL, propertyIndex); + return SmallBlockChainStream_Construct(This, NULL, streamEntryRef); +} + +static void StorageInternalImpl_Invalidate( StorageInternalImpl *This ) +{ + if (This->base.ancestorStorage) + { + TRACE("Storage invalidated (stg=%p)\n", This); + + This->base.ancestorStorage = NULL; + + StorageBaseImpl_DeleteAll(&This->base); + + list_remove(&This->ParentListEntry); + } } static void StorageInternalImpl_Destroy( StorageBaseImpl *iface) { StorageInternalImpl* This = (StorageInternalImpl*) iface; + StorageInternalImpl_Invalidate(This); + HeapFree(GetProcessHeap(), 0, This); } @@ -3577,10 +3731,10 @@ static HRESULT WINAPI IEnumSTATSTGImpl_Next( { IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface; - DirEntry currentProperty; + DirEntry currentEntry; STATSTG* currentReturnStruct = rgelt; ULONG objectFetched = 0; - ULONG currentSearchNode; + DirRef currentSearchNode; if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) ) return E_INVALIDARG; @@ -3612,17 +3766,18 @@ static HRESULT WINAPI IEnumSTATSTGImpl_Next( IEnumSTATSTGImpl_PopSearchNode(This, TRUE); /* - * Read the property from the storage. + * Read the entry from the storage. */ StorageImpl_ReadDirEntry(This->parentStorage, currentSearchNode, - ¤tProperty); + ¤tEntry); /* * Copy the information to the return buffer. */ - StorageUtl_CopyDirEntryToSTATSTG(currentReturnStruct, - ¤tProperty, + StorageUtl_CopyDirEntryToSTATSTG(This->parentStorage, + currentReturnStruct, + ¤tEntry, STATFLAG_DEFAULT); /* @@ -3634,7 +3789,7 @@ static HRESULT WINAPI IEnumSTATSTGImpl_Next( /* * Push the next search node in the search stack. */ - IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.rightChild); + IEnumSTATSTGImpl_PushSearchNode(This, currentEntry.rightChild); /* * continue the iteration. @@ -3655,9 +3810,9 @@ static HRESULT WINAPI IEnumSTATSTGImpl_Skip( { IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface; - DirEntry currentProperty; + DirEntry currentEntry; ULONG objectFetched = 0; - ULONG currentSearchNode; + DirRef currentSearchNode; /* * Start with the node at the top of the stack. @@ -3673,11 +3828,11 @@ static HRESULT WINAPI IEnumSTATSTGImpl_Skip( IEnumSTATSTGImpl_PopSearchNode(This, TRUE); /* - * Read the property from the storage. + * Read the entry from the storage. */ StorageImpl_ReadDirEntry(This->parentStorage, currentSearchNode, - ¤tProperty); + ¤tEntry); /* * Step to the next item in the iteration @@ -3687,7 +3842,7 @@ static HRESULT WINAPI IEnumSTATSTGImpl_Skip( /* * Push the next search node in the search stack. */ - IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.rightChild); + IEnumSTATSTGImpl_PushSearchNode(This, currentEntry.rightChild); /* * continue the iteration. @@ -3706,7 +3861,7 @@ static HRESULT WINAPI IEnumSTATSTGImpl_Reset( { IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface; - DirEntry rootProperty; + DirEntry storageEntry; BOOL readSuccessful; /* @@ -3715,21 +3870,21 @@ static HRESULT WINAPI IEnumSTATSTGImpl_Reset( This->stackSize = 0; /* - * Read the root property from the storage. + * Read the storage entry from the top-level storage. */ readSuccessful = StorageImpl_ReadDirEntry( This->parentStorage, - This->firstPropertyNode, - &rootProperty); + This->storageDirEntry, + &storageEntry); if (readSuccessful) { - assert(rootProperty.sizeOfNameString!=0); + assert(storageEntry.sizeOfNameString!=0); /* * Push the search node in the search stack. */ - IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirRootEntry); + IEnumSTATSTGImpl_PushSearchNode(This, storageEntry.dirRootEntry); } return S_OK; @@ -3750,7 +3905,7 @@ static HRESULT WINAPI IEnumSTATSTGImpl_Clone( return E_INVALIDARG; newClone = IEnumSTATSTGImpl_Construct(This->parentStorage, - This->firstPropertyNode); + This->storageDirEntry); /* @@ -3765,7 +3920,7 @@ static HRESULT WINAPI IEnumSTATSTGImpl_Clone( memcpy( newClone->stackToVisit, This->stackToVisit, - sizeof(ULONG) * newClone->stackSize); + sizeof(DirRef) * newClone->stackSize); *ppenum = (IEnumSTATSTG*)newClone; @@ -3780,9 +3935,9 @@ static HRESULT WINAPI IEnumSTATSTGImpl_Clone( static void IEnumSTATSTGImpl_PushSearchNode( IEnumSTATSTGImpl* This, - ULONG nodeToPush) + DirRef nodeToPush) { - DirEntry rootProperty; + DirEntry storageEntry; BOOL readSuccessful; /* @@ -3802,36 +3957,36 @@ static void IEnumSTATSTGImpl_PushSearchNode( GetProcessHeap(), 0, This->stackToVisit, - sizeof(ULONG) * This->stackMaxSize); + sizeof(DirRef) * This->stackMaxSize); } This->stackToVisit[This->stackSize] = nodeToPush; This->stackSize++; /* - * Read the root property from the storage. + * Read the storage entry from the top-level storage. */ readSuccessful = StorageImpl_ReadDirEntry( This->parentStorage, nodeToPush, - &rootProperty); + &storageEntry); if (readSuccessful) { - assert(rootProperty.sizeOfNameString!=0); + assert(storageEntry.sizeOfNameString!=0); /* * Push the previous search node in the search stack. */ - IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.leftChild); + IEnumSTATSTGImpl_PushSearchNode(This, storageEntry.leftChild); } } -static ULONG IEnumSTATSTGImpl_PopSearchNode( +static DirRef IEnumSTATSTGImpl_PopSearchNode( IEnumSTATSTGImpl* This, BOOL remove) { - ULONG topNode; + DirRef topNode; if (This->stackSize == 0) return DIRENTRY_NULL; @@ -3864,7 +4019,7 @@ static const IEnumSTATSTGVtbl IEnumSTATSTGImpl_Vtbl = static IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct( StorageImpl* parentStorage, - ULONG firstPropertyNode) + DirRef storageDirEntry) { IEnumSTATSTGImpl* newEnumeration; @@ -3885,7 +4040,7 @@ static IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct( newEnumeration->parentStorage = parentStorage; IStorage_AddRef((IStorage*)newEnumeration->parentStorage); - newEnumeration->firstPropertyNode = firstPropertyNode; + newEnumeration->storageDirEntry = storageDirEntry; /* * Initialize the search stack @@ -3893,7 +4048,7 @@ static IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct( newEnumeration->stackSize = 0; newEnumeration->stackMaxSize = ENUMSTATSGT_SIZE_INCREMENT; newEnumeration->stackToVisit = - HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG)*ENUMSTATSGT_SIZE_INCREMENT); + HeapAlloc(GetProcessHeap(), 0, sizeof(DirRef)*ENUMSTATSGT_SIZE_INCREMENT); /* * Make sure the current node of the iterator is the first one. @@ -3936,7 +4091,7 @@ static const IStorageVtbl Storage32InternalImpl_Vtbl = static StorageInternalImpl* StorageInternalImpl_Construct( StorageImpl* ancestorStorage, DWORD openFlags, - ULONG rootPropertyIndex) + DirRef storageDirEntry) { StorageInternalImpl* newStorage; @@ -3944,11 +4099,10 @@ static StorageInternalImpl* StorageInternalImpl_Construct( if (newStorage!=0) { - /* - * Initialize the stream list - */ list_init(&newStorage->base.strmHead); + list_init(&newStorage->base.storageHead); + /* * Initialize the virtual function table. */ @@ -3962,9 +4116,9 @@ static StorageInternalImpl* StorageInternalImpl_Construct( newStorage->base.ancestorStorage = ancestorStorage; /* - * Keep the index of the root property set for this storage, + * Keep a reference to the directory entry of this storage */ - newStorage->base.rootPropertySetIndex = rootPropertyIndex; + newStorage->base.storageDirEntry = storageDirEntry; return newStorage; } @@ -4051,28 +4205,41 @@ void StorageUtl_WriteGUID(BYTE* buffer, ULONG offset, const GUID* value) } void StorageUtl_CopyDirEntryToSTATSTG( + StorageImpl* storage, STATSTG* destination, const DirEntry* source, int statFlags) { + LPCWSTR entryName; + + if (source->stgType == STGTY_ROOT) + { + /* replace the name of root entry (often "Root Entry") by the file name */ + entryName = storage->filename; + } + else + { + entryName = source->name; + } + /* * The copy of the string occurs only when the flag is not set */ if( ((statFlags & STATFLAG_NONAME) != 0) || - (source->name == NULL) || - (source->name[0] == 0) ) + (entryName == NULL) || + (entryName[0] == 0) ) { destination->pwcsName = 0; } else { destination->pwcsName = - CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR)); + CoTaskMemAlloc((lstrlenW(entryName)+1)*sizeof(WCHAR)); - strcpyW(destination->pwcsName, source->name); + strcpyW(destination->pwcsName, entryName); } - switch (source->propertyType) + switch (source->stgType) { case STGTY_STORAGE: case STGTY_ROOT: @@ -4094,7 +4261,7 @@ void StorageUtl_CopyDirEntryToSTATSTG( */ destination->grfMode = 0; destination->grfLocksSupported = 0; - destination->clsid = source->propertyUniqueID; + destination->clsid = source->clsid; destination->grfStateBits = 0; destination->reserved = 0; } @@ -4106,7 +4273,7 @@ void StorageUtl_CopyDirEntryToSTATSTG( BlockChainStream* BlockChainStream_Construct( StorageImpl* parentStorage, ULONG* headOfStreamPlaceHolder, - ULONG propertyIndex) + DirRef dirEntry) { BlockChainStream* newStream; ULONG blockIndex; @@ -4115,7 +4282,7 @@ BlockChainStream* BlockChainStream_Construct( newStream->parentStorage = parentStorage; newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder; - newStream->ownerPropertyIndex = propertyIndex; + newStream->ownerDirEntry = dirEntry; newStream->lastBlockNoInSequence = 0xFFFFFFFF; newStream->tailIndex = BLOCK_END_OF_CHAIN; newStream->numBlocks = 0; @@ -4149,28 +4316,28 @@ void BlockChainStream_Destroy(BlockChainStream* This) * BlockChainStream_GetHeadOfChain * * Returns the head of this stream chain. - * Some special chains don't have properties, their heads are kept in + * Some special chains don't have directory entries, their heads are kept in * This->headOfStreamPlaceHolder. * */ static ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This) { - DirEntry chainProperty; + DirEntry chainEntry; BOOL readSuccessful; if (This->headOfStreamPlaceHolder != 0) return *(This->headOfStreamPlaceHolder); - if (This->ownerPropertyIndex != DIRENTRY_NULL) + if (This->ownerDirEntry != DIRENTRY_NULL) { readSuccessful = StorageImpl_ReadDirEntry( This->parentStorage, - This->ownerPropertyIndex, - &chainProperty); + This->ownerDirEntry, + &chainEntry); if (readSuccessful) { - return chainProperty.startingBlock; + return chainEntry.startingBlock; } } @@ -4497,20 +4664,20 @@ static BOOL BlockChainStream_Enlarge(BlockChainStream* This, } else { - DirEntry chainProp; - assert(This->ownerPropertyIndex != DIRENTRY_NULL); + DirEntry chainEntry; + assert(This->ownerDirEntry != DIRENTRY_NULL); StorageImpl_ReadDirEntry( This->parentStorage, - This->ownerPropertyIndex, - &chainProp); + This->ownerDirEntry, + &chainEntry); - chainProp.startingBlock = blockIndex; + chainEntry.startingBlock = blockIndex; StorageImpl_WriteDirEntry( This->parentStorage, - This->ownerPropertyIndex, - &chainProp); + This->ownerDirEntry, + &chainEntry); } This->tailIndex = blockIndex; @@ -4613,29 +4780,28 @@ BOOL BlockChainStream_SetSize( * BlockChainStream_GetSize * * Returns the size of this chain. - * Will return the block count if this chain doesn't have a property. + * Will return the block count if this chain doesn't have a directory entry. */ static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This) { - DirEntry chainProperty; + DirEntry chainEntry; if(This->headOfStreamPlaceHolder == NULL) { /* - * This chain is a data stream read the property and return - * the appropriate size + * This chain has a directory entry so use the size value from there. */ StorageImpl_ReadDirEntry( This->parentStorage, - This->ownerPropertyIndex, - &chainProperty); + This->ownerDirEntry, + &chainEntry); - return chainProperty.size; + return chainEntry.size; } else { /* - * this chain is a chain that does not have a property, figure out the + * this chain is a chain that does not have a directory entry, figure out the * size by making the product number of used blocks times the * size of them */ @@ -4657,7 +4823,7 @@ static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This) SmallBlockChainStream* SmallBlockChainStream_Construct( StorageImpl* parentStorage, ULONG* headOfStreamPlaceHolder, - ULONG propertyIndex) + DirRef dirEntry) { SmallBlockChainStream* newStream; @@ -4665,7 +4831,7 @@ SmallBlockChainStream* SmallBlockChainStream_Construct( newStream->parentStorage = parentStorage; newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder; - newStream->ownerPropertyIndex = propertyIndex; + newStream->ownerDirEntry = dirEntry; return newStream; } @@ -4684,22 +4850,22 @@ void SmallBlockChainStream_Destroy( static ULONG SmallBlockChainStream_GetHeadOfChain( SmallBlockChainStream* This) { - DirEntry chainProperty; + DirEntry chainEntry; BOOL readSuccessful; if (This->headOfStreamPlaceHolder != NULL) return *(This->headOfStreamPlaceHolder); - if (This->ownerPropertyIndex) + if (This->ownerDirEntry) { readSuccessful = StorageImpl_ReadDirEntry( This->parentStorage, - This->ownerPropertyIndex, - &chainProperty); + This->ownerDirEntry, + &chainEntry); if (readSuccessful) { - return chainProperty.startingBlock; + return chainEntry.startingBlock; } } @@ -4878,7 +5044,7 @@ static ULONG SmallBlockChainStream_GetNextFreeBlock( /* * We have just created the small block depot. */ - DirEntry rootProp; + DirEntry rootEntry; ULONG sbStartIndex; /* @@ -4900,17 +5066,17 @@ static ULONG SmallBlockChainStream_GetNextFreeBlock( StorageImpl_ReadDirEntry( This->parentStorage, - This->parentStorage->base.rootPropertySetIndex, - &rootProp); + This->parentStorage->base.storageDirEntry, + &rootEntry); - rootProp.startingBlock = sbStartIndex; - rootProp.size.u.HighPart = 0; - rootProp.size.u.LowPart = This->parentStorage->bigBlockSize; + rootEntry.startingBlock = sbStartIndex; + rootEntry.size.u.HighPart = 0; + rootEntry.size.u.LowPart = This->parentStorage->bigBlockSize; StorageImpl_WriteDirEntry( This->parentStorage, - This->parentStorage->base.rootPropertySetIndex, - &rootProp); + This->parentStorage->base.storageDirEntry, + &rootEntry); } else StorageImpl_SaveFileHeader(This->parentStorage); @@ -4925,27 +5091,27 @@ static ULONG SmallBlockChainStream_GetNextFreeBlock( */ if (blockIndex % smallBlocksPerBigBlock == 0) { - DirEntry rootProp; + DirEntry rootEntry; ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1; StorageImpl_ReadDirEntry( This->parentStorage, - This->parentStorage->base.rootPropertySetIndex, - &rootProp); + This->parentStorage->base.storageDirEntry, + &rootEntry); - if (rootProp.size.u.LowPart < + if (rootEntry.size.u.LowPart < (blocksRequired * This->parentStorage->bigBlockSize)) { - rootProp.size.u.LowPart += This->parentStorage->bigBlockSize; + rootEntry.size.u.LowPart += This->parentStorage->bigBlockSize; BlockChainStream_SetSize( This->parentStorage->smallBlockRootChain, - rootProp.size); + rootEntry.size); StorageImpl_WriteDirEntry( This->parentStorage, - This->parentStorage->base.rootPropertySetIndex, - &rootProp); + This->parentStorage->base.storageDirEntry, + &rootEntry); } } @@ -5175,17 +5341,17 @@ static BOOL SmallBlockChainStream_Shrink( */ if (count == 0) { - DirEntry chainProp; + DirEntry chainEntry; StorageImpl_ReadDirEntry(This->parentStorage, - This->ownerPropertyIndex, - &chainProp); + This->ownerDirEntry, + &chainEntry); - chainProp.startingBlock = BLOCK_END_OF_CHAIN; + chainEntry.startingBlock = BLOCK_END_OF_CHAIN; StorageImpl_WriteDirEntry(This->parentStorage, - This->ownerPropertyIndex, - &chainProp); + This->ownerDirEntry, + &chainEntry); /* * We start freeing the chain at the head block. @@ -5253,15 +5419,15 @@ static BOOL SmallBlockChainStream_Enlarge( } else { - DirEntry chainProp; + DirEntry chainEntry; - StorageImpl_ReadDirEntry(This->parentStorage, This->ownerPropertyIndex, - &chainProp); + StorageImpl_ReadDirEntry(This->parentStorage, This->ownerDirEntry, + &chainEntry); - chainProp.startingBlock = blockIndex; + chainEntry.startingBlock = blockIndex; - StorageImpl_WriteDirEntry(This->parentStorage, This->ownerPropertyIndex, - &chainProp); + StorageImpl_WriteDirEntry(This->parentStorage, This->ownerDirEntry, + &chainEntry); } } @@ -5370,7 +5536,7 @@ static ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This) */ static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This) { - DirEntry chainProperty; + DirEntry chainEntry; if(This->headOfStreamPlaceHolder != NULL) { @@ -5385,10 +5551,10 @@ static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This) StorageImpl_ReadDirEntry( This->parentStorage, - This->ownerPropertyIndex, - &chainProperty); + This->ownerDirEntry, + &chainEntry); - return chainProperty.size; + return chainEntry.size; } /****************************************************************************** @@ -5525,36 +5691,25 @@ HRESULT WINAPI StgCreateDocfile( /* * Allocate and initialize the new IStorage32object. */ - newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl)); - - if (newStorage == 0) - { - hr = STG_E_INSUFFICIENTMEMORY; - goto end; - } - hr = StorageImpl_Construct( - newStorage, hFile, pwcsName, NULL, grfMode, TRUE, - TRUE); + TRUE, + &newStorage); if (FAILED(hr)) { - HeapFree(GetProcessHeap(), 0, newStorage); goto end; } /* * Get an "out" pointer for the caller. */ - hr = StorageBaseImpl_QueryInterface( - (IStorage*)newStorage, - &IID_IStorage, - (void**)ppstgOpen); + *ppstgOpen = (IStorage*)newStorage; + end: TRACE("<-- %p r = %08x\n", *ppstgOpen, hr); @@ -5809,27 +5964,17 @@ HRESULT WINAPI StgOpenStorage( /* * Allocate and initialize the new IStorage32object. */ - newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl)); - - if (newStorage == 0) - { - hr = STG_E_INSUFFICIENTMEMORY; - goto end; - } - - /* Initialize the storage */ hr = StorageImpl_Construct( - newStorage, hFile, pwcsName, NULL, grfMode, TRUE, - FALSE ); + FALSE, + &newStorage); if (FAILED(hr)) { - HeapFree(GetProcessHeap(), 0, newStorage); /* * According to the docs if the file is not a storage, return STG_E_FILEALREADYEXISTS */ @@ -5846,10 +5991,7 @@ HRESULT WINAPI StgOpenStorage( /* * Get an "out" pointer for the caller. */ - hr = StorageBaseImpl_QueryInterface( - (IStorage*)newStorage, - &IID_IStorage, - (void**)ppstgOpen); + *ppstgOpen = (IStorage*)newStorage; end: TRACE("<-- %08x, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL); @@ -5874,33 +6016,24 @@ HRESULT WINAPI StgCreateDocfileOnILockBytes( /* * Allocate and initialize the new IStorage object. */ - newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl)); - - if (newStorage == 0) - return STG_E_INSUFFICIENTMEMORY; - hr = StorageImpl_Construct( - newStorage, 0, 0, plkbyt, grfMode, FALSE, - TRUE); + TRUE, + &newStorage); if (FAILED(hr)) { - HeapFree(GetProcessHeap(), 0, newStorage); return hr; } /* * Get an "out" pointer for the caller. */ - hr = StorageBaseImpl_QueryInterface( - (IStorage*)newStorage, - &IID_IStorage, - (void**)ppstgOpen); + *ppstgOpen = (IStorage*)newStorage; return hr; } @@ -5930,33 +6063,24 @@ HRESULT WINAPI StgOpenStorageOnILockBytes( /* * Allocate and initialize the new IStorage object. */ - newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl)); - - if (newStorage == 0) - return STG_E_INSUFFICIENTMEMORY; - hr = StorageImpl_Construct( - newStorage, 0, 0, plkbyt, grfMode, FALSE, - FALSE); + FALSE, + &newStorage); if (FAILED(hr)) { - HeapFree(GetProcessHeap(), 0, newStorage); return hr; } /* * Get an "out" pointer for the caller. */ - hr = StorageBaseImpl_QueryInterface( - (IStorage*)newStorage, - &IID_IStorage, - (void**)ppstgOpen); + *ppstgOpen = (IStorage*)newStorage; return hr; } diff --git a/dlls/ole32/storage32.h b/dlls/ole32/storage32.h index c7407476d14..508bd70a8a2 100644 --- a/dlls/ole32/storage32.h +++ b/dlls/ole32/storage32.h @@ -122,6 +122,11 @@ typedef struct DirEntry DirEntry; typedef struct StgStreamImpl StgStreamImpl; /* + * A reference to a directory entry in the file or a transacted cache. + */ +typedef ULONG DirRef; + +/* * This utility structure is used to read/write the information in a directory * entry. */ @@ -129,11 +134,11 @@ struct DirEntry { WCHAR name[DIRENTRY_NAME_MAX_LEN]; WORD sizeOfNameString; - BYTE propertyType; - ULONG leftChild; - ULONG rightChild; - ULONG dirRootEntry; - GUID propertyUniqueID; + BYTE stgType; + DirRef leftChild; + DirRef rightChild; + DirRef dirRootEntry; + GUID clsid; FILETIME ctime; FILETIME mtime; ULONG startingBlock; @@ -197,6 +202,11 @@ struct StorageBaseImpl struct list strmHead; /* + * Storage tracking list + */ + struct list storageHead; + + /* * Reference count of this object */ LONG ref; @@ -207,10 +217,9 @@ struct StorageBaseImpl StorageImpl* ancestorStorage; /* - * Index of the property for the root of - * this storage + * Index of the directory entry of this storage */ - ULONG rootPropertySetIndex; + DirRef storageDirEntry; /* * virtual Destructor method. @@ -304,12 +313,12 @@ HRESULT StorageImpl_WriteRawDirEntry( BOOL StorageImpl_ReadDirEntry( StorageImpl* This, - ULONG index, + DirRef index, DirEntry* buffer); BOOL StorageImpl_WriteDirEntry( StorageImpl* This, - ULONG index, + DirRef index, const DirEntry* buffer); BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks( @@ -353,9 +362,9 @@ struct StgStreamImpl DWORD grfMode; /* - * Index of the property that owns (points to) this stream. + * Index of the directory entry that owns (points to) this stream. */ - ULONG ownerProperty; + DirRef dirEntry; /* * Helper variable that contains the size of the stream @@ -382,7 +391,7 @@ struct StgStreamImpl StgStreamImpl* StgStreamImpl_Construct( StorageBaseImpl* parentStorage, DWORD grfMode, - ULONG ownerProperty); + DirRef dirEntry); /****************************************************************************** @@ -419,8 +428,8 @@ void StorageUtl_WriteULargeInteger(BYTE* buffer, ULONG offset, const ULARGE_INTEGER *value); void StorageUtl_ReadGUID(const BYTE* buffer, ULONG offset, GUID* value); void StorageUtl_WriteGUID(BYTE* buffer, ULONG offset, const GUID* value); -void StorageUtl_CopyDirEntryToSTATSTG(STATSTG* destination, const DirEntry* source, - int statFlags); +void StorageUtl_CopyDirEntryToSTATSTG(StorageImpl *storage,STATSTG* destination, + const DirEntry* source, int statFlags); /**************************************************************************** * BlockChainStream definitions. @@ -432,7 +441,7 @@ struct BlockChainStream { StorageImpl* parentStorage; ULONG* headOfStreamPlaceHolder; - ULONG ownerPropertyIndex; + DirRef ownerDirEntry; ULONG lastBlockNoInSequence; ULONG lastBlockNoInSequenceIndex; ULONG tailIndex; @@ -445,7 +454,7 @@ struct BlockChainStream BlockChainStream* BlockChainStream_Construct( StorageImpl* parentStorage, ULONG* headOfStreamPlaceHolder, - ULONG propertyIndex); + DirRef dirEntry); void BlockChainStream_Destroy( BlockChainStream* This); @@ -477,7 +486,7 @@ BOOL BlockChainStream_SetSize( struct SmallBlockChainStream { StorageImpl* parentStorage; - ULONG ownerPropertyIndex; + DirRef ownerDirEntry; ULONG* headOfStreamPlaceHolder; }; @@ -487,7 +496,7 @@ struct SmallBlockChainStream SmallBlockChainStream* SmallBlockChainStream_Construct( StorageImpl* parentStorage, ULONG* headOfStreamPlaceHolder, - ULONG propertyIndex); + DirRef dirEntry); void SmallBlockChainStream_Destroy( SmallBlockChainStream* This); diff --git a/dlls/ole32/stubmanager.c b/dlls/ole32/stubmanager.c index 12813c6a5d7..f6b8bfa1a86 100644 --- a/dlls/ole32/stubmanager.c +++ b/dlls/ole32/stubmanager.c @@ -406,13 +406,15 @@ ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs, BOOL tablewea rc = (m->extrefs -= refs); if (tableweak) - rc += --m->weakrefs; + --m->weakrefs; + if (!last_unlock_releases) + rc += m->weakrefs; LeaveCriticalSection(&m->lock); TRACE("removed %u refs from %p (oid %s), rc is now %u\n", refs, m, wine_dbgstr_longlong(m->oid), rc); - if (rc == 0 && last_unlock_releases) + if (rc == 0) stub_manager_int_release(m); return rc; @@ -551,7 +553,7 @@ void stub_manager_release_marshal_data(struct stub_manager *m, ULONG refs, const else if (ifstub->flags & MSHLFLAGS_TABLESTRONG) refs = 1; - stub_manager_ext_release(m, refs, tableweak, TRUE); + stub_manager_ext_release(m, refs, tableweak, FALSE); } /* is an ifstub table marshaled? */ diff --git a/dlls/ole32/tests/compobj.c b/dlls/ole32/tests/compobj.c index 442e7b0b323..9d469b4b174 100644 --- a/dlls/ole32/tests/compobj.c +++ b/dlls/ole32/tests/compobj.c @@ -261,6 +261,17 @@ static void test_CoCreateInstance(void) ok(pUnk == NULL, "CoCreateInstance should have changed the passed in pointer to NULL, instead of %p\n", pUnk); OleInitialize(NULL); + + /* test errors returned for non-registered clsids */ + hr = CoCreateInstance(&CLSID_non_existent, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk); + ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance for non-registered inproc server should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr); + hr = CoCreateInstance(&CLSID_non_existent, NULL, CLSCTX_INPROC_HANDLER, &IID_IUnknown, (void **)&pUnk); + ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance for non-registered inproc handler should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr); + hr = CoCreateInstance(&CLSID_non_existent, NULL, CLSCTX_LOCAL_SERVER, &IID_IUnknown, (void **)&pUnk); + ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance for non-registered local server should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr); + hr = CoCreateInstance(&CLSID_non_existent, NULL, CLSCTX_REMOTE_SERVER, &IID_IUnknown, (void **)&pUnk); + ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance for non-registered remote server should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr); + hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk); if(hr == REGDB_E_CLASSNOTREG) { @@ -837,6 +848,14 @@ static void test_CoRegisterClassObject(void) hr = CoRevokeClassObject(cookie); ok_ole_success(hr, "CoRevokeClassObject"); + /* test whether an object that doesn't support IClassFactory can be + * registered for CLSCTX_LOCAL_SERVER */ + hr = CoRegisterClassObject(&CLSID_WineOOPTest, &Test_Unknown, + CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie); + ok_ole_success(hr, "CoRegisterClassObject"); + hr = CoRevokeClassObject(cookie); + ok_ole_success(hr, "CoRevokeClassObject"); + /* test whether registered class becomes invalid when apartment is destroyed */ hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory, CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie); @@ -1415,7 +1434,7 @@ static void test_CoInitializeEx(void) /* Calling OleInitialize for the first time should yield S_OK even with * apartment already initialized by previous CoInitialize(Ex) calls. */ hr = OleInitialize(NULL); - todo_wine ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr); + ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr); /* Subsequent calls to OleInitialize should return S_FALSE */ hr = OleInitialize(NULL); diff --git a/dlls/ole32/tests/marshal.c b/dlls/ole32/tests/marshal.c index 4239b55ddc3..b4a238484be 100644 --- a/dlls/ole32/tests/marshal.c +++ b/dlls/ole32/tests/marshal.c @@ -1257,7 +1257,7 @@ static void test_lock_object_external(void) IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL); hr = CoReleaseMarshalData(pStream); ok_ole_success(hr, CoReleaseMarshalData); - IStream_Release(pStream); + IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL); ok_more_than_one_lock(); @@ -1268,6 +1268,39 @@ static void test_lock_object_external(void) CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, TRUE); ok_no_locks(); + + /* test CoLockObjectExternal releases reference to object with + * fLastUnlockReleases as TRUE and there are only strong references on + * the object */ + CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, FALSE); + + ok_more_than_one_lock(); + + CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, FALSE); + + ok_no_locks(); + + /* test CoLockObjectExternal doesn't release the last reference to an + * object with fLastUnlockReleases as TRUE and there is a weak reference + * on the object */ + hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_TABLEWEAK); + ok_ole_success(hr, CoMarshalInterface); + + ok_more_than_one_lock(); + + CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, FALSE); + + ok_more_than_one_lock(); + + CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, FALSE); + + ok_more_than_one_lock(); + + CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0); + + ok_no_locks(); + + IStream_Release(pStream); } /* tests disconnecting stubs */ @@ -2281,7 +2314,6 @@ static void test_inproc_handler(void) reg_unreg_wine_test_class(TRUE); hr = CoCreateInstance(&CLSID_WineTest, NULL, CLSCTX_INPROC_HANDLER, &IID_IUnknown, (void **)&pObject); - todo_wine ok_ole_success(hr, "CoCreateInstance"); if (SUCCEEDED(hr)) diff --git a/dlls/ole32/tests/storage32.c b/dlls/ole32/tests/storage32.c index e4783e8001d..53811dbb514 100644 --- a/dlls/ole32/tests/storage32.c +++ b/dlls/ole32/tests/storage32.c @@ -1060,35 +1060,31 @@ static void test_substorage_share(void) if (r == S_OK) { r = IStorage_OpenStorage(stg, stgname, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3); - todo_wine ok(r==STG_E_ACCESSDENIED, "IStorage->OpenStorage should fail %08x\n", r); + ok(r==STG_E_ACCESSDENIED, "IStorage->OpenStorage should fail %08x\n", r); if (r == S_OK) IStorage_Release(stg3); r = IStorage_OpenStorage(stg, stgname, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3); - todo_wine ok(r==STG_E_ACCESSDENIED, "IStorage->OpenStorage should fail %08x\n", r); + ok(r==STG_E_ACCESSDENIED, "IStorage->OpenStorage should fail %08x\n", r); if (r == S_OK) IStorage_Release(stg3); /* cannot rename the storage while it's open */ r = IStorage_RenameElement(stg, stgname, othername); - todo_wine ok(r==STG_E_ACCESSDENIED, "IStorage->RenameElement should fail %08x\n", r); + ok(r==STG_E_ACCESSDENIED, "IStorage->RenameElement should fail %08x\n", r); if (SUCCEEDED(r)) IStorage_RenameElement(stg, othername, stgname); -#if 0 - /* This crashes on Wine. */ - /* destroying an object while it's open invalidates it */ r = IStorage_DestroyElement(stg, stgname); ok(r==S_OK, "IStorage->DestroyElement failed, hr=%08x\n", r); r = IStorage_CreateStream(stg2, stmname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm); - todo_wine ok(r==STG_E_REVERTED, "IStorage->CreateStream failed, hr=%08x\n", r); + ok(r==STG_E_REVERTED, "IStorage->CreateStream failed, hr=%08x\n", r); if (r == S_OK) IStorage_Release(stm); -#endif IStorage_Release(stg2); } @@ -1100,20 +1096,20 @@ static void test_substorage_share(void) if (r == S_OK) { r = IStorage_OpenStream(stg, stmname, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stm2); - todo_wine ok(r==STG_E_ACCESSDENIED, "IStorage->OpenStream should fail %08x\n", r); + ok(r==STG_E_ACCESSDENIED, "IStorage->OpenStream should fail %08x\n", r); if (r == S_OK) IStorage_Release(stm2); r = IStorage_OpenStream(stg, stmname, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm2); - todo_wine ok(r==STG_E_ACCESSDENIED, "IStorage->OpenStream should fail %08x\n", r); + ok(r==STG_E_ACCESSDENIED, "IStorage->OpenStream should fail %08x\n", r); if (r == S_OK) IStorage_Release(stm2); /* cannot rename the stream while it's open */ r = IStorage_RenameElement(stg, stmname, othername); - todo_wine ok(r==STG_E_ACCESSDENIED, "IStorage->RenameElement should fail %08x\n", r); + ok(r==STG_E_ACCESSDENIED, "IStorage->RenameElement should fail %08x\n", r); if (SUCCEEDED(r)) IStorage_RenameElement(stg, othername, stmname); /* destroying an object while it's open invalidates it */ @@ -1121,7 +1117,7 @@ static void test_substorage_share(void) ok(r==S_OK, "IStorage->DestroyElement failed, hr=%08x\n", r); r = IStream_Write(stm, "this shouldn't work\n", 20, NULL); - todo_wine ok(r==STG_E_REVERTED, "IStream_Write should fail %08x\n", r); + ok(r==STG_E_REVERTED, "IStream_Write should fail %08x\n", r); IStorage_Release(stm); } @@ -1288,6 +1284,68 @@ static void test_revert(void) ok( r == TRUE, "deleted file\n"); } +static void test_parent_free(void) +{ + IStorage *stg = NULL, *stg2 = NULL, *stg3 = NULL; + HRESULT r; + IStream *stm = NULL; + static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 }; + static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 }; + ULONG ref; + STATSTG statstg; + + DeleteFileA(filenameA); + + /* create the file */ + r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE | + STGM_READWRITE |STGM_TRANSACTED, 0, &stg); + ok(r==S_OK, "StgCreateDocfile failed\n"); + + /* create a new storage */ + r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2); + ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r); + + if (r == S_OK) + { + /* now create a stream inside the new storage */ + r = IStorage_CreateStream(stg2, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm ); + ok(r==S_OK, "IStorage->CreateStream failed\n"); + + if (r == S_OK) + { + /* create a storage inside the new storage */ + r = IStorage_CreateStorage(stg2, stgname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stg3 ); + ok(r==S_OK, "IStorage->CreateStorage failed\n"); + } + + /* free the parent */ + ref = IStorage_Release(stg2); + ok(ref == 0, "IStorage still has %u references\n", ref); + + /* child objects are invalid */ + if (r == S_OK) + { + r = IStream_Write(stm, "this should fail\n", 17, NULL); + ok(r==STG_E_REVERTED, "IStream->Write sould fail, hr=%x\n", r); + + IStream_Release(stm); + + r = IStorage_Stat(stg3, &statstg, STATFLAG_NONAME); + ok(r==STG_E_REVERTED, "IStorage_Stat should fail %08x\n", r); + + r = IStorage_SetStateBits(stg3, 1, 1); + ok(r==STG_E_REVERTED, "IStorage_Stat should fail %08x\n", r); + + IStorage_Release(stg3); + } + } + + IStorage_Release(stg); + + r = DeleteFileA(filenameA); + ok( r == TRUE, "deleted file\n"); +} + static void test_nonroot_transacted(void) { IStorage *stg = NULL, *stg2 = NULL; @@ -2422,6 +2480,7 @@ START_TEST(storage32) test_transact(); test_substorage_share(); test_revert(); + test_parent_free(); test_nonroot_transacted(); test_ReadClassStm(); test_access(); diff --git a/dlls/ole32/usrmarshal.c b/dlls/ole32/usrmarshal.c index f180f42f8ca..ed316201f69 100644 --- a/dlls/ole32/usrmarshal.c +++ b/dlls/ole32/usrmarshal.c @@ -170,11 +170,9 @@ unsigned char * __RPC_USER CLIPFORMAT_UserMarshal(ULONG *pFlags, unsigned char * pBuffer += sizeof(UINT); *(UINT *)pBuffer = len; pBuffer += sizeof(UINT); - TRACE("marshaling format name %s\n", debugstr_wn(format, len-1)); - lstrcpynW((LPWSTR)pBuffer, format, len); + TRACE("marshaling format name %s\n", debugstr_w(format)); + memcpy(pBuffer, format, len * sizeof(WCHAR)); pBuffer += len * sizeof(WCHAR); - *(WCHAR *)pBuffer = '\0'; - pBuffer += sizeof(WCHAR); } else { @@ -238,11 +236,11 @@ unsigned char * __RPC_USER CLIPFORMAT_UserUnmarshal(ULONG *pFlags, unsigned char if (*(UINT *)pBuffer != len) RaiseException(RPC_S_INVALID_BOUND, 0, 0, NULL); pBuffer += sizeof(UINT); - if (((WCHAR *)pBuffer)[len] != '\0') + if (((WCHAR *)pBuffer)[len - 1] != '\0') RaiseException(RPC_S_INVALID_BOUND, 0, 0, NULL); TRACE("unmarshaling clip format %s\n", debugstr_w((LPCWSTR)pBuffer)); cf = RegisterClipboardFormatW((LPCWSTR)pBuffer); - pBuffer += (len + 1) * sizeof(WCHAR); + pBuffer += len * sizeof(WCHAR); if (!cf) RaiseException(DV_E_CLIPFORMAT, 0, 0, NULL); *pCF = cf; diff --git a/dlls/oleaut32/tests/tmarshal.c b/dlls/oleaut32/tests/tmarshal.c index c9ea77d4b85..46f1cdca766 100644 --- a/dlls/oleaut32/tests/tmarshal.c +++ b/dlls/oleaut32/tests/tmarshal.c @@ -587,6 +587,13 @@ static HRESULT WINAPI Widget_get_prop_uint( return S_OK; } +static HRESULT WINAPI Widget_ByRefUInt( + IWidget* iface, UINT *i) +{ + *i = 42; + return S_OK; +} + static const struct IWidgetVtbl Widget_VTable = { Widget_QueryInterface, @@ -618,7 +625,8 @@ static const struct IWidgetVtbl Widget_VTable = Widget_put_prop_with_lcid, Widget_get_prop_with_lcid, Widget_get_prop_int, - Widget_get_prop_uint + Widget_get_prop_uint, + Widget_ByRefUInt, }; static HRESULT WINAPI StaticWidget_QueryInterface(IStaticWidget *iface, REFIID riid, void **ppvObject) @@ -907,6 +915,7 @@ static ITypeInfo *NonOleAutomation_GetTypeInfo(void) ITypeInfo *pTypeInfo; hr = ITypeLib_GetTypeInfoOfGuid(pTypeLib, &IID_INonOleAutomation, &pTypeInfo); ok_ole_success(hr, ITypeLib_GetTypeInfoOfGuid); + ITypeLib_Release(pTypeLib); return pTypeInfo; } return NULL; @@ -935,6 +944,7 @@ static void test_typelibmarshal(void) ITypeInfo *pTypeInfo; MYSTRUCT mystruct; MYSTRUCT mystructArray[5]; + UINT uval; ok(pKEW != NULL, "Widget creation failed\n"); @@ -1251,10 +1261,8 @@ static void test_typelibmarshal(void) dispparams.cArgs = 1; dispparams.rgvarg = vararg; VariantInit(&varresult); -#if 0 /* NULL unknown not currently marshaled correctly */ hr = IDispatch_Invoke(pDispatch, DISPID_TM_NAME, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL); ok(hr == DISP_E_TYPEMISMATCH, "IDispatch_Invoke should have returned DISP_E_TYPEMISMATCH instead of 0x%08x\n", hr); -#endif VariantClear(&varresult); /* tests bad param type */ @@ -1342,6 +1350,24 @@ static void test_typelibmarshal(void) ok(V_UI4(&varresult) == 42, "got %x\n", V_UI4(&varresult)); VariantClear(&varresult); + /* test byref marshalling */ + uval = 666; + VariantInit(&vararg[0]); + V_VT(&vararg[0]) = VT_UI4|VT_BYREF; + V_UI4REF(&vararg[0]) = &uval; + dispparams.cNamedArgs = 0; + dispparams.cArgs = 1; + dispparams.rgvarg = vararg; + dispparams.rgdispidNamedArgs = NULL; + hr = IDispatch_Invoke(pDispatch, DISPID_TM_BYREF_UINT, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL); + ok_ole_success(hr, ITypeInfo_Invoke); + ok(V_VT(&varresult) == VT_EMPTY, "varresult should be VT_EMPTY\n"); + ok(V_VT(&vararg[0]) == (VT_UI4|VT_BYREF), "arg VT not unmarshalled correctly: %x\n", V_VT(&vararg[0])); + ok(V_UI4REF(&vararg[0]) == &uval, "Byref pointer not preserved: %p/%p\n", &uval, V_UI4REF(&vararg[0])); + ok(*V_UI4REF(&vararg[0]) == 42, "Expected 42 to be returned instead of %u\n", *V_UI4REF(&vararg[0])); + VariantClear(&varresult); + VariantClear(&vararg[0]); + IDispatch_Release(pDispatch); IWidget_Release(pWidget); diff --git a/dlls/oleaut32/tests/tmarshal.idl b/dlls/oleaut32/tests/tmarshal.idl index 71d53cf09ad..41079d0b2c9 100644 --- a/dlls/oleaut32/tests/tmarshal.idl +++ b/dlls/oleaut32/tests/tmarshal.idl @@ -137,6 +137,9 @@ library TestTypelib [id(DISPID_TM_PROP_UINT), propget] HRESULT prop_uint([out,retval] UINT *i); + + [id(DISPID_TM_BYREF_UINT)] + HRESULT ByRefUInt([in, out] UINT *i); } [ diff --git a/dlls/oleaut32/tests/tmarshal_dispids.h b/dlls/oleaut32/tests/tmarshal_dispids.h index 08d77360f80..1cfd87b27c8 100644 --- a/dlls/oleaut32/tests/tmarshal_dispids.h +++ b/dlls/oleaut32/tests/tmarshal_dispids.h @@ -37,5 +37,6 @@ #define DISPID_TM_PROP_WITH_LCID 18 #define DISPID_TM_PROP_INT 19 #define DISPID_TM_PROP_UINT 20 +#define DISPID_TM_BYREF_UINT 21 #define DISPID_NOA_BSTRRET 1 diff --git a/dlls/oleaut32/tests/vartest.c b/dlls/oleaut32/tests/vartest.c index 68a4edf8b9d..05f4be31ad3 100644 --- a/dlls/oleaut32/tests/vartest.c +++ b/dlls/oleaut32/tests/vartest.c @@ -1646,6 +1646,9 @@ static void test_VarDateFromUdate(void) UD2T(31,12,9999,0,0,0,0,0,0,0,S_OK,2958465.0); /* 31 Dec 9999 - Max */ UD2T(1,1,10000,0,0,0,0,0,0,0,E_INVALIDARG,0.0); /* > 31 Dec 9999 => err */ + UD2T(30,12,1899,0,0,0,0,0,0,0,S_OK,0.0); /* 30 Dec 1899 0:00:00 */ + UD2T(30,12,1899,0,0,0,999,0,0,0,S_OK,0.0); /* Ignore milliseconds */ + UD2T(1,1,1980,18,1,16,0,2,1,0,S_OK,29221.75087962963); /* 6:18:02 PM */ todo_wine UD2T(0,1,1980,42,1,16,0,2,1,0,S_OK,29221.75087962963); /* Test rolled hours */ todo_wine UD2T(1,1,1980,17,61,16,0,2,1,0,S_OK,29221.75087962963); /* Test rolled minutes */ diff --git a/dlls/oleaut32/tmarshal.c b/dlls/oleaut32/tmarshal.c index b3d1734e1d7..9f10981a834 100644 --- a/dlls/oleaut32/tmarshal.c +++ b/dlls/oleaut32/tmarshal.c @@ -615,8 +615,6 @@ serialize_param( vartype = VT_SAFEARRAY; switch (vartype) { - case VT_EMPTY: /* nothing. empty variant for instance */ - return S_OK; case VT_I8: case VT_UI8: case VT_R8: @@ -652,56 +650,23 @@ serialize_param( if (writeit) hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD)); return hres; - case VT_I4|VT_BYREF: - hres = S_OK; - if (debugout) TRACE_(olerelay)("&0x%x\n",*arg); - if (writeit) - hres = xbuf_add(buf,(LPBYTE)(DWORD*)*arg,sizeof(DWORD)); - /* do not dealloc at this time */ - return hres; case VT_VARIANT: { - TYPEDESC tdesc2; - VARIANT *vt = (VARIANT*)arg; - DWORD vttype = V_VT(vt); - - if (debugout) TRACE_(olerelay)("Vt(%s%s)(",debugstr_vt(vttype),debugstr_vf(vttype)); - tdesc2.vt = vttype; - if (writeit) { - hres = xbuf_add(buf,(LPBYTE)&vttype,sizeof(vttype)); - if (hres) return hres; - } - /* need to recurse since we need to free the stuff */ - hres = serialize_param(tinfo,writeit,debugout,dealloc,&tdesc2,(DWORD*)&(V_I4(vt)),buf); - if (debugout) TRACE_(olerelay)(")"); - return hres; - } - case VT_BSTR|VT_BYREF: { - if (debugout) TRACE_(olerelay)("[byref]'%s'", *(BSTR*)*arg ? relaystr(*((BSTR*)*arg)) : ""); - if (writeit) { - /* ptr to ptr to magic widestring, basically */ - BSTR *bstr = (BSTR *) *arg; - DWORD len; - if (!*bstr) { - /* -1 means "null string" which is equivalent to empty string */ - len = -1; - hres = xbuf_add(buf, (LPBYTE)&len,sizeof(DWORD)); - if (hres) return hres; - } else { - len = *((DWORD*)*bstr-1)/sizeof(WCHAR); - hres = xbuf_add(buf,(LPBYTE)&len,sizeof(DWORD)); - if (hres) return hres; - hres = xbuf_add(buf,(LPBYTE)*bstr,len * sizeof(WCHAR)); - if (hres) return hres; - } + if (debugout) TRACE_(olerelay)("Vt(%s%s)(",debugstr_vt(V_VT((VARIANT *)arg)),debugstr_vf(V_VT((VARIANT *)arg))); + if (writeit) + { + ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION); + ULONG size = VARIANT_UserSize(&flags, buf->curoff, (VARIANT *)arg); + xbuf_resize(buf, size); + VARIANT_UserMarshal(&flags, buf->base + buf->curoff, (VARIANT *)arg); + buf->curoff = size; } - - if (dealloc && arg) { - BSTR *str = *((BSTR **)arg); - SysFreeString(*str); + if (dealloc) + { + ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION); + VARIANT_UserFree(&flags, (VARIANT *)arg); } return S_OK; } - case VT_BSTR: { if (debugout) { if (*arg) @@ -709,25 +674,20 @@ serialize_param( else TRACE_(olerelay)(""); } - if (writeit) { - BSTR bstr = (BSTR)*arg; - DWORD len; - if (!bstr) { - len = -1; - hres = xbuf_add(buf,(LPBYTE)&len,sizeof(DWORD)); - if (hres) return hres; - } else { - len = *((DWORD*)bstr-1)/sizeof(WCHAR); - hres = xbuf_add(buf,(LPBYTE)&len,sizeof(DWORD)); - if (hres) return hres; - hres = xbuf_add(buf,(LPBYTE)bstr,len * sizeof(WCHAR)); - if (hres) return hres; - } - } - - if (dealloc && arg) - SysFreeString((BSTR)*arg); - return S_OK; + if (writeit) + { + ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION); + ULONG size = BSTR_UserSize(&flags, buf->curoff, (BSTR *)arg); + xbuf_resize(buf, size); + BSTR_UserMarshal(&flags, buf->base + buf->curoff, (BSTR *)arg); + buf->curoff = size; + } + if (dealloc) + { + ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION); + BSTR_UserFree(&flags, (BSTR *)arg); + } + return S_OK; } case VT_PTR: { DWORD cookie; @@ -894,6 +854,8 @@ serialize_param( if (debugout && (ibase + buf->curoff, (LPSAFEARRAY *)arg); buf->curoff = size; } + if (dealloc) + { + ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION); + LPSAFEARRAY_UserFree(&flags, (LPSAFEARRAY *)arg); + } return S_OK; } default: @@ -934,34 +901,15 @@ deserialize_param( while (1) { switch (vartype) { - case VT_EMPTY: - if (debugout) TRACE_(olerelay)("\n"); - return S_OK; - case VT_NULL: - if (debugout) TRACE_(olerelay)("\n"); - return S_OK; case VT_VARIANT: { - VARIANT *vt = (VARIANT*)arg; - - if (readit) { - DWORD vttype; - TYPEDESC tdesc2; - hres = xbuf_get(buf,(LPBYTE)&vttype,sizeof(vttype)); - if (hres) { - FIXME("vt type not read?\n"); - return hres; - } - memset(&tdesc2,0,sizeof(tdesc2)); - tdesc2.vt = vttype; - V_VT(vt) = vttype; - if (debugout) TRACE_(olerelay)("Vt(%s%s)(",debugstr_vt(vttype),debugstr_vf(vttype)); - hres = deserialize_param(tinfo, readit, debugout, alloc, &tdesc2, (DWORD*)&(V_I4(vt)), buf); - TRACE_(olerelay)(")"); - return hres; - } else { - VariantInit(vt); - return S_OK; + if (readit) + { + ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION); + unsigned char *buffer; + buffer = VARIANT_UserUnmarshal(&flags, buf->base + buf->curoff, (VARIANT *)arg); + buf->curoff = buffer - buf->base; } + return S_OK; } case VT_I8: case VT_UI8: @@ -1006,76 +954,14 @@ deserialize_param( } if (debugout) TRACE_(olerelay)("%02x",*arg & 0xff); return hres; - case VT_I4|VT_BYREF: - hres = S_OK; - if (alloc) - *arg = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD)); - if (readit) { - hres = xbuf_get(buf,(LPBYTE)*arg,sizeof(DWORD)); - if (hres) ERR("Failed to read integer 4 byte\n"); - } - if (debugout) TRACE_(olerelay)("&0x%x",*(DWORD*)*arg); - return hres; - case VT_BSTR|VT_BYREF: { - BSTR **bstr = (BSTR **)arg; - WCHAR *str; - DWORD len; - - if (readit) { - hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD)); - if (hres) { - ERR("failed to read bstr klen\n"); - return hres; - } - if (len == -1) { - *bstr = CoTaskMemAlloc(sizeof(BSTR *)); - **bstr = NULL; - if (debugout) TRACE_(olerelay)(""); - } else { - str = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(len+1)*sizeof(WCHAR)); - hres = xbuf_get(buf,(LPBYTE)str,len*sizeof(WCHAR)); - if (hres) { - ERR("Failed to read BSTR.\n"); - HeapFree(GetProcessHeap(),0,str); - return hres; - } - *bstr = CoTaskMemAlloc(sizeof(BSTR *)); - **bstr = SysAllocStringLen(str,len); - if (debugout) TRACE_(olerelay)("%s",relaystr(str)); - HeapFree(GetProcessHeap(),0,str); - } - } else { - *bstr = NULL; - } - return S_OK; - } case VT_BSTR: { - WCHAR *str; - DWORD len; - - if (readit) { - hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD)); - if (hres) { - ERR("failed to read bstr klen\n"); - return hres; - } - if (len == -1) { - *arg = 0; - if (debugout) TRACE_(olerelay)(""); - } else { - str = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(len+1)*sizeof(WCHAR)); - hres = xbuf_get(buf,(LPBYTE)str,len*sizeof(WCHAR)); - if (hres) { - ERR("Failed to read BSTR.\n"); - HeapFree(GetProcessHeap(),0,str); - return hres; - } - *arg = (DWORD)SysAllocStringLen(str,len); - if (debugout) TRACE_(olerelay)("%s",relaystr(str)); - HeapFree(GetProcessHeap(),0,str); - } - } else { - *arg = 0; + if (readit) + { + ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION); + unsigned char *buffer; + buffer = BSTR_UserUnmarshal(&flags, buf->base + buf->curoff, (BSTR *)arg); + buf->curoff = buffer - buf->base; + if (debugout) TRACE_(olerelay)("%s",relaystr(*(BSTR *)arg)); } return S_OK; } @@ -2105,7 +1991,7 @@ TMStubImpl_Invoke( nrofargs = 0; for (i=0;icParams;i++) nrofargs += _argsize(&fdesc->lprgelemdescParam[i].tdesc, tinfo); - args = HeapAlloc(GetProcessHeap(),0,(nrofargs+1)*sizeof(DWORD)); + args = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(nrofargs+1)*sizeof(DWORD)); if (!args) { hres = E_OUTOFMEMORY; diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index 07447f2c5a2..8f552dc0766 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -1048,7 +1048,7 @@ typedef struct tagITypeInfoImpl const ITypeInfo2Vtbl *lpVtbl; const ITypeCompVtbl *lpVtblTypeComp; LONG ref; - BOOL no_free_data; /* don't free data structures */ + BOOL not_attached_to_typelib; TYPEATTR TypeAttr ; /* _lots_ of type information. */ ITypeLibImpl * pTypeLib; /* back pointer to typelib */ int index; /* index in this typelib; */ @@ -1085,6 +1085,7 @@ static const ITypeInfo2Vtbl tinfvt; static const ITypeCompVtbl tcompvt; static ITypeInfo2 * ITypeInfo_Constructor(void); +static void ITypeInfo_fnDestroy(ITypeInfoImpl *This); typedef struct tagTLBContext { @@ -2991,6 +2992,7 @@ static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength) name = TLB_Alloc(size+1); MSFT_Read(name, size, &cx, DO_NOT_SEEK); (*ppImpLib)->name = TLB_MultiByteToBSTR(name); + TLB_Free(name); MSFT_ReadGuid(&(*ppImpLib)->guid, oGuid, &cx); offset = (offset + sizeof(INT) + sizeof(DWORD) + sizeof(LCID) + sizeof(UINT16) + size + 3) & ~3; @@ -4089,6 +4091,7 @@ static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface) TLBRefType *ref_type; void *cursor2; int i; + ITypeInfoImpl *pTI, *pTINext; /* remove cache entry */ if(This->path) @@ -4145,8 +4148,11 @@ static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface) TLB_Free(ref_type); } - if (This->pTypeInfo) /* can be NULL */ - ITypeInfo_Release((ITypeInfo*) This->pTypeInfo); + for (pTI = This->pTypeInfo; pTI; pTI = pTINext) + { + pTINext = pTI->next; + ITypeInfo_fnDestroy(pTI); + } HeapFree(GetProcessHeap(),0,This); return 0; } @@ -4887,7 +4893,7 @@ static ITypeInfo2 * ITypeInfo_Constructor(void) { pTypeInfoImpl->lpVtbl = &tinfvt; pTypeInfoImpl->lpVtblTypeComp = &tcompvt; - pTypeInfoImpl->ref=1; + pTypeInfoImpl->ref = 0; pTypeInfoImpl->hreftype = -1; pTypeInfoImpl->TypeAttr.memidConstructor = MEMBERID_NIL; pTypeInfoImpl->TypeAttr.memidDestructor = MEMBERID_NIL; @@ -4929,97 +4935,96 @@ static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface) ITypeInfoImpl *This = (ITypeInfoImpl *)iface; ULONG ref = InterlockedIncrement(&This->ref); - ITypeLib2_AddRef((ITypeLib2*)This->pTypeLib); - TRACE("(%p)->ref is %u\n",This, ref); + + if (ref == 1 /* incremented from 0 */) + ITypeLib2_AddRef((ITypeLib2*)This->pTypeLib); + return ref; } -/* ITypeInfo::Release - */ -static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface) +static void ITypeInfo_fnDestroy(ITypeInfoImpl *This) { - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - ULONG ref = InterlockedDecrement(&This->ref); - - TRACE("(%p)->(%u)\n",This, ref); + TLBFuncDesc *pFInfo, *pFInfoNext; + TLBVarDesc *pVInfo, *pVInfoNext; + TLBImplType *pImpl, *pImplNext; - if (ref) { - /* We don't release ITypeLib when ref=0 because - it means that function is called by ITypeLib2_Release */ - ITypeLib2_Release((ITypeLib2*)This->pTypeLib); - } else { - TLBFuncDesc *pFInfo, *pFInfoNext; - TLBVarDesc *pVInfo, *pVInfoNext; - TLBImplType *pImpl, *pImplNext; + TRACE("destroying ITypeInfo(%p)\n",This); - TRACE("destroying ITypeInfo(%p)\n",This); + SysFreeString(This->Name); + This->Name = NULL; - if (This->no_free_data) - goto finish_free; + SysFreeString(This->DocString); + This->DocString = NULL; - SysFreeString(This->Name); - This->Name = NULL; + SysFreeString(This->DllName); + This->DllName = NULL; - SysFreeString(This->DocString); - This->DocString = NULL; + for (pFInfo = This->funclist; pFInfo; pFInfo = pFInfoNext) + { + INT i; + for(i = 0;i < pFInfo->funcdesc.cParams; i++) + { + ELEMDESC *elemdesc = &pFInfo->funcdesc.lprgelemdescParam[i]; + if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) + { + VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue); + TLB_Free(elemdesc->u.paramdesc.pparamdescex); + } + SysFreeString(pFInfo->pParamDesc[i].Name); + } + TLB_Free(pFInfo->funcdesc.lprgelemdescParam); + TLB_Free(pFInfo->pParamDesc); + TLB_FreeCustData(pFInfo->pCustData); + if (HIWORD(pFInfo->Entry) != 0 && pFInfo->Entry != (BSTR)-1) + SysFreeString(pFInfo->Entry); + SysFreeString(pFInfo->HelpString); + SysFreeString(pFInfo->Name); + + pFInfoNext = pFInfo->next; + TLB_Free(pFInfo); + } + for (pVInfo = This->varlist; pVInfo; pVInfo = pVInfoNext) + { + if (pVInfo->vardesc.varkind == VAR_CONST) + { + VariantClear(pVInfo->vardesc.u.lpvarValue); + TLB_Free(pVInfo->vardesc.u.lpvarValue); + } + TLB_FreeCustData(pVInfo->pCustData); + SysFreeString(pVInfo->Name); + pVInfoNext = pVInfo->next; + TLB_Free(pVInfo); + } + for (pImpl = This->impltypelist; pImpl; pImpl = pImplNext) + { + TLB_FreeCustData(pImpl->pCustData); + pImplNext = pImpl->next; + TLB_Free(pImpl); + } + TLB_FreeCustData(This->pCustData); - SysFreeString(This->DllName); - This->DllName = NULL; + HeapFree(GetProcessHeap(), 0, This); +} - for (pFInfo = This->funclist; pFInfo; pFInfo = pFInfoNext) - { - INT i; - for(i = 0;i < pFInfo->funcdesc.cParams; i++) - { - ELEMDESC *elemdesc = &pFInfo->funcdesc.lprgelemdescParam[i]; - if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) - { - VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue); - TLB_Free(elemdesc->u.paramdesc.pparamdescex); - } - SysFreeString(pFInfo->pParamDesc[i].Name); - } - TLB_Free(pFInfo->funcdesc.lprgelemdescParam); - TLB_Free(pFInfo->pParamDesc); - TLB_FreeCustData(pFInfo->pCustData); - if (HIWORD(pFInfo->Entry) != 0 && pFInfo->Entry != (BSTR)-1) - SysFreeString(pFInfo->Entry); - SysFreeString(pFInfo->HelpString); - SysFreeString(pFInfo->Name); - - pFInfoNext = pFInfo->next; - TLB_Free(pFInfo); - } - for (pVInfo = This->varlist; pVInfo; pVInfo = pVInfoNext) - { - if (pVInfo->vardesc.varkind == VAR_CONST) - { - VariantClear(pVInfo->vardesc.u.lpvarValue); - TLB_Free(pVInfo->vardesc.u.lpvarValue); - } - TLB_FreeCustData(pVInfo->pCustData); - SysFreeString(pVInfo->Name); - pVInfoNext = pVInfo->next; - TLB_Free(pVInfo); - } - for(pImpl = This->impltypelist; pImpl; pImpl = pImplNext) - { - TLB_FreeCustData(pImpl->pCustData); - pImplNext = pImpl->next; - TLB_Free(pImpl); - } - TLB_FreeCustData(This->pCustData); +/* ITypeInfo::Release + */ +static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + ULONG ref = InterlockedDecrement(&This->ref); -finish_free: - if (This->next) - { - ITypeInfo_Release((ITypeInfo*)This->next); - } + TRACE("(%p)->(%u)\n",This, ref); - HeapFree(GetProcessHeap(),0,This); - return 0; + if (!ref) + { + BOOL not_attached_to_typelib = This->not_attached_to_typelib; + ITypeLib2_Release((ITypeLib2*)This->pTypeLib); + if (not_attached_to_typelib) + HeapFree(GetProcessHeap(), 0, This); + /* otherwise This will be freed when typelib is freed */ } + return ref; } @@ -6146,7 +6151,8 @@ static HRESULT WINAPI ITypeInfo_fnInvoke( else { VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams); - hres = VariantCopy(&missing_arg[i], src_arg); + if (wParamFlags & PARAMFLAG_FIN) + hres = VariantCopy(&missing_arg[i], src_arg); V_VARIANTREF(&rgvarg[i]) = &missing_arg[i]; } V_VT(&rgvarg[i]) = rgvt[i]; @@ -6184,8 +6190,10 @@ static HRESULT WINAPI ITypeInfo_fnInvoke( else if ((rgvt[i] & VT_BYREF) && !V_ISBYREF(src_arg)) { VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams); - V_VT(&missing_arg[i]) = V_VT(src_arg); - hres = VariantChangeType(&missing_arg[i], src_arg, 0, rgvt[i] & ~VT_BYREF); + if (wParamFlags & PARAMFLAG_FIN) + hres = VariantChangeType(&missing_arg[i], src_arg, 0, rgvt[i] & ~VT_BYREF); + else + V_VT(&missing_arg[i]) = rgvt[i] & ~VT_BYREF; V_BYREF(&rgvarg[i]) = &V_NONE(&missing_arg[i]); V_VT(&rgvarg[i]) = rgvt[i]; } @@ -6268,6 +6276,7 @@ static HRESULT WINAPI ITypeInfo_fnInvoke( for (i = 0; i < func_desc->cParams; i++) { USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags; + VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams); if (wParamFlags & PARAMFLAG_FLCID) continue; @@ -6286,33 +6295,23 @@ static HRESULT WINAPI ITypeInfo_fnInvoke( hres = VariantCopyInd(pVarResult, prgpvarg[i]); } - /* free data stored in varresult. Note that - * VariantClear doesn't do what we want because we are - * working with byref types. */ - /* FIXME: clear safearrays, bstrs, records and - * variants here too */ - if ((V_VT(prgpvarg[i]) == (VT_UNKNOWN | VT_BYREF)) || - (V_VT(prgpvarg[i]) == (VT_DISPATCH | VT_BYREF))) - { - if(*V_UNKNOWNREF(prgpvarg[i])) - IUnknown_Release(*V_UNKNOWNREF(prgpvarg[i])); - } - break; + VARIANT_ClearInd(prgpvarg[i]); } else if (vargs_converted < pDispParams->cArgs) { + VARIANTARG *arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted]; if (wParamFlags & PARAMFLAG_FOUT) { - VARIANTARG *arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted]; - - if ((rgvt[i] == VT_BYREF) && (V_VT(arg) != VT_BYREF)) + if ((rgvt[i] & VT_BYREF) && !(V_VT(arg) & VT_BYREF)) + { hres = VariantChangeType(arg, &rgvarg[i], 0, V_VT(arg)); - if (FAILED(hres)) - { - ERR("failed to convert param %d to vt %d\n", i, - V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted])); - break; + if (FAILED(hres)) + { + ERR("failed to convert param %d to vt %d\n", i, + V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted])); + break; + } } } else if (V_VT(prgpvarg[i]) == (VT_VARIANT | VT_ARRAY) && @@ -6351,6 +6350,8 @@ static HRESULT WINAPI ITypeInfo_fnInvoke( if (wParamFlags & PARAMFLAG_FHASDEFAULT) VariantClear(&rgvarg[i]); } + + VariantClear(&missing_arg[i]); } if ((V_VT(&varresult) == VT_ERROR) && FAILED(V_ERROR(&varresult))) @@ -6658,12 +6659,11 @@ static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo( *ppTInfo = (ITypeInfo*) pTypeInfoImpl; - /* we use data structures from This, so we need to keep a reference - * to it to stop it being destroyed and signal to the new instance to + /* the AddRef implicitly adds a reference to the parent typelib, which + * stops the copied data from being destroyed until the new typeinfo's + * refcount goes to zero, but we need to signal to the new instance to * not free its data structures when it is destroyed */ - pTypeInfoImpl->no_free_data = TRUE; - pTypeInfoImpl->next = This; - ITypeInfo_AddRef((ITypeInfo*) This); + pTypeInfoImpl->not_attached_to_typelib = TRUE; ITypeInfo_AddRef(*ppTInfo); diff --git a/dlls/oleaut32/usrmarshal.c b/dlls/oleaut32/usrmarshal.c index 3172ebad5fc..6ad9bd6d755 100644 --- a/dlls/oleaut32/usrmarshal.c +++ b/dlls/oleaut32/usrmarshal.c @@ -1180,6 +1180,8 @@ HRESULT CALLBACK IDispatch_Invoke_Proxy( if (V_ISBYREF(arg)) { rgVarRefIdx[cVarRef] = u; VariantInit(&rgVarRef[cVarRef]); + VariantCopy(&rgVarRef[cVarRef], arg); + VariantClear(arg); cVarRef++; } } @@ -1265,6 +1267,12 @@ HRESULT __RPC_STUB IDispatch_Invoke_Stub( } if (SUCCEEDED(hr)) { + /* copy ref args to arg array */ + for (u=0; urgvarg = arg; hr = IDispatch_Invoke(This, @@ -1277,14 +1285,10 @@ HRESULT __RPC_STUB IDispatch_Invoke_Stub( pExcepInfo, pArgErr); - /* copy ref args to out list */ + /* copy ref args from arg array */ for (u=0; u(%s%s))\n", pVarg, debugstr_VT(pVarg), debugstr_VF(pVarg)); + + hres = VARIANT_ValidateType(V_VT(pVarg)); + if (FAILED(hres)) + return hres; + + switch (V_VT(pVarg)) + { + case VT_DISPATCH: + case VT_UNKNOWN: + if (V_UNKNOWN(pVarg)) + IUnknown_Release(V_UNKNOWN(pVarg)); + break; + case VT_UNKNOWN | VT_BYREF: + case VT_DISPATCH | VT_BYREF: + if(*V_UNKNOWNREF(pVarg)) + IUnknown_Release(*V_UNKNOWNREF(pVarg)); + break; + case VT_BSTR: + SysFreeString(V_BSTR(pVarg)); + break; + case VT_BSTR | VT_BYREF: + SysFreeString(*V_BSTRREF(pVarg)); + break; + case VT_VARIANT | VT_BYREF: + VariantClear(V_VARIANTREF(pVarg)); + break; + case VT_RECORD: + case VT_RECORD | VT_BYREF: + { + struct __tagBRECORD* pBr = &V_UNION(pVarg,brecVal); + if (pBr->pRecInfo) + { + IRecordInfo_RecordClear(pBr->pRecInfo, pBr->pvRecord); + IRecordInfo_Release(pBr->pRecInfo); + } + break; + } + default: + if (V_ISARRAY(pVarg) || (V_VT(pVarg) & ~VT_BYREF) == VT_SAFEARRAY) + { + if (V_ISBYREF(pVarg)) + { + if (*V_ARRAYREF(pVarg)) + hres = SafeArrayDestroy(*V_ARRAYREF(pVarg)); + } + else if (V_ARRAY(pVarg)) + hres = SafeArrayDestroy(V_ARRAY(pVarg)); + } + break; + } + + V_VT(pVarg) = VT_EMPTY; + return hres; +} + /****************************************************************************** * VariantClear [OLEAUT32.9] * @@ -1328,7 +1388,6 @@ HRESULT WINAPI VarDateFromUdateEx(UDATE *pUdateIn, LCID lcid, ULONG dwFlags, DAT dateVal += ud.st.wHour / 24.0; dateVal += ud.st.wMinute / 1440.0; dateVal += ud.st.wSecond / 86400.0; - dateVal += ud.st.wMilliseconds / 86400000.0; TRACE("Returning %g\n", dateVal); *pDateOut = dateVal; diff --git a/dlls/oleaut32/variant.h b/dlls/oleaut32/variant.h index c881b24d60f..265fcc8041e 100644 --- a/dlls/oleaut32/variant.h +++ b/dlls/oleaut32/variant.h @@ -126,3 +126,4 @@ typedef struct tagVARIANT_NUMBER_CHARS BOOL VARIANT_GetLocalisedText(LANGID, DWORD, WCHAR *); +HRESULT VARIANT_ClearInd(VARIANTARG *); diff --git a/dlls/oledb32/tests/marshal.c b/dlls/oledb32/tests/marshal.c index 67fc7fd5eab..39d8448fa10 100644 --- a/dlls/oledb32/tests/marshal.c +++ b/dlls/oledb32/tests/marshal.c @@ -165,7 +165,6 @@ static HRESULT WINAPI Test_DBProperties_GetProperties( DBPROPSET **prgPropertySets) { ok(cPropertyIDSets == 0, "Expected cPropertyIDSets to be 0 instead of %d\n", cPropertyIDSets); - todo_wine ok(*pcPropertySets == 0, "Expected *pcPropertySets to be 0 instead of %d\n", *pcPropertySets); *pcPropertySets = 1; *prgPropertySets = CoTaskMemAlloc(sizeof(DBPROPSET)); @@ -243,7 +242,7 @@ static void test_IDBProperties(void) propset_count = 1; hr = IDBProperties_GetProperties(pProxy, 0, NULL, &propset_count, &propsets); - ok(hr == S_OK, "IDBProperties_GetProperties failed with error 0x%08x", hr); + ok(hr == S_OK, "IDBProperties_GetProperties failed with error 0x%08x\n", hr); ok(propset_count == 1, "Expected propset_count of 1 but got %d\n", propset_count); ok(propsets->rgProperties[0].dwPropertyID == TEST_PROPID, "Expected property ID of 0x%x, but got 0x%x\n", TEST_PROPID, propsets->rgProperties[0].dwPropertyID); diff --git a/dlls/opengl32/make_opengl b/dlls/opengl32/make_opengl index c98cd454650..d3ef4a79607 100755 --- a/dlls/opengl32/make_opengl +++ b/dlls/opengl32/make_opengl @@ -571,6 +571,9 @@ while (my $line = ) { if ($ext =~ /array/) { # This is a pointer $ptr = 1; + } elsif ($ext =~ /reference/) { + # This is a pointer + $ptr = 1; } elsif ($ext =~ /value/) { # And this a 'normal' value $ptr = 0; diff --git a/dlls/opengl32/opengl_ext.c b/dlls/opengl32/opengl_ext.c index 9c69ccdac3b..e446382b8f8 100644 --- a/dlls/opengl32/opengl_ext.c +++ b/dlls/opengl32/opengl_ext.c @@ -9,6 +9,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(opengl); enum extensions { + EXT_glActiveProgramEXT, EXT_glActiveStencilFaceEXT, EXT_glActiveTexture, EXT_glActiveTextureARB, @@ -35,6 +36,7 @@ enum extensions EXT_glBeginTransformFeedbackEXT, EXT_glBeginTransformFeedbackNV, EXT_glBeginVertexShaderEXT, + EXT_glBeginVideoCaptureNV, EXT_glBindAttribLocation, EXT_glBindAttribLocationARB, EXT_glBindBuffer, @@ -67,6 +69,8 @@ enum extensions EXT_glBindVertexArray, EXT_glBindVertexArrayAPPLE, EXT_glBindVertexShaderEXT, + EXT_glBindVideoCaptureStreamBufferNV, + EXT_glBindVideoCaptureStreamTextureNV, EXT_glBinormal3bEXT, EXT_glBinormal3bvEXT, EXT_glBinormal3dEXT, @@ -97,6 +101,7 @@ enum extensions EXT_glBlendFunci, EXT_glBlitFramebuffer, EXT_glBlitFramebufferEXT, + EXT_glBufferAddressRangeNV, EXT_glBufferData, EXT_glBufferDataARB, EXT_glBufferParameteriAPPLE, @@ -132,6 +137,7 @@ enum extensions EXT_glColor4ubVertex2fvSUN, EXT_glColor4ubVertex3fSUN, EXT_glColor4ubVertex3fvSUN, + EXT_glColorFormatNV, EXT_glColorFragmentOp1ATI, EXT_glColorFragmentOp2ATI, EXT_glColorFragmentOp3ATI, @@ -203,6 +209,7 @@ enum extensions EXT_glCopyConvolutionFilter1DEXT, EXT_glCopyConvolutionFilter2D, EXT_glCopyConvolutionFilter2DEXT, + EXT_glCopyImageSubDataNV, EXT_glCopyMultiTexImage1DEXT, EXT_glCopyMultiTexImage2DEXT, EXT_glCopyMultiTexSubImage1DEXT, @@ -223,6 +230,7 @@ enum extensions EXT_glCreateProgramObjectARB, EXT_glCreateShader, EXT_glCreateShaderObjectARB, + EXT_glCreateShaderProgramEXT, EXT_glCullParameterdvEXT, EXT_glCullParameterfvEXT, EXT_glCurrentPaletteMatrixARB, @@ -291,6 +299,7 @@ enum extensions EXT_glDrawRangeElementsBaseVertex, EXT_glDrawRangeElementsEXT, EXT_glDrawTransformFeedbackNV, + EXT_glEdgeFlagFormatNV, EXT_glEdgeFlagPointerEXT, EXT_glEdgeFlagPointerListIBM, EXT_glElementPointerAPPLE, @@ -313,6 +322,7 @@ enum extensions EXT_glEndTransformFeedbackEXT, EXT_glEndTransformFeedbackNV, EXT_glEndVertexShaderEXT, + EXT_glEndVideoCaptureNV, EXT_glEvalMapsNV, EXT_glExecuteProgramNV, EXT_glExtractComponentEXT, @@ -329,6 +339,7 @@ enum extensions EXT_glFlushRasterSGIX, EXT_glFlushVertexArrayRangeAPPLE, EXT_glFlushVertexArrayRangeNV, + EXT_glFogCoordFormatNV, EXT_glFogCoordPointer, EXT_glFogCoordPointerEXT, EXT_glFogCoordPointerListIBM, @@ -425,6 +436,7 @@ enum extensions EXT_glGetBufferParameteri64v, EXT_glGetBufferParameteriv, EXT_glGetBufferParameterivARB, + EXT_glGetBufferParameterui64vNV, EXT_glGetBufferPointerv, EXT_glGetBufferPointervARB, EXT_glGetBufferSubData, @@ -484,6 +496,8 @@ enum extensions EXT_glGetInteger64v, EXT_glGetIntegerIndexedvEXT, EXT_glGetIntegeri_v, + EXT_glGetIntegerui64i_vNV, + EXT_glGetIntegerui64vNV, EXT_glGetInvariantBooleanvEXT, EXT_glGetInvariantFloatvEXT, EXT_glGetInvariantIntegervEXT, @@ -518,6 +532,7 @@ enum extensions EXT_glGetMultisamplefv, EXT_glGetMultisamplefvNV, EXT_glGetNamedBufferParameterivEXT, + EXT_glGetNamedBufferParameterui64vNV, EXT_glGetNamedBufferPointervEXT, EXT_glGetNamedBufferSubDataEXT, EXT_glGetNamedFramebufferAttachmentParameterivEXT, @@ -611,6 +626,7 @@ enum extensions EXT_glGetUniformfvARB, EXT_glGetUniformiv, EXT_glGetUniformivARB, + EXT_glGetUniformui64vNV, EXT_glGetUniformuiv, EXT_glGetUniformuivEXT, EXT_glGetVariantArrayObjectfvATI, @@ -638,6 +654,10 @@ enum extensions EXT_glGetVertexAttribiv, EXT_glGetVertexAttribivARB, EXT_glGetVertexAttribivNV, + EXT_glGetVideoCaptureStreamdvNV, + EXT_glGetVideoCaptureStreamfvNV, + EXT_glGetVideoCaptureStreamivNV, + EXT_glGetVideoCaptureivNV, EXT_glGetVideoi64vNV, EXT_glGetVideoivNV, EXT_glGetVideoui64vNV, @@ -658,6 +678,7 @@ enum extensions EXT_glImageTransformParameterfvHP, EXT_glImageTransformParameteriHP, EXT_glImageTransformParameterivHP, + EXT_glIndexFormatNV, EXT_glIndexFuncEXT, EXT_glIndexMaterialEXT, EXT_glIndexPointerEXT, @@ -667,12 +688,14 @@ enum extensions EXT_glIsAsyncMarkerSGIX, EXT_glIsBuffer, EXT_glIsBufferARB, + EXT_glIsBufferResidentNV, EXT_glIsEnabledIndexedEXT, EXT_glIsEnabledi, EXT_glIsFenceAPPLE, EXT_glIsFenceNV, EXT_glIsFramebuffer, EXT_glIsFramebufferEXT, + EXT_glIsNamedBufferResidentNV, EXT_glIsObjectBufferATI, EXT_glIsOcclusionQueryNV, EXT_glIsProgram, @@ -706,6 +729,8 @@ enum extensions EXT_glLockArraysEXT, EXT_glMTexCoord2fSGIS, EXT_glMTexCoord2fvSGIS, + EXT_glMakeBufferNonResidentNV, + EXT_glMakeBufferResidentNV, EXT_glMapBuffer, EXT_glMapBufferARB, EXT_glMapBufferRange, @@ -896,6 +921,8 @@ enum extensions EXT_glNamedFramebufferTextureEXT, EXT_glNamedFramebufferTextureFaceEXT, EXT_glNamedFramebufferTextureLayerEXT, + EXT_glNamedMakeBufferNonResidentNV, + EXT_glNamedMakeBufferResidentNV, EXT_glNamedProgramLocalParameter4dEXT, EXT_glNamedProgramLocalParameter4dvEXT, EXT_glNamedProgramLocalParameter4fEXT, @@ -917,6 +944,7 @@ enum extensions EXT_glNormal3fVertex3fvSUN, EXT_glNormal3hNV, EXT_glNormal3hvNV, + EXT_glNormalFormatNV, EXT_glNormalPointerEXT, EXT_glNormalPointerListIBM, EXT_glNormalPointervINTEL, @@ -1039,6 +1067,8 @@ enum extensions EXT_glProgramUniformMatrix4fvEXT, EXT_glProgramUniformMatrix4x2fvEXT, EXT_glProgramUniformMatrix4x3fvEXT, + EXT_glProgramUniformui64NV, + EXT_glProgramUniformui64vNV, EXT_glProgramVertexLimitNV, EXT_glProvokingVertex, EXT_glProvokingVertexEXT, @@ -1124,6 +1154,7 @@ enum extensions EXT_glSecondaryColor3usEXT, EXT_glSecondaryColor3usv, EXT_glSecondaryColor3usvEXT, + EXT_glSecondaryColorFormatNV, EXT_glSecondaryColorPointer, EXT_glSecondaryColorPointerEXT, EXT_glSecondaryColorPointerListIBM, @@ -1202,6 +1233,7 @@ enum extensions EXT_glTexCoord4fVertex4fvSUN, EXT_glTexCoord4hNV, EXT_glTexCoord4hvNV, + EXT_glTexCoordFormatNV, EXT_glTexCoordPointerEXT, EXT_glTexCoordPointerListIBM, EXT_glTexCoordPointervINTEL, @@ -1221,6 +1253,7 @@ enum extensions EXT_glTexSubImage3D, EXT_glTexSubImage3DEXT, EXT_glTexSubImage4DSGIS, + EXT_glTextureBarrierNV, EXT_glTextureBufferEXT, EXT_glTextureColorMaskSGIS, EXT_glTextureImage1DEXT, @@ -1307,6 +1340,8 @@ enum extensions EXT_glUniformMatrix4fvARB, EXT_glUniformMatrix4x2fv, EXT_glUniformMatrix4x3fv, + EXT_glUniformui64NV, + EXT_glUniformui64vNV, EXT_glUnlockArraysEXT, EXT_glUnmapBuffer, EXT_glUnmapBufferARB, @@ -1315,6 +1350,7 @@ enum extensions EXT_glUpdateObjectBufferATI, EXT_glUseProgram, EXT_glUseProgramObjectARB, + EXT_glUseShaderProgramEXT, EXT_glValidateProgram, EXT_glValidateProgramARB, EXT_glVariantArrayObjectATI, @@ -1444,6 +1480,7 @@ enum extensions EXT_glVertexAttrib4usvARB, EXT_glVertexAttribArrayObjectATI, EXT_glVertexAttribDivisorARB, + EXT_glVertexAttribFormatNV, EXT_glVertexAttribI1i, EXT_glVertexAttribI1iEXT, EXT_glVertexAttribI1iv, @@ -1484,6 +1521,7 @@ enum extensions EXT_glVertexAttribI4uivEXT, EXT_glVertexAttribI4usv, EXT_glVertexAttribI4usvEXT, + EXT_glVertexAttribIFormatNV, EXT_glVertexAttribIPointer, EXT_glVertexAttribIPointerEXT, EXT_glVertexAttribPointer, @@ -1509,6 +1547,7 @@ enum extensions EXT_glVertexBlendARB, EXT_glVertexBlendEnvfATI, EXT_glVertexBlendEnviATI, + EXT_glVertexFormatNV, EXT_glVertexPointerEXT, EXT_glVertexPointerListIBM, EXT_glVertexPointervINTEL, @@ -1549,6 +1588,10 @@ enum extensions EXT_glVertexWeightfvEXT, EXT_glVertexWeighthNV, EXT_glVertexWeighthvNV, + EXT_glVideoCaptureNV, + EXT_glVideoCaptureStreamParameterdvNV, + EXT_glVideoCaptureStreamParameterfvNV, + EXT_glVideoCaptureStreamParameterivNV, EXT_glWaitSync, EXT_glWeightPointerARB, EXT_glWeightbvARB, @@ -1623,6 +1666,14 @@ const int extension_registry_size = NB_EXTENSIONS; void *extension_funcs[NB_EXTENSIONS]; /* The thunks themselves....*/ +static void WINAPI wine_glActiveProgramEXT( GLuint program ) { + void (*func_glActiveProgramEXT)( GLuint ) = extension_funcs[EXT_glActiveProgramEXT]; + TRACE("(%d)\n", program ); + ENTER_GL(); + func_glActiveProgramEXT( program ); + LEAVE_GL(); +} + static void WINAPI wine_glActiveStencilFaceEXT( GLenum face ) { void (*func_glActiveStencilFaceEXT)( GLenum ) = extension_funcs[EXT_glActiveStencilFaceEXT]; TRACE("(%d)\n", face ); @@ -1835,6 +1886,14 @@ static void WINAPI wine_glBeginVertexShaderEXT( void ) { LEAVE_GL(); } +static void WINAPI wine_glBeginVideoCaptureNV( GLuint video_capture_slot ) { + void (*func_glBeginVideoCaptureNV)( GLuint ) = extension_funcs[EXT_glBeginVideoCaptureNV]; + TRACE("(%d)\n", video_capture_slot ); + ENTER_GL(); + func_glBeginVideoCaptureNV( video_capture_slot ); + LEAVE_GL(); +} + static void WINAPI wine_glBindAttribLocation( GLuint program, GLuint index, char* name ) { void (*func_glBindAttribLocation)( GLuint, GLuint, char* ) = extension_funcs[EXT_glBindAttribLocation]; TRACE("(%d, %d, %p)\n", program, index, name ); @@ -2101,6 +2160,22 @@ static void WINAPI wine_glBindVertexShaderEXT( GLuint id ) { LEAVE_GL(); } +static void WINAPI wine_glBindVideoCaptureStreamBufferNV( GLuint video_capture_slot, GLuint stream, GLenum frame_region, INT_PTR offset ) { + void (*func_glBindVideoCaptureStreamBufferNV)( GLuint, GLuint, GLenum, INT_PTR ) = extension_funcs[EXT_glBindVideoCaptureStreamBufferNV]; + TRACE("(%d, %d, %d, %ld)\n", video_capture_slot, stream, frame_region, offset ); + ENTER_GL(); + func_glBindVideoCaptureStreamBufferNV( video_capture_slot, stream, frame_region, offset ); + LEAVE_GL(); +} + +static void WINAPI wine_glBindVideoCaptureStreamTextureNV( GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLenum target, GLuint texture ) { + void (*func_glBindVideoCaptureStreamTextureNV)( GLuint, GLuint, GLenum, GLenum, GLuint ) = extension_funcs[EXT_glBindVideoCaptureStreamTextureNV]; + TRACE("(%d, %d, %d, %d, %d)\n", video_capture_slot, stream, frame_region, target, texture ); + ENTER_GL(); + func_glBindVideoCaptureStreamTextureNV( video_capture_slot, stream, frame_region, target, texture ); + LEAVE_GL(); +} + static void WINAPI wine_glBinormal3bEXT( GLbyte bx, GLbyte by, GLbyte bz ) { void (*func_glBinormal3bEXT)( GLbyte, GLbyte, GLbyte ) = extension_funcs[EXT_glBinormal3bEXT]; TRACE("(%d, %d, %d)\n", bx, by, bz ); @@ -2341,6 +2416,14 @@ static void WINAPI wine_glBlitFramebufferEXT( GLint srcX0, GLint srcY0, GLint sr LEAVE_GL(); } +static void WINAPI wine_glBufferAddressRangeNV( GLenum pname, GLuint index, UINT64 address, INT_PTR length ) { + void (*func_glBufferAddressRangeNV)( GLenum, GLuint, UINT64, INT_PTR ) = extension_funcs[EXT_glBufferAddressRangeNV]; + TRACE("(%d, %d, %s, %ld)\n", pname, index, wine_dbgstr_longlong(address), length ); + ENTER_GL(); + func_glBufferAddressRangeNV( pname, index, address, length ); + LEAVE_GL(); +} + static void WINAPI wine_glBufferData( GLenum target, INT_PTR size, GLvoid* data, GLenum usage ) { void (*func_glBufferData)( GLenum, INT_PTR, GLvoid*, GLenum ) = extension_funcs[EXT_glBufferData]; TRACE("(%d, %ld, %p, %d)\n", target, size, data, usage ); @@ -2631,6 +2714,14 @@ static void WINAPI wine_glColor4ubVertex3fvSUN( GLubyte* c, GLfloat* v ) { LEAVE_GL(); } +static void WINAPI wine_glColorFormatNV( GLint size, GLenum type, GLsizei stride ) { + void (*func_glColorFormatNV)( GLint, GLenum, GLsizei ) = extension_funcs[EXT_glColorFormatNV]; + TRACE("(%d, %d, %d)\n", size, type, stride ); + ENTER_GL(); + func_glColorFormatNV( size, type, stride ); + LEAVE_GL(); +} + static void WINAPI wine_glColorFragmentOp1ATI( GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod ) { void (*func_glColorFragmentOp1ATI)( GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint ) = extension_funcs[EXT_glColorFragmentOp1ATI]; TRACE("(%d, %d, %d, %d, %d, %d, %d)\n", op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod ); @@ -3199,6 +3290,14 @@ static void WINAPI wine_glCopyConvolutionFilter2DEXT( GLenum target, GLenum inte LEAVE_GL(); } +static void WINAPI wine_glCopyImageSubDataNV( GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth ) { + void (*func_glCopyImageSubDataNV)( GLuint, GLenum, GLint, GLint, GLint, GLint, GLuint, GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei ) = extension_funcs[EXT_glCopyImageSubDataNV]; + TRACE("(%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d)\n", srcName, srcTarget, srcLevel, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, width, height, depth ); + ENTER_GL(); + func_glCopyImageSubDataNV( srcName, srcTarget, srcLevel, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, width, height, depth ); + LEAVE_GL(); +} + static void WINAPI wine_glCopyMultiTexImage1DEXT( GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border ) { void (*func_glCopyMultiTexImage1DEXT)( GLenum, GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLint ) = extension_funcs[EXT_glCopyMultiTexImage1DEXT]; TRACE("(%d, %d, %d, %d, %d, %d, %d, %d)\n", texunit, target, level, internalformat, x, y, width, border ); @@ -3367,6 +3466,16 @@ static unsigned int WINAPI wine_glCreateShaderObjectARB( GLenum shaderType ) { return ret_value; } +static GLuint WINAPI wine_glCreateShaderProgramEXT( GLenum type, char* string ) { + GLuint ret_value; + GLuint (*func_glCreateShaderProgramEXT)( GLenum, char* ) = extension_funcs[EXT_glCreateShaderProgramEXT]; + TRACE("(%d, %p)\n", type, string ); + ENTER_GL(); + ret_value = func_glCreateShaderProgramEXT( type, string ); + LEAVE_GL(); + return ret_value; +} + static void WINAPI wine_glCullParameterdvEXT( GLenum pname, GLdouble* params ) { void (*func_glCullParameterdvEXT)( GLenum, GLdouble* ) = extension_funcs[EXT_glCullParameterdvEXT]; TRACE("(%d, %p)\n", pname, params ); @@ -3911,6 +4020,14 @@ static void WINAPI wine_glDrawTransformFeedbackNV( GLenum mode, GLuint id ) { LEAVE_GL(); } +static void WINAPI wine_glEdgeFlagFormatNV( GLsizei stride ) { + void (*func_glEdgeFlagFormatNV)( GLsizei ) = extension_funcs[EXT_glEdgeFlagFormatNV]; + TRACE("(%d)\n", stride ); + ENTER_GL(); + func_glEdgeFlagFormatNV( stride ); + LEAVE_GL(); +} + static void WINAPI wine_glEdgeFlagPointerEXT( GLsizei stride, GLsizei count, GLboolean* pointer ) { void (*func_glEdgeFlagPointerEXT)( GLsizei, GLsizei, GLboolean* ) = extension_funcs[EXT_glEdgeFlagPointerEXT]; TRACE("(%d, %d, %p)\n", stride, count, pointer ); @@ -4087,6 +4204,14 @@ static void WINAPI wine_glEndVertexShaderEXT( void ) { LEAVE_GL(); } +static void WINAPI wine_glEndVideoCaptureNV( GLuint video_capture_slot ) { + void (*func_glEndVideoCaptureNV)( GLuint ) = extension_funcs[EXT_glEndVideoCaptureNV]; + TRACE("(%d)\n", video_capture_slot ); + ENTER_GL(); + func_glEndVideoCaptureNV( video_capture_slot ); + LEAVE_GL(); +} + static void WINAPI wine_glEvalMapsNV( GLenum target, GLenum mode ) { void (*func_glEvalMapsNV)( GLenum, GLenum ) = extension_funcs[EXT_glEvalMapsNV]; TRACE("(%d, %d)\n", target, mode ); @@ -4219,6 +4344,14 @@ static void WINAPI wine_glFlushVertexArrayRangeNV( void ) { LEAVE_GL(); } +static void WINAPI wine_glFogCoordFormatNV( GLenum type, GLsizei stride ) { + void (*func_glFogCoordFormatNV)( GLenum, GLsizei ) = extension_funcs[EXT_glFogCoordFormatNV]; + TRACE("(%d, %d)\n", type, stride ); + ENTER_GL(); + func_glFogCoordFormatNV( type, stride ); + LEAVE_GL(); +} + static void WINAPI wine_glFogCoordPointer( GLenum type, GLsizei stride, GLvoid* pointer ) { void (*func_glFogCoordPointer)( GLenum, GLsizei, GLvoid* ) = extension_funcs[EXT_glFogCoordPointer]; TRACE("(%d, %d, %p)\n", type, stride, pointer ); @@ -4999,6 +5132,14 @@ static void WINAPI wine_glGetBufferParameterivARB( GLenum target, GLenum pname, LEAVE_GL(); } +static void WINAPI wine_glGetBufferParameterui64vNV( GLenum target, GLenum pname, UINT64* params ) { + void (*func_glGetBufferParameterui64vNV)( GLenum, GLenum, UINT64* ) = extension_funcs[EXT_glGetBufferParameterui64vNV]; + TRACE("(%d, %d, %p)\n", target, pname, params ); + ENTER_GL(); + func_glGetBufferParameterui64vNV( target, pname, params ); + LEAVE_GL(); +} + static void WINAPI wine_glGetBufferPointerv( GLenum target, GLenum pname, GLvoid** params ) { void (*func_glGetBufferPointerv)( GLenum, GLenum, GLvoid** ) = extension_funcs[EXT_glGetBufferPointerv]; TRACE("(%d, %d, %p)\n", target, pname, params ); @@ -5479,6 +5620,22 @@ static void WINAPI wine_glGetIntegeri_v( GLenum target, GLuint index, GLint* dat LEAVE_GL(); } +static void WINAPI wine_glGetIntegerui64i_vNV( GLenum value, GLuint index, UINT64* result ) { + void (*func_glGetIntegerui64i_vNV)( GLenum, GLuint, UINT64* ) = extension_funcs[EXT_glGetIntegerui64i_vNV]; + TRACE("(%d, %d, %p)\n", value, index, result ); + ENTER_GL(); + func_glGetIntegerui64i_vNV( value, index, result ); + LEAVE_GL(); +} + +static void WINAPI wine_glGetIntegerui64vNV( GLenum value, UINT64* result ) { + void (*func_glGetIntegerui64vNV)( GLenum, UINT64* ) = extension_funcs[EXT_glGetIntegerui64vNV]; + TRACE("(%d, %p)\n", value, result ); + ENTER_GL(); + func_glGetIntegerui64vNV( value, result ); + LEAVE_GL(); +} + static void WINAPI wine_glGetInvariantBooleanvEXT( GLuint id, GLenum value, GLboolean* data ) { void (*func_glGetInvariantBooleanvEXT)( GLuint, GLenum, GLboolean* ) = extension_funcs[EXT_glGetInvariantBooleanvEXT]; TRACE("(%d, %d, %p)\n", id, value, data ); @@ -5751,6 +5908,14 @@ static void WINAPI wine_glGetNamedBufferParameterivEXT( GLuint buffer, GLenum pn LEAVE_GL(); } +static void WINAPI wine_glGetNamedBufferParameterui64vNV( GLuint buffer, GLenum pname, UINT64* params ) { + void (*func_glGetNamedBufferParameterui64vNV)( GLuint, GLenum, UINT64* ) = extension_funcs[EXT_glGetNamedBufferParameterui64vNV]; + TRACE("(%d, %d, %p)\n", buffer, pname, params ); + ENTER_GL(); + func_glGetNamedBufferParameterui64vNV( buffer, pname, params ); + LEAVE_GL(); +} + static void WINAPI wine_glGetNamedBufferPointervEXT( GLuint buffer, GLenum pname, GLvoid** params ) { void (*func_glGetNamedBufferPointervEXT)( GLuint, GLenum, GLvoid** ) = extension_funcs[EXT_glGetNamedBufferPointervEXT]; TRACE("(%d, %d, %p)\n", buffer, pname, params ); @@ -6507,6 +6672,14 @@ static void WINAPI wine_glGetUniformivARB( unsigned int programObj, GLint locati LEAVE_GL(); } +static void WINAPI wine_glGetUniformui64vNV( GLuint program, GLint location, UINT64* params ) { + void (*func_glGetUniformui64vNV)( GLuint, GLint, UINT64* ) = extension_funcs[EXT_glGetUniformui64vNV]; + TRACE("(%d, %d, %p)\n", program, location, params ); + ENTER_GL(); + func_glGetUniformui64vNV( program, location, params ); + LEAVE_GL(); +} + static void WINAPI wine_glGetUniformuiv( GLuint program, GLint location, GLuint* params ) { void (*func_glGetUniformuiv)( GLuint, GLint, GLuint* ) = extension_funcs[EXT_glGetUniformuiv]; TRACE("(%d, %d, %p)\n", program, location, params ); @@ -6725,6 +6898,38 @@ static void WINAPI wine_glGetVertexAttribivNV( GLuint index, GLenum pname, GLint LEAVE_GL(); } +static void WINAPI wine_glGetVideoCaptureStreamdvNV( GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble* params ) { + void (*func_glGetVideoCaptureStreamdvNV)( GLuint, GLuint, GLenum, GLdouble* ) = extension_funcs[EXT_glGetVideoCaptureStreamdvNV]; + TRACE("(%d, %d, %d, %p)\n", video_capture_slot, stream, pname, params ); + ENTER_GL(); + func_glGetVideoCaptureStreamdvNV( video_capture_slot, stream, pname, params ); + LEAVE_GL(); +} + +static void WINAPI wine_glGetVideoCaptureStreamfvNV( GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat* params ) { + void (*func_glGetVideoCaptureStreamfvNV)( GLuint, GLuint, GLenum, GLfloat* ) = extension_funcs[EXT_glGetVideoCaptureStreamfvNV]; + TRACE("(%d, %d, %d, %p)\n", video_capture_slot, stream, pname, params ); + ENTER_GL(); + func_glGetVideoCaptureStreamfvNV( video_capture_slot, stream, pname, params ); + LEAVE_GL(); +} + +static void WINAPI wine_glGetVideoCaptureStreamivNV( GLuint video_capture_slot, GLuint stream, GLenum pname, GLint* params ) { + void (*func_glGetVideoCaptureStreamivNV)( GLuint, GLuint, GLenum, GLint* ) = extension_funcs[EXT_glGetVideoCaptureStreamivNV]; + TRACE("(%d, %d, %d, %p)\n", video_capture_slot, stream, pname, params ); + ENTER_GL(); + func_glGetVideoCaptureStreamivNV( video_capture_slot, stream, pname, params ); + LEAVE_GL(); +} + +static void WINAPI wine_glGetVideoCaptureivNV( GLuint video_capture_slot, GLenum pname, GLint* params ) { + void (*func_glGetVideoCaptureivNV)( GLuint, GLenum, GLint* ) = extension_funcs[EXT_glGetVideoCaptureivNV]; + TRACE("(%d, %d, %p)\n", video_capture_slot, pname, params ); + ENTER_GL(); + func_glGetVideoCaptureivNV( video_capture_slot, pname, params ); + LEAVE_GL(); +} + static void WINAPI wine_glGetVideoi64vNV( GLuint video_slot, GLenum pname, INT64* params ) { void (*func_glGetVideoi64vNV)( GLuint, GLenum, INT64* ) = extension_funcs[EXT_glGetVideoi64vNV]; TRACE("(%d, %d, %p)\n", video_slot, pname, params ); @@ -6885,6 +7090,14 @@ static void WINAPI wine_glImageTransformParameterivHP( GLenum target, GLenum pna LEAVE_GL(); } +static void WINAPI wine_glIndexFormatNV( GLenum type, GLsizei stride ) { + void (*func_glIndexFormatNV)( GLenum, GLsizei ) = extension_funcs[EXT_glIndexFormatNV]; + TRACE("(%d, %d)\n", type, stride ); + ENTER_GL(); + func_glIndexFormatNV( type, stride ); + LEAVE_GL(); +} + static void WINAPI wine_glIndexFuncEXT( GLenum func, GLclampf ref ) { void (*func_glIndexFuncEXT)( GLenum, GLclampf ) = extension_funcs[EXT_glIndexFuncEXT]; TRACE("(%d, %f)\n", func, ref ); @@ -6963,6 +7176,16 @@ static GLboolean WINAPI wine_glIsBufferARB( GLuint buffer ) { return ret_value; } +static GLboolean WINAPI wine_glIsBufferResidentNV( GLenum target ) { + GLboolean ret_value; + GLboolean (*func_glIsBufferResidentNV)( GLenum ) = extension_funcs[EXT_glIsBufferResidentNV]; + TRACE("(%d)\n", target ); + ENTER_GL(); + ret_value = func_glIsBufferResidentNV( target ); + LEAVE_GL(); + return ret_value; +} + static GLboolean WINAPI wine_glIsEnabledIndexedEXT( GLenum target, GLuint index ) { GLboolean ret_value; GLboolean (*func_glIsEnabledIndexedEXT)( GLenum, GLuint ) = extension_funcs[EXT_glIsEnabledIndexedEXT]; @@ -7023,6 +7246,16 @@ static GLboolean WINAPI wine_glIsFramebufferEXT( GLuint framebuffer ) { return ret_value; } +static GLboolean WINAPI wine_glIsNamedBufferResidentNV( GLuint buffer ) { + GLboolean ret_value; + GLboolean (*func_glIsNamedBufferResidentNV)( GLuint ) = extension_funcs[EXT_glIsNamedBufferResidentNV]; + TRACE("(%d)\n", buffer ); + ENTER_GL(); + ret_value = func_glIsNamedBufferResidentNV( buffer ); + LEAVE_GL(); + return ret_value; +} + static GLboolean WINAPI wine_glIsObjectBufferATI( GLuint buffer ) { GLboolean ret_value; GLboolean (*func_glIsObjectBufferATI)( GLuint ) = extension_funcs[EXT_glIsObjectBufferATI]; @@ -7321,6 +7554,22 @@ static void WINAPI wine_glMTexCoord2fvSGIS( GLenum target, GLfloat * v ) { LEAVE_GL(); } +static void WINAPI wine_glMakeBufferNonResidentNV( GLenum target ) { + void (*func_glMakeBufferNonResidentNV)( GLenum ) = extension_funcs[EXT_glMakeBufferNonResidentNV]; + TRACE("(%d)\n", target ); + ENTER_GL(); + func_glMakeBufferNonResidentNV( target ); + LEAVE_GL(); +} + +static void WINAPI wine_glMakeBufferResidentNV( GLenum target, GLenum access ) { + void (*func_glMakeBufferResidentNV)( GLenum, GLenum ) = extension_funcs[EXT_glMakeBufferResidentNV]; + TRACE("(%d, %d)\n", target, access ); + ENTER_GL(); + func_glMakeBufferResidentNV( target, access ); + LEAVE_GL(); +} + static GLvoid* WINAPI wine_glMapBuffer( GLenum target, GLenum access ) { GLvoid* ret_value; GLvoid* (*func_glMapBuffer)( GLenum, GLenum ) = extension_funcs[EXT_glMapBuffer]; @@ -8851,6 +9100,22 @@ static void WINAPI wine_glNamedFramebufferTextureLayerEXT( GLuint framebuffer, G LEAVE_GL(); } +static void WINAPI wine_glNamedMakeBufferNonResidentNV( GLuint buffer ) { + void (*func_glNamedMakeBufferNonResidentNV)( GLuint ) = extension_funcs[EXT_glNamedMakeBufferNonResidentNV]; + TRACE("(%d)\n", buffer ); + ENTER_GL(); + func_glNamedMakeBufferNonResidentNV( buffer ); + LEAVE_GL(); +} + +static void WINAPI wine_glNamedMakeBufferResidentNV( GLuint buffer, GLenum access ) { + void (*func_glNamedMakeBufferResidentNV)( GLuint, GLenum ) = extension_funcs[EXT_glNamedMakeBufferResidentNV]; + TRACE("(%d, %d)\n", buffer, access ); + ENTER_GL(); + func_glNamedMakeBufferResidentNV( buffer, access ); + LEAVE_GL(); +} + static void WINAPI wine_glNamedProgramLocalParameter4dEXT( GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w ) { void (*func_glNamedProgramLocalParameter4dEXT)( GLuint, GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble ) = extension_funcs[EXT_glNamedProgramLocalParameter4dEXT]; TRACE("(%d, %d, %d, %f, %f, %f, %f)\n", program, target, index, x, y, z, w ); @@ -9023,6 +9288,14 @@ static void WINAPI wine_glNormal3hvNV( unsigned short* v ) { LEAVE_GL(); } +static void WINAPI wine_glNormalFormatNV( GLenum type, GLsizei stride ) { + void (*func_glNormalFormatNV)( GLenum, GLsizei ) = extension_funcs[EXT_glNormalFormatNV]; + TRACE("(%d, %d)\n", type, stride ); + ENTER_GL(); + func_glNormalFormatNV( type, stride ); + LEAVE_GL(); +} + static void WINAPI wine_glNormalPointerEXT( GLenum type, GLsizei stride, GLsizei count, GLvoid* pointer ) { void (*func_glNormalPointerEXT)( GLenum, GLsizei, GLsizei, GLvoid* ) = extension_funcs[EXT_glNormalPointerEXT]; TRACE("(%d, %d, %d, %p)\n", type, stride, count, pointer ); @@ -10007,6 +10280,22 @@ static void WINAPI wine_glProgramUniformMatrix4x3fvEXT( GLuint program, GLint lo LEAVE_GL(); } +static void WINAPI wine_glProgramUniformui64NV( GLuint program, GLint location, UINT64 value ) { + void (*func_glProgramUniformui64NV)( GLuint, GLint, UINT64 ) = extension_funcs[EXT_glProgramUniformui64NV]; + TRACE("(%d, %d, %s)\n", program, location, wine_dbgstr_longlong(value) ); + ENTER_GL(); + func_glProgramUniformui64NV( program, location, value ); + LEAVE_GL(); +} + +static void WINAPI wine_glProgramUniformui64vNV( GLuint program, GLint location, GLsizei count, UINT64* value ) { + void (*func_glProgramUniformui64vNV)( GLuint, GLint, GLsizei, UINT64* ) = extension_funcs[EXT_glProgramUniformui64vNV]; + TRACE("(%d, %d, %d, %p)\n", program, location, count, value ); + ENTER_GL(); + func_glProgramUniformui64vNV( program, location, count, value ); + LEAVE_GL(); +} + static void WINAPI wine_glProgramVertexLimitNV( GLenum target, GLint limit ) { void (*func_glProgramVertexLimitNV)( GLenum, GLint ) = extension_funcs[EXT_glProgramVertexLimitNV]; TRACE("(%d, %d)\n", target, limit ); @@ -10687,6 +10976,14 @@ static void WINAPI wine_glSecondaryColor3usvEXT( GLushort* v ) { LEAVE_GL(); } +static void WINAPI wine_glSecondaryColorFormatNV( GLint size, GLenum type, GLsizei stride ) { + void (*func_glSecondaryColorFormatNV)( GLint, GLenum, GLsizei ) = extension_funcs[EXT_glSecondaryColorFormatNV]; + TRACE("(%d, %d, %d)\n", size, type, stride ); + ENTER_GL(); + func_glSecondaryColorFormatNV( size, type, stride ); + LEAVE_GL(); +} + static void WINAPI wine_glSecondaryColorPointer( GLint size, GLenum type, GLsizei stride, GLvoid* pointer ) { void (*func_glSecondaryColorPointer)( GLint, GLenum, GLsizei, GLvoid* ) = extension_funcs[EXT_glSecondaryColorPointer]; TRACE("(%d, %d, %d, %p)\n", size, type, stride, pointer ); @@ -11317,6 +11614,14 @@ static void WINAPI wine_glTexCoord4hvNV( unsigned short* v ) { LEAVE_GL(); } +static void WINAPI wine_glTexCoordFormatNV( GLint size, GLenum type, GLsizei stride ) { + void (*func_glTexCoordFormatNV)( GLint, GLenum, GLsizei ) = extension_funcs[EXT_glTexCoordFormatNV]; + TRACE("(%d, %d, %d)\n", size, type, stride ); + ENTER_GL(); + func_glTexCoordFormatNV( size, type, stride ); + LEAVE_GL(); +} + static void WINAPI wine_glTexCoordPointerEXT( GLint size, GLenum type, GLsizei stride, GLsizei count, GLvoid* pointer ) { void (*func_glTexCoordPointerEXT)( GLint, GLenum, GLsizei, GLsizei, GLvoid* ) = extension_funcs[EXT_glTexCoordPointerEXT]; TRACE("(%d, %d, %d, %d, %p)\n", size, type, stride, count, pointer ); @@ -11469,6 +11774,14 @@ static void WINAPI wine_glTexSubImage4DSGIS( GLenum target, GLint level, GLint x LEAVE_GL(); } +static void WINAPI wine_glTextureBarrierNV( void ) { + void (*func_glTextureBarrierNV)( void ) = extension_funcs[EXT_glTextureBarrierNV]; + TRACE("()\n"); + ENTER_GL(); + func_glTextureBarrierNV( ); + LEAVE_GL(); +} + static void WINAPI wine_glTextureBufferEXT( GLuint texture, GLenum target, GLenum internalformat, GLuint buffer ) { void (*func_glTextureBufferEXT)( GLuint, GLenum, GLenum, GLuint ) = extension_funcs[EXT_glTextureBufferEXT]; TRACE("(%d, %d, %d, %d)\n", texture, target, internalformat, buffer ); @@ -12157,6 +12470,22 @@ static void WINAPI wine_glUniformMatrix4x3fv( GLint location, GLsizei count, GLb LEAVE_GL(); } +static void WINAPI wine_glUniformui64NV( GLint location, UINT64 value ) { + void (*func_glUniformui64NV)( GLint, UINT64 ) = extension_funcs[EXT_glUniformui64NV]; + TRACE("(%d, %s)\n", location, wine_dbgstr_longlong(value) ); + ENTER_GL(); + func_glUniformui64NV( location, value ); + LEAVE_GL(); +} + +static void WINAPI wine_glUniformui64vNV( GLint location, GLsizei count, UINT64* value ) { + void (*func_glUniformui64vNV)( GLint, GLsizei, UINT64* ) = extension_funcs[EXT_glUniformui64vNV]; + TRACE("(%d, %d, %p)\n", location, count, value ); + ENTER_GL(); + func_glUniformui64vNV( location, count, value ); + LEAVE_GL(); +} + static void WINAPI wine_glUnlockArraysEXT( void ) { void (*func_glUnlockArraysEXT)( void ) = extension_funcs[EXT_glUnlockArraysEXT]; TRACE("()\n"); @@ -12227,6 +12556,14 @@ static void WINAPI wine_glUseProgramObjectARB( unsigned int programObj ) { LEAVE_GL(); } +static void WINAPI wine_glUseShaderProgramEXT( GLenum type, GLuint program ) { + void (*func_glUseShaderProgramEXT)( GLenum, GLuint ) = extension_funcs[EXT_glUseShaderProgramEXT]; + TRACE("(%d, %d)\n", type, program ); + ENTER_GL(); + func_glUseShaderProgramEXT( type, program ); + LEAVE_GL(); +} + static void WINAPI wine_glValidateProgram( GLuint program ) { void (*func_glValidateProgram)( GLuint ) = extension_funcs[EXT_glValidateProgram]; TRACE("(%d)\n", program ); @@ -13259,6 +13596,14 @@ static void WINAPI wine_glVertexAttribDivisorARB( GLuint index, GLuint divisor ) LEAVE_GL(); } +static void WINAPI wine_glVertexAttribFormatNV( GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride ) { + void (*func_glVertexAttribFormatNV)( GLuint, GLint, GLenum, GLboolean, GLsizei ) = extension_funcs[EXT_glVertexAttribFormatNV]; + TRACE("(%d, %d, %d, %d, %d)\n", index, size, type, normalized, stride ); + ENTER_GL(); + func_glVertexAttribFormatNV( index, size, type, normalized, stride ); + LEAVE_GL(); +} + static void WINAPI wine_glVertexAttribI1i( GLuint index, GLint x ) { void (*func_glVertexAttribI1i)( GLuint, GLint ) = extension_funcs[EXT_glVertexAttribI1i]; TRACE("(%d, %d)\n", index, x ); @@ -13579,6 +13924,14 @@ static void WINAPI wine_glVertexAttribI4usvEXT( GLuint index, GLushort* v ) { LEAVE_GL(); } +static void WINAPI wine_glVertexAttribIFormatNV( GLuint index, GLint size, GLenum type, GLsizei stride ) { + void (*func_glVertexAttribIFormatNV)( GLuint, GLint, GLenum, GLsizei ) = extension_funcs[EXT_glVertexAttribIFormatNV]; + TRACE("(%d, %d, %d, %d)\n", index, size, type, stride ); + ENTER_GL(); + func_glVertexAttribIFormatNV( index, size, type, stride ); + LEAVE_GL(); +} + static void WINAPI wine_glVertexAttribIPointer( GLuint index, GLint size, GLenum type, GLsizei stride, GLvoid* pointer ) { void (*func_glVertexAttribIPointer)( GLuint, GLint, GLenum, GLsizei, GLvoid* ) = extension_funcs[EXT_glVertexAttribIPointer]; TRACE("(%d, %d, %d, %d, %p)\n", index, size, type, stride, pointer ); @@ -13779,6 +14132,14 @@ static void WINAPI wine_glVertexBlendEnviATI( GLenum pname, GLint param ) { LEAVE_GL(); } +static void WINAPI wine_glVertexFormatNV( GLint size, GLenum type, GLsizei stride ) { + void (*func_glVertexFormatNV)( GLint, GLenum, GLsizei ) = extension_funcs[EXT_glVertexFormatNV]; + TRACE("(%d, %d, %d)\n", size, type, stride ); + ENTER_GL(); + func_glVertexFormatNV( size, type, stride ); + LEAVE_GL(); +} + static void WINAPI wine_glVertexPointerEXT( GLint size, GLenum type, GLsizei stride, GLsizei count, GLvoid* pointer ) { void (*func_glVertexPointerEXT)( GLint, GLenum, GLsizei, GLsizei, GLvoid* ) = extension_funcs[EXT_glVertexPointerEXT]; TRACE("(%d, %d, %d, %d, %p)\n", size, type, stride, count, pointer ); @@ -14099,6 +14460,40 @@ static void WINAPI wine_glVertexWeighthvNV( unsigned short* weight ) { LEAVE_GL(); } +static GLenum WINAPI wine_glVideoCaptureNV( GLuint video_capture_slot, GLuint* sequence_num, UINT64* capture_time ) { + GLenum ret_value; + GLenum (*func_glVideoCaptureNV)( GLuint, GLuint*, UINT64* ) = extension_funcs[EXT_glVideoCaptureNV]; + TRACE("(%d, %p, %p)\n", video_capture_slot, sequence_num, capture_time ); + ENTER_GL(); + ret_value = func_glVideoCaptureNV( video_capture_slot, sequence_num, capture_time ); + LEAVE_GL(); + return ret_value; +} + +static void WINAPI wine_glVideoCaptureStreamParameterdvNV( GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble* params ) { + void (*func_glVideoCaptureStreamParameterdvNV)( GLuint, GLuint, GLenum, GLdouble* ) = extension_funcs[EXT_glVideoCaptureStreamParameterdvNV]; + TRACE("(%d, %d, %d, %p)\n", video_capture_slot, stream, pname, params ); + ENTER_GL(); + func_glVideoCaptureStreamParameterdvNV( video_capture_slot, stream, pname, params ); + LEAVE_GL(); +} + +static void WINAPI wine_glVideoCaptureStreamParameterfvNV( GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat* params ) { + void (*func_glVideoCaptureStreamParameterfvNV)( GLuint, GLuint, GLenum, GLfloat* ) = extension_funcs[EXT_glVideoCaptureStreamParameterfvNV]; + TRACE("(%d, %d, %d, %p)\n", video_capture_slot, stream, pname, params ); + ENTER_GL(); + func_glVideoCaptureStreamParameterfvNV( video_capture_slot, stream, pname, params ); + LEAVE_GL(); +} + +static void WINAPI wine_glVideoCaptureStreamParameterivNV( GLuint video_capture_slot, GLuint stream, GLenum pname, GLint* params ) { + void (*func_glVideoCaptureStreamParameterivNV)( GLuint, GLuint, GLenum, GLint* ) = extension_funcs[EXT_glVideoCaptureStreamParameterivNV]; + TRACE("(%d, %d, %d, %p)\n", video_capture_slot, stream, pname, params ); + ENTER_GL(); + func_glVideoCaptureStreamParameterivNV( video_capture_slot, stream, pname, params ); + LEAVE_GL(); +} + static void WINAPI wine_glWaitSync( GLvoid* sync, GLbitfield flags, UINT64 timeout ) { void (*func_glWaitSync)( GLvoid*, GLbitfield, UINT64 ) = extension_funcs[EXT_glWaitSync]; TRACE("(%p, %d, %s)\n", sync, flags, wine_dbgstr_longlong(timeout) ); @@ -14638,6 +15033,7 @@ static void WINAPI wine_glWriteMaskEXT( GLuint res, GLuint in, GLenum outX, GLen /* The table giving the correspondence between names and functions */ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { + { "glActiveProgramEXT", "GL_EXT_separate_shader_objects", wine_glActiveProgramEXT }, { "glActiveStencilFaceEXT", "GL_EXT_stencil_two_side", wine_glActiveStencilFaceEXT }, { "glActiveTexture", "GL_VERSION_1_3", wine_glActiveTexture }, { "glActiveTextureARB", "GL_ARB_multitexture", wine_glActiveTextureARB }, @@ -14664,6 +15060,7 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glBeginTransformFeedbackEXT", "GL_EXT_transform_feedback", wine_glBeginTransformFeedbackEXT }, { "glBeginTransformFeedbackNV", "GL_NV_transform_feedback", wine_glBeginTransformFeedbackNV }, { "glBeginVertexShaderEXT", "GL_EXT_vertex_shader", wine_glBeginVertexShaderEXT }, + { "glBeginVideoCaptureNV", "GL_NV_video_capture", wine_glBeginVideoCaptureNV }, { "glBindAttribLocation", "GL_VERSION_2_0", wine_glBindAttribLocation }, { "glBindAttribLocationARB", "GL_ARB_vertex_shader", wine_glBindAttribLocationARB }, { "glBindBuffer", "GL_VERSION_1_5", wine_glBindBuffer }, @@ -14696,6 +15093,8 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glBindVertexArray", "GL_ARB_vertex_array_object", wine_glBindVertexArray }, { "glBindVertexArrayAPPLE", "GL_APPLE_vertex_array_object", wine_glBindVertexArrayAPPLE }, { "glBindVertexShaderEXT", "GL_EXT_vertex_shader", wine_glBindVertexShaderEXT }, + { "glBindVideoCaptureStreamBufferNV", "GL_NV_video_capture", wine_glBindVideoCaptureStreamBufferNV }, + { "glBindVideoCaptureStreamTextureNV", "GL_NV_video_capture", wine_glBindVideoCaptureStreamTextureNV }, { "glBinormal3bEXT", "GL_EXT_coordinate_frame", wine_glBinormal3bEXT }, { "glBinormal3bvEXT", "GL_EXT_coordinate_frame", wine_glBinormal3bvEXT }, { "glBinormal3dEXT", "GL_EXT_coordinate_frame", wine_glBinormal3dEXT }, @@ -14726,6 +15125,7 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glBlendFunci", "GL_ARB_draw_buffers_blend", wine_glBlendFunci }, { "glBlitFramebuffer", "GL_ARB_framebuffer_object", wine_glBlitFramebuffer }, { "glBlitFramebufferEXT", "GL_EXT_framebuffer_blit", wine_glBlitFramebufferEXT }, + { "glBufferAddressRangeNV", "GL_NV_vertex_buffer_unified_memory", wine_glBufferAddressRangeNV }, { "glBufferData", "GL_VERSION_1_5", wine_glBufferData }, { "glBufferDataARB", "GL_ARB_vertex_buffer_object", wine_glBufferDataARB }, { "glBufferParameteriAPPLE", "GL_APPLE_flush_buffer_range", wine_glBufferParameteriAPPLE }, @@ -14761,6 +15161,7 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glColor4ubVertex2fvSUN", "GL_SUN_vertex", wine_glColor4ubVertex2fvSUN }, { "glColor4ubVertex3fSUN", "GL_SUN_vertex", wine_glColor4ubVertex3fSUN }, { "glColor4ubVertex3fvSUN", "GL_SUN_vertex", wine_glColor4ubVertex3fvSUN }, + { "glColorFormatNV", "GL_NV_vertex_buffer_unified_memory", wine_glColorFormatNV }, { "glColorFragmentOp1ATI", "GL_ATI_fragment_shader", wine_glColorFragmentOp1ATI }, { "glColorFragmentOp2ATI", "GL_ATI_fragment_shader", wine_glColorFragmentOp2ATI }, { "glColorFragmentOp3ATI", "GL_ATI_fragment_shader", wine_glColorFragmentOp3ATI }, @@ -14832,6 +15233,7 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glCopyConvolutionFilter1DEXT", "GL_EXT_convolution", wine_glCopyConvolutionFilter1DEXT }, { "glCopyConvolutionFilter2D", "GL_VERSION_1_2_DEPRECATED", wine_glCopyConvolutionFilter2D }, { "glCopyConvolutionFilter2DEXT", "GL_EXT_convolution", wine_glCopyConvolutionFilter2DEXT }, + { "glCopyImageSubDataNV", "GL_NV_copy_image", wine_glCopyImageSubDataNV }, { "glCopyMultiTexImage1DEXT", "GL_EXT_direct_state_access", wine_glCopyMultiTexImage1DEXT }, { "glCopyMultiTexImage2DEXT", "GL_EXT_direct_state_access", wine_glCopyMultiTexImage2DEXT }, { "glCopyMultiTexSubImage1DEXT", "GL_EXT_direct_state_access", wine_glCopyMultiTexSubImage1DEXT }, @@ -14852,6 +15254,7 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glCreateProgramObjectARB", "GL_ARB_shader_objects", wine_glCreateProgramObjectARB }, { "glCreateShader", "GL_VERSION_2_0", wine_glCreateShader }, { "glCreateShaderObjectARB", "GL_ARB_shader_objects", wine_glCreateShaderObjectARB }, + { "glCreateShaderProgramEXT", "GL_EXT_separate_shader_objects", wine_glCreateShaderProgramEXT }, { "glCullParameterdvEXT", "GL_EXT_cull_vertex", wine_glCullParameterdvEXT }, { "glCullParameterfvEXT", "GL_EXT_cull_vertex", wine_glCullParameterfvEXT }, { "glCurrentPaletteMatrixARB", "GL_ARB_matrix_palette", wine_glCurrentPaletteMatrixARB }, @@ -14920,6 +15323,7 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glDrawRangeElementsBaseVertex", "GL_ARB_draw_elements_base_vertex", wine_glDrawRangeElementsBaseVertex }, { "glDrawRangeElementsEXT", "GL_EXT_draw_range_elements", wine_glDrawRangeElementsEXT }, { "glDrawTransformFeedbackNV", "GL_NV_transform_feedback2", wine_glDrawTransformFeedbackNV }, + { "glEdgeFlagFormatNV", "GL_NV_vertex_buffer_unified_memory", wine_glEdgeFlagFormatNV }, { "glEdgeFlagPointerEXT", "GL_EXT_vertex_array", wine_glEdgeFlagPointerEXT }, { "glEdgeFlagPointerListIBM", "GL_IBM_vertex_array_lists", wine_glEdgeFlagPointerListIBM }, { "glElementPointerAPPLE", "GL_APPLE_element_array", wine_glElementPointerAPPLE }, @@ -14942,6 +15346,7 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glEndTransformFeedbackEXT", "GL_EXT_transform_feedback", wine_glEndTransformFeedbackEXT }, { "glEndTransformFeedbackNV", "GL_NV_transform_feedback", wine_glEndTransformFeedbackNV }, { "glEndVertexShaderEXT", "GL_EXT_vertex_shader", wine_glEndVertexShaderEXT }, + { "glEndVideoCaptureNV", "GL_NV_video_capture", wine_glEndVideoCaptureNV }, { "glEvalMapsNV", "GL_NV_evaluators", wine_glEvalMapsNV }, { "glExecuteProgramNV", "GL_NV_vertex_program", wine_glExecuteProgramNV }, { "glExtractComponentEXT", "GL_EXT_vertex_shader", wine_glExtractComponentEXT }, @@ -14958,6 +15363,7 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glFlushRasterSGIX", "GL_SGIX_flush_raster", wine_glFlushRasterSGIX }, { "glFlushVertexArrayRangeAPPLE", "GL_APPLE_vertex_array_range", wine_glFlushVertexArrayRangeAPPLE }, { "glFlushVertexArrayRangeNV", "GL_NV_vertex_array_range", wine_glFlushVertexArrayRangeNV }, + { "glFogCoordFormatNV", "GL_NV_vertex_buffer_unified_memory", wine_glFogCoordFormatNV }, { "glFogCoordPointer", "GL_VERSION_1_4_DEPRECATED", wine_glFogCoordPointer }, { "glFogCoordPointerEXT", "GL_EXT_fog_coord", wine_glFogCoordPointerEXT }, { "glFogCoordPointerListIBM", "GL_IBM_vertex_array_lists", wine_glFogCoordPointerListIBM }, @@ -15054,6 +15460,7 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glGetBufferParameteri64v", "GL_VERSION_3_2", wine_glGetBufferParameteri64v }, { "glGetBufferParameteriv", "GL_VERSION_1_5", wine_glGetBufferParameteriv }, { "glGetBufferParameterivARB", "GL_ARB_vertex_buffer_object", wine_glGetBufferParameterivARB }, + { "glGetBufferParameterui64vNV", "GL_NV_shader_buffer_load", wine_glGetBufferParameterui64vNV }, { "glGetBufferPointerv", "GL_VERSION_1_5", wine_glGetBufferPointerv }, { "glGetBufferPointervARB", "GL_ARB_vertex_buffer_object", wine_glGetBufferPointervARB }, { "glGetBufferSubData", "GL_VERSION_1_5", wine_glGetBufferSubData }, @@ -15113,6 +15520,8 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glGetInteger64v", "GL_ARB_sync", wine_glGetInteger64v }, { "glGetIntegerIndexedvEXT", "GL_EXT_draw_buffers2", wine_glGetIntegerIndexedvEXT }, { "glGetIntegeri_v", "GL_VERSION_3_0", wine_glGetIntegeri_v }, + { "glGetIntegerui64i_vNV", "GL_NV_vertex_buffer_unified_memory", wine_glGetIntegerui64i_vNV }, + { "glGetIntegerui64vNV", "GL_NV_shader_buffer_load", wine_glGetIntegerui64vNV }, { "glGetInvariantBooleanvEXT", "GL_EXT_vertex_shader", wine_glGetInvariantBooleanvEXT }, { "glGetInvariantFloatvEXT", "GL_EXT_vertex_shader", wine_glGetInvariantFloatvEXT }, { "glGetInvariantIntegervEXT", "GL_EXT_vertex_shader", wine_glGetInvariantIntegervEXT }, @@ -15147,6 +15556,7 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glGetMultisamplefv", "GL_ARB_texture_multisample", wine_glGetMultisamplefv }, { "glGetMultisamplefvNV", "GL_NV_explicit_multisample", wine_glGetMultisamplefvNV }, { "glGetNamedBufferParameterivEXT", "GL_EXT_direct_state_access", wine_glGetNamedBufferParameterivEXT }, + { "glGetNamedBufferParameterui64vNV", "GL_NV_shader_buffer_load", wine_glGetNamedBufferParameterui64vNV }, { "glGetNamedBufferPointervEXT", "GL_EXT_direct_state_access", wine_glGetNamedBufferPointervEXT }, { "glGetNamedBufferSubDataEXT", "GL_EXT_direct_state_access", wine_glGetNamedBufferSubDataEXT }, { "glGetNamedFramebufferAttachmentParameterivEXT", "GL_EXT_direct_state_access", wine_glGetNamedFramebufferAttachmentParameterivEXT }, @@ -15240,6 +15650,7 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glGetUniformfvARB", "GL_ARB_shader_objects", wine_glGetUniformfvARB }, { "glGetUniformiv", "GL_VERSION_2_0", wine_glGetUniformiv }, { "glGetUniformivARB", "GL_ARB_shader_objects", wine_glGetUniformivARB }, + { "glGetUniformui64vNV", "GL_NV_shader_buffer_load", wine_glGetUniformui64vNV }, { "glGetUniformuiv", "GL_VERSION_3_0", wine_glGetUniformuiv }, { "glGetUniformuivEXT", "GL_EXT_gpu_shader4", wine_glGetUniformuivEXT }, { "glGetVariantArrayObjectfvATI", "GL_ATI_vertex_array_object", wine_glGetVariantArrayObjectfvATI }, @@ -15267,6 +15678,10 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glGetVertexAttribiv", "GL_VERSION_2_0", wine_glGetVertexAttribiv }, { "glGetVertexAttribivARB", "GL_ARB_vertex_program", wine_glGetVertexAttribivARB }, { "glGetVertexAttribivNV", "GL_NV_vertex_program", wine_glGetVertexAttribivNV }, + { "glGetVideoCaptureStreamdvNV", "GL_NV_video_capture", wine_glGetVideoCaptureStreamdvNV }, + { "glGetVideoCaptureStreamfvNV", "GL_NV_video_capture", wine_glGetVideoCaptureStreamfvNV }, + { "glGetVideoCaptureStreamivNV", "GL_NV_video_capture", wine_glGetVideoCaptureStreamivNV }, + { "glGetVideoCaptureivNV", "GL_NV_video_capture", wine_glGetVideoCaptureivNV }, { "glGetVideoi64vNV", "GL_NV_present_video", wine_glGetVideoi64vNV }, { "glGetVideoivNV", "GL_NV_present_video", wine_glGetVideoivNV }, { "glGetVideoui64vNV", "GL_NV_present_video", wine_glGetVideoui64vNV }, @@ -15287,6 +15702,7 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glImageTransformParameterfvHP", "GL_HP_image_transform", wine_glImageTransformParameterfvHP }, { "glImageTransformParameteriHP", "GL_HP_image_transform", wine_glImageTransformParameteriHP }, { "glImageTransformParameterivHP", "GL_HP_image_transform", wine_glImageTransformParameterivHP }, + { "glIndexFormatNV", "GL_NV_vertex_buffer_unified_memory", wine_glIndexFormatNV }, { "glIndexFuncEXT", "GL_EXT_index_func", wine_glIndexFuncEXT }, { "glIndexMaterialEXT", "GL_EXT_index_material", wine_glIndexMaterialEXT }, { "glIndexPointerEXT", "GL_EXT_vertex_array", wine_glIndexPointerEXT }, @@ -15296,12 +15712,14 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glIsAsyncMarkerSGIX", "GL_SGIX_async", wine_glIsAsyncMarkerSGIX }, { "glIsBuffer", "GL_VERSION_1_5", wine_glIsBuffer }, { "glIsBufferARB", "GL_ARB_vertex_buffer_object", wine_glIsBufferARB }, + { "glIsBufferResidentNV", "GL_NV_shader_buffer_load", wine_glIsBufferResidentNV }, { "glIsEnabledIndexedEXT", "GL_EXT_draw_buffers2", wine_glIsEnabledIndexedEXT }, { "glIsEnabledi", "GL_VERSION_3_0", wine_glIsEnabledi }, { "glIsFenceAPPLE", "GL_APPLE_fence", wine_glIsFenceAPPLE }, { "glIsFenceNV", "GL_NV_fence", wine_glIsFenceNV }, { "glIsFramebuffer", "GL_ARB_framebuffer_object", wine_glIsFramebuffer }, { "glIsFramebufferEXT", "GL_EXT_framebuffer_object", wine_glIsFramebufferEXT }, + { "glIsNamedBufferResidentNV", "GL_NV_shader_buffer_load", wine_glIsNamedBufferResidentNV }, { "glIsObjectBufferATI", "GL_ATI_vertex_array_object", wine_glIsObjectBufferATI }, { "glIsOcclusionQueryNV", "GL_NV_occlusion_query", wine_glIsOcclusionQueryNV }, { "glIsProgram", "GL_VERSION_2_0", wine_glIsProgram }, @@ -15335,6 +15753,8 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glLockArraysEXT", "GL_EXT_compiled_vertex_array", wine_glLockArraysEXT }, { "glMTexCoord2fSGIS", "GL_SGIS_multitexture", wine_glMTexCoord2fSGIS }, { "glMTexCoord2fvSGIS", "GL_SGIS_multitexture", wine_glMTexCoord2fvSGIS }, + { "glMakeBufferNonResidentNV", "GL_NV_shader_buffer_load", wine_glMakeBufferNonResidentNV }, + { "glMakeBufferResidentNV", "GL_NV_shader_buffer_load", wine_glMakeBufferResidentNV }, { "glMapBuffer", "GL_VERSION_1_5", wine_glMapBuffer }, { "glMapBufferARB", "GL_ARB_vertex_buffer_object", wine_glMapBufferARB }, { "glMapBufferRange", "GL_ARB_map_buffer_range", wine_glMapBufferRange }, @@ -15525,6 +15945,8 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glNamedFramebufferTextureEXT", "GL_EXT_direct_state_access", wine_glNamedFramebufferTextureEXT }, { "glNamedFramebufferTextureFaceEXT", "GL_EXT_direct_state_access", wine_glNamedFramebufferTextureFaceEXT }, { "glNamedFramebufferTextureLayerEXT", "GL_EXT_direct_state_access", wine_glNamedFramebufferTextureLayerEXT }, + { "glNamedMakeBufferNonResidentNV", "GL_NV_shader_buffer_load", wine_glNamedMakeBufferNonResidentNV }, + { "glNamedMakeBufferResidentNV", "GL_NV_shader_buffer_load", wine_glNamedMakeBufferResidentNV }, { "glNamedProgramLocalParameter4dEXT", "GL_EXT_direct_state_access", wine_glNamedProgramLocalParameter4dEXT }, { "glNamedProgramLocalParameter4dvEXT", "GL_EXT_direct_state_access", wine_glNamedProgramLocalParameter4dvEXT }, { "glNamedProgramLocalParameter4fEXT", "GL_EXT_direct_state_access", wine_glNamedProgramLocalParameter4fEXT }, @@ -15546,6 +15968,7 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glNormal3fVertex3fvSUN", "GL_SUN_vertex", wine_glNormal3fVertex3fvSUN }, { "glNormal3hNV", "GL_NV_half_float", wine_glNormal3hNV }, { "glNormal3hvNV", "GL_NV_half_float", wine_glNormal3hvNV }, + { "glNormalFormatNV", "GL_NV_vertex_buffer_unified_memory", wine_glNormalFormatNV }, { "glNormalPointerEXT", "GL_EXT_vertex_array", wine_glNormalPointerEXT }, { "glNormalPointerListIBM", "GL_IBM_vertex_array_lists", wine_glNormalPointerListIBM }, { "glNormalPointervINTEL", "GL_INTEL_parallel_arrays", wine_glNormalPointervINTEL }, @@ -15668,6 +16091,8 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glProgramUniformMatrix4fvEXT", "GL_EXT_direct_state_access", wine_glProgramUniformMatrix4fvEXT }, { "glProgramUniformMatrix4x2fvEXT", "GL_EXT_direct_state_access", wine_glProgramUniformMatrix4x2fvEXT }, { "glProgramUniformMatrix4x3fvEXT", "GL_EXT_direct_state_access", wine_glProgramUniformMatrix4x3fvEXT }, + { "glProgramUniformui64NV", "GL_NV_shader_buffer_load", wine_glProgramUniformui64NV }, + { "glProgramUniformui64vNV", "GL_NV_shader_buffer_load", wine_glProgramUniformui64vNV }, { "glProgramVertexLimitNV", "GL_NV_geometry_program4", wine_glProgramVertexLimitNV }, { "glProvokingVertex", "GL_ARB_provoking_vertex", wine_glProvokingVertex }, { "glProvokingVertexEXT", "GL_EXT_provoking_vertex", wine_glProvokingVertexEXT }, @@ -15753,6 +16178,7 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glSecondaryColor3usEXT", "GL_EXT_secondary_color", wine_glSecondaryColor3usEXT }, { "glSecondaryColor3usv", "GL_VERSION_1_4_DEPRECATED", wine_glSecondaryColor3usv }, { "glSecondaryColor3usvEXT", "GL_EXT_secondary_color", wine_glSecondaryColor3usvEXT }, + { "glSecondaryColorFormatNV", "GL_NV_vertex_buffer_unified_memory", wine_glSecondaryColorFormatNV }, { "glSecondaryColorPointer", "GL_VERSION_1_4_DEPRECATED", wine_glSecondaryColorPointer }, { "glSecondaryColorPointerEXT", "GL_EXT_secondary_color", wine_glSecondaryColorPointerEXT }, { "glSecondaryColorPointerListIBM", "GL_IBM_vertex_array_lists", wine_glSecondaryColorPointerListIBM }, @@ -15831,6 +16257,7 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glTexCoord4fVertex4fvSUN", "GL_SUN_vertex", wine_glTexCoord4fVertex4fvSUN }, { "glTexCoord4hNV", "GL_NV_half_float", wine_glTexCoord4hNV }, { "glTexCoord4hvNV", "GL_NV_half_float", wine_glTexCoord4hvNV }, + { "glTexCoordFormatNV", "GL_NV_vertex_buffer_unified_memory", wine_glTexCoordFormatNV }, { "glTexCoordPointerEXT", "GL_EXT_vertex_array", wine_glTexCoordPointerEXT }, { "glTexCoordPointerListIBM", "GL_IBM_vertex_array_lists", wine_glTexCoordPointerListIBM }, { "glTexCoordPointervINTEL", "GL_INTEL_parallel_arrays", wine_glTexCoordPointervINTEL }, @@ -15850,6 +16277,7 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glTexSubImage3D", "GL_VERSION_1_2", wine_glTexSubImage3D }, { "glTexSubImage3DEXT", "GL_EXT_texture3D", wine_glTexSubImage3DEXT }, { "glTexSubImage4DSGIS", "GL_SGIS_texture4D", wine_glTexSubImage4DSGIS }, + { "glTextureBarrierNV", "GL_NV_texture_barrier", wine_glTextureBarrierNV }, { "glTextureBufferEXT", "GL_EXT_direct_state_access", wine_glTextureBufferEXT }, { "glTextureColorMaskSGIS", "GL_SGIS_texture_color_mask", wine_glTextureColorMaskSGIS }, { "glTextureImage1DEXT", "GL_EXT_direct_state_access", wine_glTextureImage1DEXT }, @@ -15936,6 +16364,8 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glUniformMatrix4fvARB", "GL_ARB_shader_objects", wine_glUniformMatrix4fvARB }, { "glUniformMatrix4x2fv", "GL_VERSION_2_1", wine_glUniformMatrix4x2fv }, { "glUniformMatrix4x3fv", "GL_VERSION_2_1", wine_glUniformMatrix4x3fv }, + { "glUniformui64NV", "GL_NV_shader_buffer_load", wine_glUniformui64NV }, + { "glUniformui64vNV", "GL_NV_shader_buffer_load", wine_glUniformui64vNV }, { "glUnlockArraysEXT", "GL_EXT_compiled_vertex_array", wine_glUnlockArraysEXT }, { "glUnmapBuffer", "GL_VERSION_1_5", wine_glUnmapBuffer }, { "glUnmapBufferARB", "GL_ARB_vertex_buffer_object", wine_glUnmapBufferARB }, @@ -15944,6 +16374,7 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glUpdateObjectBufferATI", "GL_ATI_vertex_array_object", wine_glUpdateObjectBufferATI }, { "glUseProgram", "GL_VERSION_2_0", wine_glUseProgram }, { "glUseProgramObjectARB", "GL_ARB_shader_objects", wine_glUseProgramObjectARB }, + { "glUseShaderProgramEXT", "GL_EXT_separate_shader_objects", wine_glUseShaderProgramEXT }, { "glValidateProgram", "GL_VERSION_2_0", wine_glValidateProgram }, { "glValidateProgramARB", "GL_ARB_shader_objects", wine_glValidateProgramARB }, { "glVariantArrayObjectATI", "GL_ATI_vertex_array_object", wine_glVariantArrayObjectATI }, @@ -16073,6 +16504,7 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glVertexAttrib4usvARB", "GL_ARB_vertex_program", wine_glVertexAttrib4usvARB }, { "glVertexAttribArrayObjectATI", "GL_ATI_vertex_attrib_array_object", wine_glVertexAttribArrayObjectATI }, { "glVertexAttribDivisorARB", "GL_ARB_instanced_arrays", wine_glVertexAttribDivisorARB }, + { "glVertexAttribFormatNV", "GL_NV_vertex_buffer_unified_memory", wine_glVertexAttribFormatNV }, { "glVertexAttribI1i", "GL_VERSION_3_0", wine_glVertexAttribI1i }, { "glVertexAttribI1iEXT", "GL_NV_vertex_program4", wine_glVertexAttribI1iEXT }, { "glVertexAttribI1iv", "GL_VERSION_3_0", wine_glVertexAttribI1iv }, @@ -16113,6 +16545,7 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glVertexAttribI4uivEXT", "GL_NV_vertex_program4", wine_glVertexAttribI4uivEXT }, { "glVertexAttribI4usv", "GL_VERSION_3_0", wine_glVertexAttribI4usv }, { "glVertexAttribI4usvEXT", "GL_NV_vertex_program4", wine_glVertexAttribI4usvEXT }, + { "glVertexAttribIFormatNV", "GL_NV_vertex_buffer_unified_memory", wine_glVertexAttribIFormatNV }, { "glVertexAttribIPointer", "GL_VERSION_3_0", wine_glVertexAttribIPointer }, { "glVertexAttribIPointerEXT", "GL_NV_vertex_program4", wine_glVertexAttribIPointerEXT }, { "glVertexAttribPointer", "GL_VERSION_2_0", wine_glVertexAttribPointer }, @@ -16138,6 +16571,7 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glVertexBlendARB", "GL_ARB_vertex_blend", wine_glVertexBlendARB }, { "glVertexBlendEnvfATI", "GL_ATI_vertex_streams", wine_glVertexBlendEnvfATI }, { "glVertexBlendEnviATI", "GL_ATI_vertex_streams", wine_glVertexBlendEnviATI }, + { "glVertexFormatNV", "GL_NV_vertex_buffer_unified_memory", wine_glVertexFormatNV }, { "glVertexPointerEXT", "GL_EXT_vertex_array", wine_glVertexPointerEXT }, { "glVertexPointerListIBM", "GL_IBM_vertex_array_lists", wine_glVertexPointerListIBM }, { "glVertexPointervINTEL", "GL_INTEL_parallel_arrays", wine_glVertexPointervINTEL }, @@ -16178,6 +16612,10 @@ const OpenGL_extension extension_registry[NB_EXTENSIONS] = { { "glVertexWeightfvEXT", "GL_EXT_vertex_weighting", wine_glVertexWeightfvEXT }, { "glVertexWeighthNV", "GL_NV_half_float", wine_glVertexWeighthNV }, { "glVertexWeighthvNV", "GL_NV_half_float", wine_glVertexWeighthvNV }, + { "glVideoCaptureNV", "GL_NV_video_capture", wine_glVideoCaptureNV }, + { "glVideoCaptureStreamParameterdvNV", "GL_NV_video_capture", wine_glVideoCaptureStreamParameterdvNV }, + { "glVideoCaptureStreamParameterfvNV", "GL_NV_video_capture", wine_glVideoCaptureStreamParameterfvNV }, + { "glVideoCaptureStreamParameterivNV", "GL_NV_video_capture", wine_glVideoCaptureStreamParameterivNV }, { "glWaitSync", "GL_ARB_sync", wine_glWaitSync }, { "glWeightPointerARB", "GL_ARB_vertex_blend", wine_glWeightPointerARB }, { "glWeightbvARB", "GL_ARB_vertex_blend", wine_glWeightbvARB }, diff --git a/dlls/opengl32/tests/opengl.c b/dlls/opengl32/tests/opengl.c index 13e41fd2cae..b2d8e185c88 100644 --- a/dlls/opengl32/tests/opengl.c +++ b/dlls/opengl32/tests/opengl.c @@ -314,7 +314,7 @@ static void test_sharelists(HDC winhdc) res = wglMakeCurrent(winhdc, hglrc2); ok(res, "Make current failed\n"); res = wglShareLists(hglrc1, hglrc2); - todo_wine ok(res, "Sharing display lists with a destination context which has been made current passed\n"); + todo_wine ok(res, "Sharing display lists with a destination context which has been made current failed\n"); wglMakeCurrent(0, 0); wglDeleteContext(hglrc2); } @@ -325,7 +325,7 @@ static void test_sharelists(HDC winhdc) if(hglrc3) { res = wglShareLists(hglrc3, hglrc1); - ok(res == FALSE, "Sharing of display lists failed for a context which already shared lists before\n"); + ok(res == FALSE, "Sharing of display lists passed for a context which already shared lists before\n"); wglDeleteContext(hglrc3); } @@ -336,7 +336,7 @@ static void test_sharelists(HDC winhdc) res = wglMakeCurrent(winhdc, hglrc1); ok(res, "Make current failed\n"); res = wglShareLists(hglrc1, hglrc2); - ok(res, "Sharing display lists with a source context which has been made current passed\n"); + ok(res, "Sharing display lists with a source context which has been made current failed\n"); wglMakeCurrent(0, 0); wglDeleteContext(hglrc2); } @@ -551,20 +551,10 @@ static void test_dc(HWND hwnd, HDC hdc) } } +/* Nvidia converts win32 error codes to (0xc007 << 16) | win32_error_code */ +#define NVIDIA_HRESULT_FROM_WIN32(x) (HRESULT_FROM_WIN32(x) | 0x40000000) static void test_opengl3(HDC hdc) { - /* Try to create a context using an invalid OpenGL version namely 0.x */ - { - HGLRC gl3Ctx; - int attribs[] = {WGL_CONTEXT_MAJOR_VERSION_ARB, 0, 0}; - - gl3Ctx = pwglCreateContextAttribsARB(hdc, 0, attribs); - ok(gl3Ctx == 0, "wglCreateContextAttribs with major version=0 should fail!\n"); - - if(gl3Ctx) - wglDeleteContext(gl3Ctx); - } - /* Try to create a context compatible with OpenGL 1.x; 1.0-2.1 is allowed */ { HGLRC gl3Ctx; @@ -582,7 +572,9 @@ static void test_opengl3(HDC hdc) gl3Ctx = pwglCreateContextAttribsARB((HDC)0xdeadbeef, 0, 0); ok(gl3Ctx == 0, "pwglCreateContextAttribsARB using an invalid HDC passed\n"); error = GetLastError(); - todo_wine ok(error == ERROR_DC_NOT_FOUND, "Expected ERROR_DC_NOT_FOUND, got error=%x\n", error); + todo_wine ok(error == ERROR_DC_NOT_FOUND || + broken(error == NVIDIA_HRESULT_FROM_WIN32(ERROR_INVALID_DATA)), /* Nvidia Vista + Win7 */ + "Expected ERROR_DC_NOT_FOUND, got error=%x\n", error); wglDeleteContext(gl3Ctx); } @@ -591,9 +583,11 @@ static void test_opengl3(HDC hdc) HGLRC gl3Ctx; DWORD error; gl3Ctx = pwglCreateContextAttribsARB(hdc, (HGLRC)0xdeadbeef, 0); - ok(gl3Ctx == 0, "pwglCreateContextAttribsARB using an invalid shareList passed\n"); + todo_wine ok(gl3Ctx == 0, "pwglCreateContextAttribsARB using an invalid shareList passed\n"); error = GetLastError(); - todo_wine ok(error == ERROR_INVALID_OPERATION, "Expected ERROR_INVALID_OPERATION, got error=%x\n", error); + /* The Nvidia implementation seems to return hresults instead of win32 error codes */ + todo_wine ok(error == ERROR_INVALID_OPERATION || + error == NVIDIA_HRESULT_FROM_WIN32(ERROR_INVALID_OPERATION), "Expected ERROR_INVALID_OPERATION, got error=%x\n", error); wglDeleteContext(gl3Ctx); } @@ -641,10 +635,13 @@ static void test_opengl3(HDC hdc) gl3Ctx = pwglCreateContextAttribsARB(hdc, 0, attribs); ok(gl3Ctx != 0, "pwglCreateContextAttribsARB for a 3.0 context failed!\n"); - /* OpenGL 3.0 allows offscreen rendering WITHOUT a drawable */ - /* NOTE: Nvidia's 177.89 beta drivers don't allow this yet */ + /* OpenGL 3.0 allows offscreen rendering WITHOUT a drawable + * Neither AMD or Nvidia support it at this point. The WGL_ARB_create_context specs also say that + * it is hard because drivers use the HDC to enter the display driver and it sounds like they don't + * expect drivers to ever offer it. + */ res = wglMakeCurrent(0, gl3Ctx); - todo_wine ok(res == TRUE, "OpenGL 3.0 should allow windowless rendering, but the test failed!\n"); + ok(res == FALSE, "Wow, OpenGL 3.0 windowless rendering passed while it was expected not to!\n"); if(res) wglMakeCurrent(0, 0); diff --git a/dlls/pdh/pdh.spec b/dlls/pdh/pdh.spec index 135692f8c67..7486606db10 100644 --- a/dlls/pdh/pdh.spec +++ b/dlls/pdh/pdh.spec @@ -38,10 +38,10 @@ @ stub PdhEnumObjectsW @ stub PdhExpandCounterPathA @ stub PdhExpandCounterPathW -@ stub PdhExpandWildCardPathA +@ stdcall PdhExpandWildCardPathA(str str ptr ptr long) @ stub PdhExpandWildCardPathHA @ stub PdhExpandWildCardPathHW -@ stub PdhExpandWildCardPathW +@ stdcall PdhExpandWildCardPathW(wstr wstr ptr ptr long) @ stub PdhFormatFromRawValue @ stdcall PdhGetCounterInfoA(ptr long ptr ptr) @ stdcall PdhGetCounterInfoW(ptr long ptr ptr) diff --git a/dlls/pdh/pdh_main.c b/dlls/pdh/pdh_main.c index 9ca174b957e..7f08c923784 100644 --- a/dlls/pdh/pdh_main.c +++ b/dlls/pdh/pdh_main.c @@ -600,6 +600,24 @@ PDH_STATUS WINAPI PdhCollectQueryDataWithTime( PDH_HQUERY handle, LONGLONG *time } /*********************************************************************** + * PdhExpandWildCardPathA (PDH.@) + */ +PDH_STATUS WINAPI PdhExpandWildCardPathA( LPCSTR szDataSource, LPCSTR szWildCardPath, LPSTR mszExpandedPathList, LPDWORD pcchPathListLength, DWORD dwFlags ) +{ + FIXME("%s, %s, %p, %p, 0x%x: stub\n", debugstr_a(szDataSource), debugstr_a(szWildCardPath), mszExpandedPathList, pcchPathListLength, dwFlags); + return PDH_NOT_IMPLEMENTED; +} + +/*********************************************************************** + * PdhExpandWildCardPathW (PDH.@) + */ +PDH_STATUS WINAPI PdhExpandWildCardPathW( LPCWSTR szDataSource, LPCWSTR szWildCardPath, LPWSTR mszExpandedPathList, LPDWORD pcchPathListLength, DWORD dwFlags ) +{ + FIXME("%s, %s, %p, %p, 0x%x: stub\n", debugstr_w(szDataSource), debugstr_w(szWildCardPath), mszExpandedPathList, pcchPathListLength, dwFlags); + return PDH_NOT_IMPLEMENTED; +} + +/*********************************************************************** * PdhGetCounterInfoA (PDH.@) */ PDH_STATUS WINAPI PdhGetCounterInfoA( PDH_HCOUNTER handle, BOOLEAN text, LPDWORD size, PPDH_COUNTER_INFO_A info ) diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c index d978f721eb5..53772810831 100644 --- a/dlls/quartz/filtergraph.c +++ b/dlls/quartz/filtergraph.c @@ -2557,28 +2557,33 @@ static const IMediaSeekingVtbl IMediaSeeking_VTable = MediaSeeking_GetPreroll }; +static inline IFilterGraphImpl *impl_from_IMediaPosition( IMediaPosition *iface ) +{ + return (IFilterGraphImpl *)((char*)iface - FIELD_OFFSET(IFilterGraphImpl, IMediaPosition_vtbl)); +} + /*** IUnknown methods ***/ -static HRESULT WINAPI MediaPosition_QueryInterface(IMediaPosition* iface, REFIID riid, void** ppvObj){ - ICOM_THIS_MULTI(IFilterGraphImpl, IMediaPosition_vtbl, iface); +static HRESULT WINAPI MediaPosition_QueryInterface(IMediaPosition* iface, REFIID riid, void** ppvObj) +{ + IFilterGraphImpl *This = impl_from_IMediaPosition( iface ); TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj); - return Filtergraph_QueryInterface(This, riid, ppvObj); } -static ULONG WINAPI MediaPosition_AddRef(IMediaPosition *iface){ - ICOM_THIS_MULTI(IFilterGraphImpl, IMediaPosition_vtbl, iface); +static ULONG WINAPI MediaPosition_AddRef(IMediaPosition *iface) +{ + IFilterGraphImpl *This = impl_from_IMediaPosition( iface ); TRACE("(%p/%p)->()\n", This, iface); - return Filtergraph_AddRef(This); } -static ULONG WINAPI MediaPosition_Release(IMediaPosition *iface){ - ICOM_THIS_MULTI(IFilterGraphImpl, IMediaPosition_vtbl, iface); +static ULONG WINAPI MediaPosition_Release(IMediaPosition *iface) +{ + IFilterGraphImpl *This = impl_from_IMediaPosition( iface ); TRACE("(%p/%p)->()\n", This, iface); - return Filtergraph_Release(This); } @@ -2604,31 +2609,51 @@ static HRESULT WINAPI MediaPosition_Invoke(IMediaPosition* iface, DISPID dispIdM } /*** IMediaPosition methods ***/ -static HRESULT WINAPI MediaPosition_get_Duration(IMediaPosition * iface, REFTIME *plength){ - FIXME("(%p)->(%p) stub!\n", iface, plength); - return E_NOTIMPL; +static HRESULT WINAPI MediaPosition_get_Duration(IMediaPosition * iface, REFTIME *plength) +{ + LONGLONG duration; + IFilterGraphImpl *This = impl_from_IMediaPosition( iface ); + HRESULT hr = IMediaSeeking_GetDuration( (IMediaSeeking *)&This->IMediaSeeking_vtbl, &duration ); + if (SUCCEEDED(hr)) *plength = duration; + return hr; } -static HRESULT WINAPI MediaPosition_put_CurrentPosition(IMediaPosition * iface, REFTIME llTime){ - ICOM_THIS_MULTI(IFilterGraphImpl, IMediaPosition_vtbl, iface); +static HRESULT WINAPI MediaPosition_put_CurrentPosition(IMediaPosition * iface, REFTIME llTime) +{ + IFilterGraphImpl *This = impl_from_IMediaPosition( iface ); LONGLONG reftime = llTime; - return IMediaSeeking_SetPositions((IMediaSeeking *)&This->IMediaSeeking_vtbl, &reftime, AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning); + return IMediaSeeking_SetPositions((IMediaSeeking *)&This->IMediaSeeking_vtbl, + &reftime, AM_SEEKING_AbsolutePositioning, + NULL, AM_SEEKING_NoPositioning); } -static HRESULT WINAPI MediaPosition_get_CurrentPosition(IMediaPosition * iface, REFTIME *pllTime){ - FIXME("(%p)->(%p) stub!\n", iface, pllTime); - return E_NOTIMPL; +static HRESULT WINAPI MediaPosition_get_CurrentPosition(IMediaPosition * iface, REFTIME *pllTime) +{ + IFilterGraphImpl *This = impl_from_IMediaPosition( iface ); + LONGLONG pos; + HRESULT hr = IMediaSeeking_GetCurrentPosition( (IMediaSeeking *)&This->IMediaSeeking_vtbl, &pos ); + if (SUCCEEDED(hr)) *pllTime = pos; + return hr; } -static HRESULT WINAPI MediaPosition_get_StopTime(IMediaPosition * iface, REFTIME *pllTime){ - FIXME("(%p)->(%p) stub!\n", iface, pllTime); - return E_NOTIMPL; +static HRESULT WINAPI MediaPosition_get_StopTime(IMediaPosition * iface, REFTIME *pllTime) +{ + IFilterGraphImpl *This = impl_from_IMediaPosition( iface ); + LONGLONG pos; + HRESULT hr = IMediaSeeking_GetStopPosition( (IMediaSeeking *)&This->IMediaSeeking_vtbl, &pos ); + if (SUCCEEDED(hr)) *pllTime = pos; + return hr; } -static HRESULT WINAPI MediaPosition_put_StopTime(IMediaPosition * iface, REFTIME llTime){ - FIXME("(%p)->(%f) stub!\n", iface, llTime); - return E_NOTIMPL; +static HRESULT WINAPI MediaPosition_put_StopTime(IMediaPosition * iface, REFTIME llTime) +{ + IFilterGraphImpl *This = impl_from_IMediaPosition( iface ); + LONGLONG reftime = llTime; + + return IMediaSeeking_SetPositions((IMediaSeeking *)&This->IMediaSeeking_vtbl, + NULL, AM_SEEKING_NoPositioning, + &reftime, AM_SEEKING_AbsolutePositioning); } static HRESULT WINAPI MediaPosition_get_PrerollTime(IMediaPosition * iface, REFTIME *pllTime){ @@ -2641,14 +2666,16 @@ static HRESULT WINAPI MediaPosition_put_PrerollTime(IMediaPosition * iface, REFT return E_NOTIMPL; } -static HRESULT WINAPI MediaPosition_put_Rate(IMediaPosition * iface, double dRate){ - FIXME("(%p)->(%f) stub!\n", iface, dRate); - return E_NOTIMPL; +static HRESULT WINAPI MediaPosition_put_Rate(IMediaPosition * iface, double dRate) +{ + IFilterGraphImpl *This = impl_from_IMediaPosition( iface ); + return IMediaSeeking_SetRate((IMediaSeeking *)&This->IMediaSeeking_vtbl, dRate); } -static HRESULT WINAPI MediaPosition_get_Rate(IMediaPosition * iface, double *pdRate){ - FIXME("(%p)->(%p) stub!\n", iface, pdRate); - return E_NOTIMPL; +static HRESULT WINAPI MediaPosition_get_Rate(IMediaPosition * iface, double *pdRate) +{ + IFilterGraphImpl *This = impl_from_IMediaPosition( iface ); + return IMediaSeeking_GetRate((IMediaSeeking *)&This->IMediaSeeking_vtbl, pdRate); } static HRESULT WINAPI MediaPosition_CanSeekForward(IMediaPosition * iface, LONG *pCanSeekForward){ diff --git a/dlls/rpcrt4/ndr_fullpointer.c b/dlls/rpcrt4/ndr_fullpointer.c index b686683f6f4..2bbd2b2b1aa 100644 --- a/dlls/rpcrt4/ndr_fullpointer.c +++ b/dlls/rpcrt4/ndr_fullpointer.c @@ -161,6 +161,9 @@ int WINAPI NdrFullPointerQueryRefId(PFULL_PTR_XLAT_TABLES pXlatTables, { TRACE("(%p, 0x%x, %d, %p)\n", pXlatTables, RefId, QueryType, ppPointer); + if (!RefId) + return 1; + expand_pointer_table_if_necessary(pXlatTables, RefId); pXlatTables->NextRefId = max(RefId + 1, pXlatTables->NextRefId); diff --git a/dlls/rpcrt4/ndr_marshall.c b/dlls/rpcrt4/ndr_marshall.c index d1b57fd187a..8db45b8f6f3 100644 --- a/dlls/rpcrt4/ndr_marshall.c +++ b/dlls/rpcrt4/ndr_marshall.c @@ -935,7 +935,7 @@ static void PointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, if (type == RPC_FC_FP) NdrFullPointerInsertRefId(pStubMsg->FullPtrXlatTables, pointer_id, - base_ptr_val); + *pPointer); } TRACE("pointer=%p\n", *pPointer); diff --git a/dlls/rpcrt4/ndr_stubless.c b/dlls/rpcrt4/ndr_stubless.c index 8150238f8fd..bf6a7bea37a 100644 --- a/dlls/rpcrt4/ndr_stubless.c +++ b/dlls/rpcrt4/ndr_stubless.c @@ -686,7 +686,8 @@ LONG_PTR WINAPIV NdrClientCall2(PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pForma * 4. PROXY_SENDRECEIVE - send/receive buffer * 5. PROXY_UNMARHSAL - unmarshal [out] params from buffer */ - if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) + if ((pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) || + (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_HAS_COMM_OR_FAULT)) { __TRY { @@ -696,13 +697,56 @@ LONG_PTR WINAPIV NdrClientCall2(PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pForma switch (phase) { case PROXY_GETBUFFER: - /* allocate the buffer */ - NdrProxyGetBuffer(This, &stubMsg); + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) + { + /* allocate the buffer */ + NdrProxyGetBuffer(This, &stubMsg); + } + else + { + /* allocate the buffer */ + if (Oif_flags.HasPipes) + /* NdrGetPipeBuffer(...) */ + FIXME("pipes not supported yet\n"); + else + { + if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE) +#if 0 + NdrNsGetBuffer(&stubMsg, stubMsg.BufferLength, hBinding); +#else + FIXME("using auto handle - call NdrNsGetBuffer when it gets implemented\n"); +#endif + else + NdrGetBuffer(&stubMsg, stubMsg.BufferLength, hBinding); + } + } break; case PROXY_SENDRECEIVE: - /* send the [in] params and receive the [out] and [retval] - * params */ - NdrProxySendReceive(This, &stubMsg); + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) + { + /* send the [in] params and receive the [out] and [retval] + * params */ + NdrProxySendReceive(This, &stubMsg); + } + else + { + /* send the [in] params and receive the [out] and [retval] + * params */ + if (Oif_flags.HasPipes) + /* NdrPipesSendReceive(...) */ + FIXME("pipes not supported yet\n"); + else + { + if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE) +#if 0 + NdrNsSendReceive(&stubMsg, stubMsg.Buffer, pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle); +#else + FIXME("using auto handle - call NdrNsSendReceive when it gets implemented\n"); +#endif + else + NdrSendReceive(&stubMsg, stubMsg.Buffer); + } + } /* convert strings, floating point values and endianess into our * preferred format */ @@ -729,7 +773,33 @@ LONG_PTR WINAPIV NdrClientCall2(PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pForma } __EXCEPT_ALL { - RetVal = NdrProxyErrorHandler(GetExceptionCode()); + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) + RetVal = NdrProxyErrorHandler(GetExceptionCode()); + else + { + const COMM_FAULT_OFFSETS *comm_fault_offsets = &pStubDesc->CommFaultOffsets[procedure_number]; + ULONG *comm_status; + ULONG *fault_status; + + TRACE("comm_fault_offsets = {0x%hx, 0x%hx}\n", comm_fault_offsets->CommOffset, comm_fault_offsets->FaultOffset); + + if (comm_fault_offsets->CommOffset == -1) + comm_status = (ULONG *)&RetVal; + else if (comm_fault_offsets->CommOffset >= 0) + comm_status = *(ULONG **)ARG_FROM_OFFSET(stubMsg.StackTop, comm_fault_offsets->CommOffset); + else + comm_status = NULL; + + if (comm_fault_offsets->FaultOffset == -1) + fault_status = (ULONG *)&RetVal; + else if (comm_fault_offsets->FaultOffset >= 0) + fault_status = *(ULONG **)ARG_FROM_OFFSET(stubMsg.StackTop, comm_fault_offsets->CommOffset); + else + fault_status = NULL; + + NdrMapCommAndFaultStatus(&stubMsg, comm_status, fault_status, + GetExceptionCode()); + } } __ENDTRY } diff --git a/dlls/rpcrt4/rpc_binding.c b/dlls/rpcrt4/rpc_binding.c index b264b9a2bb8..212e201dbbb 100644 --- a/dlls/rpcrt4/rpc_binding.c +++ b/dlls/rpcrt4/rpc_binding.c @@ -785,8 +785,11 @@ RPC_STATUS WINAPI RpcBindingFree( RPC_BINDING_HANDLE* Binding ) { RPC_STATUS status; TRACE("(%p) = %p\n", Binding, *Binding); - status = RPCRT4_ReleaseBinding(*Binding); - if (status == RPC_S_OK) *Binding = 0; + if (*Binding) + status = RPCRT4_ReleaseBinding(*Binding); + else + status = RPC_S_INVALID_BINDING; + if (status == RPC_S_OK) *Binding = NULL; return status; } diff --git a/dlls/rpcrt4/rpc_epmap.c b/dlls/rpcrt4/rpc_epmap.c index c1b8d1d922f..b81367e4160 100644 --- a/dlls/rpcrt4/rpc_epmap.c +++ b/dlls/rpcrt4/rpc_epmap.c @@ -108,8 +108,8 @@ static inline BOOL is_epm_destination_local(RPC_BINDING_HANDLE handle) const char *protseq = bind->Protseq; const char *network_addr = bind->NetworkAddr; - return ((!strcmp(protseq, "ncalrpc") && !network_addr) || - (!strcmp(protseq, "ncacn_np") && + return (!strcmp(protseq, "ncalrpc") || + (!strcmp(protseq, "ncacn_np") && (!network_addr || !strcmp(network_addr, ".")))); } diff --git a/dlls/rpcrt4/rpc_server.c b/dlls/rpcrt4/rpc_server.c index 1bd123592bf..84e8854194e 100644 --- a/dlls/rpcrt4/rpc_server.c +++ b/dlls/rpcrt4/rpc_server.c @@ -203,6 +203,7 @@ static RPC_STATUS process_bind_packet(RpcConnection *conn, RpcPktBindHdr *hdr, R response = RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION, RPC_VER_MAJOR, RPC_VER_MINOR, REJECT_LOCAL_LIMIT_EXCEEDED); + goto send; } for (i = 0, ctxt_elem = (RpcContextElement *)msg->Buffer; diff --git a/dlls/rpcrt4/tests/ndr_marshall.c b/dlls/rpcrt4/tests/ndr_marshall.c index 97811152edc..91f3040c323 100644 --- a/dlls/rpcrt4/tests/ndr_marshall.c +++ b/dlls/rpcrt4/tests/ndr_marshall.c @@ -1046,6 +1046,9 @@ static void test_fullpointer_xlat(void) /* "unmarshaling" phase */ + ret = NdrFullPointerQueryRefId(pXlatTables, 0x0, 0, &Pointer); + ok(ret == 1, "ret should be 1 instead of 0x%x\n", ret); + ret = NdrFullPointerQueryRefId(pXlatTables, 0x2, 0, &Pointer); ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret); ok(Pointer == (void *)0xcafebabe, "Pointer should be 0xcafebabe instead of %p\n", Pointer); diff --git a/dlls/rpcrt4/tests/rpc.c b/dlls/rpcrt4/tests/rpc.c index 01d7392fe4d..0f742b20b48 100644 --- a/dlls/rpcrt4/tests/rpc.c +++ b/dlls/rpcrt4/tests/rpc.c @@ -800,6 +800,17 @@ static void test_UuidCreate(void) } } +static void test_RpcBindingFree(void) +{ + RPC_BINDING_HANDLE binding = NULL; + RPC_STATUS status; + + status = RpcBindingFree(&binding); + ok(status == RPC_S_INVALID_BINDING, + "RpcBindingFree should have retured RPC_S_INVALID_BINDING instead of %d\n", + status); +} + START_TEST( rpc ) { UuidConversionAndComparison(); @@ -811,4 +822,5 @@ START_TEST( rpc ) test_I_RpcExceptionFilter(); test_RpcStringBindingFromBinding(); test_UuidCreate(); + test_RpcBindingFree(); } diff --git a/dlls/rpcrt4/tests/server.c b/dlls/rpcrt4/tests/server.c index 1205ea47d09..6453f5304c4 100644 --- a/dlls/rpcrt4/tests/server.c +++ b/dlls/rpcrt4/tests/server.c @@ -717,6 +717,21 @@ s_get_numbers_struct(numbers_struct_t **ns) } void +s_full_pointer_test(int *a, int *b) +{ + ok(*a == 42, "Expected *a to be 42 instead of %d\n", *a); + ok(*b == 42, "Expected *b to be 42 instead of %d\n", *a); + ok(a == b, "Expected a (%p) to point to the same memory as b (%p)\n", a, b); +} + +void +s_full_pointer_null_test(int *a, int *b) +{ + ok(*a == 42, "Expected *a to be 42 instead of %d\n", *a); + ok(b == NULL, "Expected b to be NULL instead of %p\n", b); +} + +void s_stop(void) { ok(RPC_S_OK == RpcMgmtStopServerListening(NULL), "RpcMgmtStopServerListening\n"); @@ -1077,6 +1092,7 @@ pointer_tests(void) void *buffer; int *pa2; s123_t *s123; + int val = 42; ok(test_list_length(list) == 3, "RPC test_list_length\n"); ok(square_puint(p1) == 121, "RPC square_puint\n"); @@ -1137,6 +1153,9 @@ pointer_tests(void) s123 = get_s123(); ok(s123->f1 == 1 && s123->f2 == 2 && s123->f3 == 3, "RPC get_s123\n"); MIDL_user_free(s123); + + full_pointer_test(&val, &val); + full_pointer_null_test(&val, NULL); } static int diff --git a/dlls/rpcrt4/tests/server.idl b/dlls/rpcrt4/tests/server.idl index d8e79bd9556..ee03c0bd8aa 100644 --- a/dlls/rpcrt4/tests/server.idl +++ b/dlls/rpcrt4/tests/server.idl @@ -357,5 +357,9 @@ cpp_quote("#endif") void get_ranged_enum([out] renum_t *re); void context_handle_test(void); + + void full_pointer_test([in, ptr] int *a, [in, ptr] int *b); + void full_pointer_null_test([in, ptr] int *a, [in, ptr] int *b); + void stop(void); } diff --git a/dlls/rsaenh/tests/rsaenh.c b/dlls/rsaenh/tests/rsaenh.c index e59ad95a8c2..b56f4d415a3 100644 --- a/dlls/rsaenh/tests/rsaenh.c +++ b/dlls/rsaenh/tests/rsaenh.c @@ -72,9 +72,15 @@ static void uniquecontainer(char *unique) HKEY hkey; char guid[MAX_PATH]; DWORD size = MAX_PATH; + HRESULT ret; /* Get the MachineGUID */ - RegOpenKeyA(HKEY_LOCAL_MACHINE, szCryptography, &hkey); + ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, szCryptography, 0, KEY_READ | KEY_WOW64_64KEY, &hkey); + if (ret == ERROR_ACCESS_DENIED) + { + /* Windows 2000 can't handle KEY_WOW64_64KEY */ + RegOpenKeyA(HKEY_LOCAL_MACHINE, szCryptography, &hkey); + } RegQueryValueExA(hkey, szMachineGuid, NULL, NULL, (LPBYTE)guid, &size); RegCloseKey(hkey); @@ -2085,7 +2091,7 @@ static void test_rsa_round_trip(void) if (result) { ok(dataLen == sizeof(test_string), "unexpected size %d\n", dataLen); - ok(!memcmp(data, test_string, sizeof(test_string)), "unexpected value"); + ok(!memcmp(data, test_string, sizeof(test_string)), "unexpected value\n"); } CryptReleaseContext(prov, 0); diff --git a/dlls/secur32/schannel.c b/dlls/secur32/schannel.c index af9402410f6..27cb1b75e03 100644 --- a/dlls/secur32/schannel.c +++ b/dlls/secur32/schannel.c @@ -1203,6 +1203,9 @@ static SECURITY_STATUS SEC_ENTRY schan_DecryptMessage(PCtxtHandle context_handle return SEC_E_INTERNAL_ERROR; } } + else if (!ret) + break; + received += ret; } diff --git a/dlls/setupapi/tests/install.c b/dlls/setupapi/tests/install.c index 35514d5bdff..9aa5a911ee3 100644 --- a/dlls/setupapi/tests/install.c +++ b/dlls/setupapi/tests/install.c @@ -35,6 +35,7 @@ #include "wine/test.h" static const char inffile[] = "test.inf"; +static const WCHAR inffileW[] = {'t','e','s','t','.','i','n','f',0}; static char CURR_DIR[MAX_PATH]; /* Notes on InstallHinfSectionA/W: @@ -470,12 +471,13 @@ cleanup: static void test_inffilelist(void) { static const char inffile2[] = "test2.inf"; + static const WCHAR inffile2W[] = {'t','e','s','t','2','.','i','n','f',0}; static const char invalid_inf[] = "invalid.inf"; static const char *inf = "[Version]\n" "Signature=\"$Chicago$\""; - WCHAR *ptr; + WCHAR *p, *ptr; WCHAR dir[MAX_PATH] = { 0 }; WCHAR buffer[MAX_PATH] = { 0 }; DWORD expected, outsize; @@ -560,7 +562,9 @@ static void test_inffilelist(void) todo_wine ok(expected == outsize, "expected required buffersize to be %d, got %d\n", expected, outsize); - + for(p = buffer; lstrlenW(p) && (outsize > (p - buffer)); p+=lstrlenW(p) + 1) + ok(!lstrcmpW(p,inffile2W) || !lstrcmpW(p,inffileW), + "unexpected filename %s\n",wine_dbgstr_w(p)); DeleteFile(inffile); DeleteFile(inffile2); diff --git a/dlls/shdocvw/oleobject.c b/dlls/shdocvw/oleobject.c index 3657a7a5276..dde850f08c7 100644 --- a/dlls/shdocvw/oleobject.c +++ b/dlls/shdocvw/oleobject.c @@ -282,7 +282,9 @@ static ULONG WINAPI OleObject_Release(IOleObject *iface) static HRESULT WINAPI OleObject_SetClientSite(IOleObject *iface, LPOLECLIENTSITE pClientSite) { WebBrowser *This = OLEOBJ_THIS(iface); + IDocHostUIHandler *hostui; IOleContainer *container; + IDispatch *disp; HRESULT hres; TRACE("(%p)->(%p)\n", This, pClientSite); @@ -322,11 +324,15 @@ static HRESULT WINAPI OleObject_SetClientSite(IOleObject *iface, LPOLECLIENTSITE IOleClientSite_AddRef(pClientSite); - IOleClientSite_QueryInterface(This->client, &IID_IDispatch, - (void**)&This->doc_host.client_disp); + hres = IOleClientSite_QueryInterface(This->client, &IID_IDispatch, + (void**)&disp); + if(SUCCEEDED(hres)) + This->doc_host.client_disp = disp; - IOleClientSite_QueryInterface(This->client, &IID_IDocHostUIHandler, - (void**)&This->doc_host.hostui); + hres = IOleClientSite_QueryInterface(This->client, &IID_IDocHostUIHandler, + (void**)&hostui); + if(SUCCEEDED(hres)) + This->doc_host.hostui = hostui; hres = IOleClientSite_GetContainer(This->client, &container); if(SUCCEEDED(hres)) { diff --git a/dlls/shdocvw/tests/webbrowser.c b/dlls/shdocvw/tests/webbrowser.c index 745ac15628a..41b7c7d2eee 100644 --- a/dlls/shdocvw/tests/webbrowser.c +++ b/dlls/shdocvw/tests/webbrowser.c @@ -2368,40 +2368,8 @@ static void test_WebBrowser(BOOL do_download) ok(ref == 0, "ref=%d, expected 0\n", ref); } -static void gecko_installer_workaround(BOOL disable) -{ - HKEY hkey; - DWORD res; - - static BOOL has_url = FALSE; - static char url[2048]; - - if(!disable && !has_url) - return; - - res = RegOpenKey(HKEY_CURRENT_USER, "Software\\Wine\\MSHTML", &hkey); - if(res != ERROR_SUCCESS) - return; - - if(disable) { - DWORD type, size = sizeof(url); - - res = RegQueryValueEx(hkey, "GeckoUrl", NULL, &type, (PVOID)url, &size); - if(res == ERROR_SUCCESS && type == REG_SZ) - has_url = TRUE; - - RegDeleteValue(hkey, "GeckoUrl"); - }else { - RegSetValueEx(hkey, "GeckoUrl", 0, REG_SZ, (PVOID)url, lstrlenA(url)+1); - } - - RegCloseKey(hkey); -} - START_TEST(webbrowser) { - gecko_installer_workaround(TRUE); - container_hwnd = create_container_window(); OleInitialize(NULL); @@ -2412,6 +2380,4 @@ START_TEST(webbrowser) test_WebBrowser(TRUE); OleUninitialize(); - - gecko_installer_workaround(FALSE); } diff --git a/dlls/shell32/assoc.c b/dlls/shell32/assoc.c index bf9ccb97f39..85efa07451c 100644 --- a/dlls/shell32/assoc.c +++ b/dlls/shell32/assoc.c @@ -320,16 +320,25 @@ static HRESULT ASSOC_GetExecutable(IQueryAssociationsImpl *This, { pszStart = pszCommand + 1; pszEnd = strchrW(pszStart, '"'); + if (pszEnd) + *pszEnd = 0; + *len = SearchPathW(NULL, pszStart, NULL, pathlen, path, NULL); } else { pszStart = pszCommand; - pszEnd = strchrW(pszStart, ' '); + for (pszEnd = pszStart; (pszEnd = strchrW(pszEnd, ' ')); pszEnd++) + { + WCHAR c = *pszEnd; + *pszEnd = 0; + if ((*len = SearchPathW(NULL, pszStart, NULL, pathlen, path, NULL))) + break; + *pszEnd = c; + } + if (!pszEnd) + *len = SearchPathW(NULL, pszStart, NULL, pathlen, path, NULL); } - if (pszEnd) - *pszEnd = 0; - *len = SearchPathW(NULL, pszStart, NULL, pathlen, path, NULL); HeapFree(GetProcessHeap(), 0, pszCommand); if (!*len) return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); diff --git a/dlls/shell32/shelllink.c b/dlls/shell32/shelllink.c index 414cc54e8ab..3b161705cc7 100644 --- a/dlls/shell32/shelllink.c +++ b/dlls/shell32/shelllink.c @@ -1497,9 +1497,13 @@ static HRESULT WINAPI IShellLinkA_fnSetArguments(IShellLinkA * iface, LPCSTR psz TRACE("(%p)->(args=%s)\n",This, pszArgs); HeapFree(GetProcessHeap(), 0, This->sArgs); - This->sArgs = HEAP_strdupAtoW( GetProcessHeap(), 0, pszArgs); - if( !This->sArgs ) - return E_OUTOFMEMORY; + if (pszArgs) + { + This->sArgs = HEAP_strdupAtoW( GetProcessHeap(), 0, pszArgs); + if( !This->sArgs ) + return E_OUTOFMEMORY; + } + else This->sArgs = NULL; This->bDirty = TRUE; @@ -1877,11 +1881,16 @@ static HRESULT WINAPI IShellLinkW_fnSetArguments(IShellLinkW * iface, LPCWSTR ps TRACE("(%p)->(args=%s)\n",This, debugstr_w(pszArgs)); HeapFree(GetProcessHeap(), 0, This->sArgs); - This->sArgs = HeapAlloc( GetProcessHeap(), 0, - (lstrlenW( pszArgs )+1)*sizeof (WCHAR) ); - if ( !This->sArgs ) - return E_OUTOFMEMORY; - lstrcpyW( This->sArgs, pszArgs ); + if (pszArgs) + { + This->sArgs = HeapAlloc( GetProcessHeap(), 0, + (lstrlenW( pszArgs )+1)*sizeof (WCHAR) ); + if ( !This->sArgs ) + return E_OUTOFMEMORY; + lstrcpyW( This->sArgs, pszArgs ); + } + else This->sArgs = NULL; + This->bDirty = TRUE; return S_OK; diff --git a/dlls/shell32/shellord.c b/dlls/shell32/shellord.c index fd942f7f8f9..940633e59d5 100644 --- a/dlls/shell32/shellord.c +++ b/dlls/shell32/shellord.c @@ -46,6 +46,7 @@ #include "pidl.h" #include "shlwapi.h" #include "commdlg.h" +#include "commoncontrols.h" WINE_DEFAULT_DEBUG_CHANNEL(shell); WINE_DECLARE_DEBUG_CHANNEL(pidl); @@ -169,7 +170,7 @@ DWORD WINAPI ParseFieldAW(LPCVOID src, DWORD nField, LPVOID dst, DWORD len) /************************************************************************* * GetFileNameFromBrowseA [internal] */ -BOOL WINAPI GetFileNameFromBrowseA( +static BOOL GetFileNameFromBrowseA( HWND hwndOwner, LPSTR lpstrFile, DWORD nMaxFile, @@ -216,7 +217,7 @@ BOOL WINAPI GetFileNameFromBrowseA( /************************************************************************* * GetFileNameFromBrowseW [internal] */ -BOOL WINAPI GetFileNameFromBrowseW( +static BOOL GetFileNameFromBrowseW( HWND hwndOwner, LPWSTR lpstrFile, DWORD nMaxFile, @@ -2173,10 +2174,40 @@ void WINAPI SHFlushSFCache(void) { } +/************************************************************************* + * SHGetImageList (SHELL32.727) + * + * Returns a copy of a shell image list. + * + * NOTES + * Windows XP features 4 sizes of image list, and Vista 5. Wine currently + * only supports the traditional small and large image lists, so requests + * for the others will currently fail. + */ HRESULT WINAPI SHGetImageList(int iImageList, REFIID riid, void **ppv) { - FIXME("STUB: %i %s\n",iImageList,debugstr_guid(riid)); - return E_NOINTERFACE; + HIMAGELIST hLarge, hSmall; + HIMAGELIST hNew; + HRESULT ret = E_FAIL; + + /* Wine currently only maintains large and small image lists */ + if ((iImageList != SHIL_LARGE) && (iImageList != SHIL_SMALL) && (iImageList != SHIL_SYSSMALL)) + { + FIXME("Unsupported image list %i requested\n", iImageList); + return E_FAIL; + } + + Shell_GetImageList(&hLarge, &hSmall); + hNew = ImageList_Duplicate(iImageList == SHIL_LARGE ? hLarge : hSmall); + + /* Get the interface for the new image list */ + if (hNew) + { + ret = HIMAGELIST_QueryInterface(hNew, riid, ppv); + ImageList_Destroy(hNew); + } + + return ret; } /************************************************************************* diff --git a/dlls/shell32/shfldr_unixfs.c b/dlls/shell32/shfldr_unixfs.c index 9d4e956d81c..921b9c03e35 100644 --- a/dlls/shell32/shfldr_unixfs.c +++ b/dlls/shell32/shfldr_unixfs.c @@ -1468,7 +1468,7 @@ static HRESULT WINAPI UnixFolder_IPersistFolder3_Initialize(IPersistFolder3* ifa current = ILGetNext(current); } - if (current && current->mkid.cb) { + if (current->mkid.cb) { if (_ILIsDrive(current)) { WCHAR wszDrive[4] = { '?', ':', '\\', 0 }; wszDrive[0] = (WCHAR)*_ILGetTextPointer(current); diff --git a/dlls/shell32/tests/progman_dde.c b/dlls/shell32/tests/progman_dde.c index e4867e1a986..09eb7916d8e 100644 --- a/dlls/shell32/tests/progman_dde.c +++ b/dlls/shell32/tests/progman_dde.c @@ -26,6 +26,13 @@ * as documented * Better AddItem Tests (Lots of parameters to test) * Tests for Invalid Characters in Names / Invalid Parameters + * - Technically, calling as an administrator creates groups in the CSIDL_COMMON_PROGRAMS + * directory. Win 9x and non-administrator calls us CSIDL_PROGRAMS directory. + * Original plans were to check that items/groups were created in appropriate + * places. As of this writing and in order to simplify the test code, it now + * checks for existence in either place. From web searches, it is not at all + * obvious or trivial to detect if the call is coming from an administrator or + * non-administrator. IsUserAnAdmin */ #include @@ -39,9 +46,9 @@ /* Timeout on DdeClientTransaction Call */ #define MS_TIMEOUT_VAL 1000 /* # of times to poll for window creation */ -#define PDDE_POLL_NUM 50 +#define PDDE_POLL_NUM 150 /* time to sleep between polls */ -#define PDDE_POLL_TIME 200 +#define PDDE_POLL_TIME 300 /* Call Info */ #define DDE_TEST_MISC 0x00010000 @@ -69,6 +76,45 @@ static void init_function_pointers(void) pSHGetSpecialFolderPathA = (void*)GetProcAddress(hmod, "SHGetSpecialFolderPathA"); } +static char Group1Title[MAX_PATH] = "Group1"; +static char Group2Title[MAX_PATH] = "Group2"; +static char Group3Title[MAX_PATH] = "Group3"; +static char Startup[MAX_PATH] = "Startup"; +static char StartupTitle[MAX_PATH] = "Startup"; + +static void init_strings(void) +{ + HKEY key; + DWORD fullpath = 0; + DWORD size = sizeof(DWORD); + + if (!pSHGetSpecialFolderPathA) + return; + + RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CabinetState", &key); + RegQueryValueExA(key, "FullPath", NULL, NULL, (LPBYTE)&fullpath, &size); + RegCloseKey(key); + if (fullpath == 1) + { + BOOL ret; + char commonprog[MAX_PATH], startup[MAX_PATH]; + + ret = SHGetSpecialFolderPathA(NULL, commonprog, CSIDL_COMMON_PROGRAMS, FALSE); + if (!ret) /* Win9x */ + SHGetSpecialFolderPathA(NULL, commonprog, CSIDL_PROGRAMS, FALSE); + lstrcpyA(Group1Title, commonprog); + lstrcatA(Group1Title, "\\Group1"); + lstrcpyA(Group2Title, commonprog); + lstrcatA(Group2Title, "\\Group2"); + lstrcpyA(Group3Title, commonprog); + lstrcatA(Group3Title, "\\Group3"); + + SHGetSpecialFolderPathA(NULL, startup, CSIDL_STARTUP, FALSE); + lstrcpyA(StartupTitle, startup); + lstrcpyA(Startup, (strrchr(StartupTitle, '\\') + 1)); + } +} + static HDDEDATA CALLBACK DdeCallback(UINT type, UINT format, HCONV hConv, HSZ hsz1, HSZ hsz2, HDDEDATA hDDEData, ULONG_PTR data1, ULONG_PTR data2) { @@ -121,7 +167,6 @@ static const char * GetStringFromTestParams(int testParams) #define DMLERR_TO_STR(x) case x: return#x; static const char * GetStringFromError(UINT err) { - const char * retstr; switch (err) { DMLERR_TO_STR(DMLERR_NO_ERROR); @@ -144,11 +189,8 @@ static const char * GetStringFromError(UINT err) DMLERR_TO_STR(DMLERR_UNADVACKTIMEOUT); DMLERR_TO_STR(DMLERR_UNFOUND_QUEUE_ID); default: - retstr = "Unknown DML Error"; - break; + return "Unknown DML Error"; } - - return retstr; } /* Helper Function to Transfer DdeGetLastError into a String */ @@ -196,6 +238,7 @@ static void DdeExecuteCommand(DWORD instance, HCONV hConv, const char *strCmd, H *hData, GetStringFromTestParams(testParams)); } } + DdeFreeDataHandle(command); } /* @@ -312,7 +355,7 @@ static void CheckFileExistsInProgramGroups(const char *nameToCheck, int shouldEx * 2. window is open */ static void CreateGroupTest(DWORD instance, HCONV hConv, const char *command, UINT expected_result, - const char *groupName, int testParams) + const char *groupName, const char *windowTitle, int testParams) { HDDEDATA hData; UINT error; @@ -333,7 +376,7 @@ static void CreateGroupTest(DWORD instance, HCONV hConv, const char *command, UI /* Check if Group Now Exists */ CheckFileExistsInProgramGroups(groupName, TRUE, TRUE, NULL, testParams); /* Check if Window is Open (polling) */ - CheckWindowCreated(groupName, TRUE, testParams); + CheckWindowCreated(windowTitle, TRUE, testParams); } } @@ -343,7 +386,7 @@ static void CreateGroupTest(DWORD instance, HCONV hConv, const char *command, UI * 1. window is open */ static void ShowGroupTest(DWORD instance, HCONV hConv, const char *command, UINT expected_result, - const char *groupName, int closeAfterShowing, int testParams) + const char *groupName, const char *windowTitle, int closeAfterShowing, int testParams) { HDDEDATA hData; UINT error; @@ -368,7 +411,7 @@ static void ShowGroupTest(DWORD instance, HCONV hConv, const char *command, UINT if (error == DMLERR_NO_ERROR) { /* Check if Window is Open (polling) */ - CheckWindowCreated(groupName, closeAfterShowing, testParams); + CheckWindowCreated(windowTitle, closeAfterShowing, testParams); } } @@ -457,7 +500,7 @@ static void DeleteItemTest(DWORD instance, HCONV hConv, const char *command, UIN * AddItems) so this covers minimum expected functionality. */ static void CompoundCommandTest(DWORD instance, HCONV hConv, const char *command, UINT expected_result, - const char *groupName, const char *fileName1, + const char *groupName, const char *windowTitle, const char *fileName1, const char *fileName2, int testParams) { HDDEDATA hData; @@ -475,7 +518,7 @@ static void CompoundCommandTest(DWORD instance, HCONV hConv, const char *command { /* Check that File exists */ CheckFileExistsInProgramGroups(groupName, TRUE, TRUE, NULL, testParams); - CheckWindowCreated(groupName, FALSE, testParams); + CheckWindowCreated(windowTitle, FALSE, testParams); CheckFileExistsInProgramGroups(fileName1, TRUE, FALSE, groupName, testParams); CheckFileExistsInProgramGroups(fileName2, TRUE, FALSE, groupName, testParams); } @@ -495,26 +538,26 @@ static int DdeTestProgman(DWORD instance, HCONV hConv) GetStringFromError(DMLERR_NOTPROCESSED), GetStringFromError(error)); /* CreateGroup Tests (including AddItem, DeleteItem) */ - CreateGroupTest(instance, hConv, "[CreateGroup(Group1)]", DMLERR_NO_ERROR, "Group1", DDE_TEST_COMMON|DDE_TEST_CREATEGROUP|testnum++); + CreateGroupTest(instance, hConv, "[CreateGroup(Group1)]", DMLERR_NO_ERROR, "Group1", Group1Title, DDE_TEST_COMMON|DDE_TEST_CREATEGROUP|testnum++); AddItemTest(instance, hConv, "[AddItem(c:\\f1g1,f1g1Name)]", DMLERR_NO_ERROR, "f1g1Name.lnk", "Group1", DDE_TEST_COMMON|DDE_TEST_ADDITEM|testnum++); AddItemTest(instance, hConv, "[AddItem(c:\\f2g1,f2g1Name)]", DMLERR_NO_ERROR, "f2g1Name.lnk", "Group1", DDE_TEST_COMMON|DDE_TEST_ADDITEM|testnum++); DeleteItemTest(instance, hConv, "[DeleteItem(f2g1Name)]", DMLERR_NO_ERROR, "f2g1Name.lnk", "Group1", DDE_TEST_COMMON|DDE_TEST_DELETEITEM|testnum++); AddItemTest(instance, hConv, "[AddItem(c:\\f3g1,f3g1Name)]", DMLERR_NO_ERROR, "f3g1Name.lnk", "Group1", DDE_TEST_COMMON|DDE_TEST_ADDITEM|testnum++); - CreateGroupTest(instance, hConv, "[CreateGroup(Group2)]", DMLERR_NO_ERROR, "Group2", DDE_TEST_COMMON|DDE_TEST_CREATEGROUP|testnum++); + CreateGroupTest(instance, hConv, "[CreateGroup(Group2)]", DMLERR_NO_ERROR, "Group2", Group2Title, DDE_TEST_COMMON|DDE_TEST_CREATEGROUP|testnum++); /* Create Group that already exists - same instance */ - CreateGroupTest(instance, hConv, "[CreateGroup(Group1)]", DMLERR_NO_ERROR, "Group1", DDE_TEST_COMMON|DDE_TEST_CREATEGROUP|testnum++); + CreateGroupTest(instance, hConv, "[CreateGroup(Group1)]", DMLERR_NO_ERROR, "Group1", Group1Title, DDE_TEST_COMMON|DDE_TEST_CREATEGROUP|testnum++); /* ShowGroup Tests */ - ShowGroupTest(instance, hConv, "[ShowGroup(Group1)]", DMLERR_NOTPROCESSED, "Startup", TRUE, DDE_TEST_SHOWGROUP|testnum++); + ShowGroupTest(instance, hConv, "[ShowGroup(Group1)]", DMLERR_NOTPROCESSED, Startup, StartupTitle, TRUE, DDE_TEST_SHOWGROUP|testnum++); DeleteItemTest(instance, hConv, "[DeleteItem(f3g1Name)]", DMLERR_NO_ERROR, "f3g1Name.lnk", "Group1", DDE_TEST_COMMON|DDE_TEST_DELETEITEM|testnum++); - ShowGroupTest(instance, hConv, "[ShowGroup(Startup,0)]", DMLERR_NO_ERROR, "Startup", TRUE, DDE_TEST_SHOWGROUP|testnum++); - ShowGroupTest(instance, hConv, "[ShowGroup(Group1,0)]", DMLERR_NO_ERROR, "Group1", FALSE, DDE_TEST_SHOWGROUP|testnum++); + ShowGroupTest(instance, hConv, "[ShowGroup(Startup,0)]", DMLERR_NO_ERROR, Startup, StartupTitle, TRUE, DDE_TEST_SHOWGROUP|testnum++); + ShowGroupTest(instance, hConv, "[ShowGroup(Group1,0)]", DMLERR_NO_ERROR, "Group1", Group1Title, FALSE, DDE_TEST_SHOWGROUP|testnum++); /* DeleteGroup Test - Note that Window is Open for this test */ DeleteGroupTest(instance, hConv, "[DeleteGroup(Group1)]", DMLERR_NO_ERROR, "Group1", DDE_TEST_DELETEGROUP|testnum++); /* Compound Execute String Command */ - CompoundCommandTest(instance, hConv, "[CreateGroup(Group3)][AddItem(c:\\f1g3,f1g3Name)][AddItem(c:\\f2g3,f2g3Name)]", DMLERR_NO_ERROR, "Group3", "f1g3Name.lnk", "f2g3Name.lnk", DDE_TEST_COMMON|DDE_TEST_COMPOUND|testnum++); + CompoundCommandTest(instance, hConv, "[CreateGroup(Group3)][AddItem(c:\\f1g3,f1g3Name)][AddItem(c:\\f2g3,f2g3Name)]", DMLERR_NO_ERROR, "Group3", Group3Title, "f1g3Name.lnk", "f2g3Name.lnk", DDE_TEST_COMMON|DDE_TEST_COMPOUND|testnum++); DeleteGroupTest(instance, hConv, "[DeleteGroup(Group3)]", DMLERR_NO_ERROR, "Group3", DDE_TEST_DELETEGROUP|testnum++); /* Full Parameters of Add Item */ @@ -527,7 +570,7 @@ static int DdeTestProgman(DWORD instance, HCONV hConv) static void DdeTestProgman2(DWORD instance, HCONV hConv, int testnum) { /* Create Group that already exists on a separate connection */ - CreateGroupTest(instance, hConv, "[CreateGroup(Group2)]", DMLERR_NO_ERROR, "Group2", DDE_TEST_COMMON|DDE_TEST_CREATEGROUP|testnum++); + CreateGroupTest(instance, hConv, "[CreateGroup(Group2)]", DMLERR_NO_ERROR, "Group2", Group2Title, DDE_TEST_COMMON|DDE_TEST_CREATEGROUP|testnum++); DeleteGroupTest(instance, hConv, "[DeleteGroup(Group2)]", DMLERR_NO_ERROR, "Group2", DDE_TEST_COMMON|DDE_TEST_DELETEGROUP|testnum++); } @@ -540,6 +583,7 @@ START_TEST(progman_dde) int testnum; init_function_pointers(); + init_strings(); /* Only report this once */ if (!pSHGetSpecialFolderPathA) @@ -553,8 +597,13 @@ START_TEST(progman_dde) hszProgman = DdeCreateStringHandle(instance, "PROGMAN", CP_WINANSI); ok (hszProgman != NULL, "DdeCreateStringHandle Error %s\n", GetDdeLastErrorStr(instance)); hConv = DdeConnect(instance, hszProgman, hszProgman, NULL); - ok (hConv != NULL, "DdeConnect Error %s\n", GetDdeLastErrorStr(instance)); ok (DdeFreeStringHandle(instance, hszProgman), "DdeFreeStringHandle failure\n"); + /* Seeing failures on early versions of Windows Connecting to progman, exit if connection fails */ + if (hConv == NULL) + { + ok (DdeUninitialize(instance), "DdeUninitialize failed\n"); + return; + } /* Run Tests */ testnum = DdeTestProgman(instance, hConv); diff --git a/dlls/shell32/tests/shelllink.c b/dlls/shell32/tests/shelllink.c index 2f20200c67a..25354718601 100644 --- a/dlls/shell32/tests/shelllink.c +++ b/dlls/shell32/tests/shelllink.c @@ -275,6 +275,20 @@ static void test_get_set(void) ok(SUCCEEDED(r), "GetArguments failed (0x%08x)\n", r); ok(lstrcmp(buffer,str)==0, "GetArguments returned '%s'\n", buffer); + strcpy(buffer,"garbage"); + r = IShellLinkA_SetArguments(sl, NULL); + ok(SUCCEEDED(r), "SetArguments failed (0x%08x)\n", r); + r = IShellLinkA_GetArguments(sl, buffer, sizeof(buffer)); + ok(SUCCEEDED(r), "GetArguments failed (0x%08x)\n", r); + ok(!buffer[0] || lstrcmp(buffer,str)==0, "GetArguments returned '%s'\n", buffer); + + strcpy(buffer,"garbage"); + r = IShellLinkA_SetArguments(sl, ""); + ok(SUCCEEDED(r), "SetArguments failed (0x%08x)\n", r); + r = IShellLinkA_GetArguments(sl, buffer, sizeof(buffer)); + ok(SUCCEEDED(r), "GetArguments failed (0x%08x)\n", r); + ok(!buffer[0], "GetArguments returned '%s'\n", buffer); + /* Test Getting / Setting showcmd */ i=0xdeadbeef; r = IShellLinkA_GetShowCmd(sl, &i); diff --git a/dlls/shell32/tests/shlfileop.c b/dlls/shell32/tests/shlfileop.c index 33d1a943868..0a5cdcab4fd 100644 --- a/dlls/shell32/tests/shlfileop.c +++ b/dlls/shell32/tests/shlfileop.c @@ -965,9 +965,10 @@ static void test_copy(void) set_curr_dir_path(from, "test1.txt\0test2.txt\0"); set_curr_dir_path(to, "test3.txt\0"); retval = SHFileOperation(&shfo); - if (retval == DE_FLDDESTISFILE) + if (retval == DE_FLDDESTISFILE || /* Vista and W2K8 */ + retval == DE_INVALIDFILES) /* Win7 */ { - /* Vista and W2K8 (broken or new behavior ?) */ + /* Most likely new behavior */ ok(!shfo.fAnyOperationsAborted, "Didn't expect aborted operations\n"); } else diff --git a/dlls/snmpapi/tests/util.c b/dlls/snmpapi/tests/util.c index 64c75010445..908d5e29f73 100644 --- a/dlls/snmpapi/tests/util.c +++ b/dlls/snmpapi/tests/util.c @@ -424,7 +424,7 @@ static void test_SnmpUtilOidAppend(void) static AsnObjectIdentifier oid1; static AsnObjectIdentifier oid2 = { 3, ids2 }; - ids1 = HeapAlloc(GetProcessHeap(), 0, 3 * sizeof(UINT)); + ids1 = SnmpUtilMemAlloc(3 * sizeof(UINT)); ids1[0] = 1; ids1[1] = 2; ids1[2] = 3; @@ -451,7 +451,7 @@ static void test_SnmpUtilOidAppend(void) ok(!memcmp(&oid1.ids[3], ids2, 3 * sizeof(UINT)), "SnmpUtilOidAppend failed\n"); - HeapFree(GetProcessHeap(), 0, ids1); + SnmpUtilOidFree(&oid1); } static void test_SnmpUtilVarBindCpyFree(void) diff --git a/dlls/urlmon/bindprot.c b/dlls/urlmon/bindprot.c index e4f203d28f5..20472baa3fe 100644 --- a/dlls/urlmon/bindprot.c +++ b/dlls/urlmon/bindprot.c @@ -205,7 +205,7 @@ static void push_task(BindProtocol *This, task_header_t *task, task_proc_t proc) This->task_queue_tail = task; }else { This->task_queue_tail = This->task_queue_head = task; - do_post = TRUE; + do_post = !This->continue_call; } LeaveCriticalSection(&This->section); diff --git a/dlls/urlmon/tests/url.c b/dlls/urlmon/tests/url.c index 53646d1ddbf..ecc4db798d9 100644 --- a/dlls/urlmon/tests/url.c +++ b/dlls/urlmon/tests/url.c @@ -2821,40 +2821,8 @@ static void test_StdURLMoniker(void) IMoniker_Release(mon); } -static void gecko_installer_workaround(BOOL disable) -{ - HKEY hkey; - DWORD res; - - static BOOL has_url = FALSE; - static char url[2048]; - - if(!disable && !has_url) - return; - - res = RegOpenKey(HKEY_CURRENT_USER, "Software\\Wine\\MSHTML", &hkey); - if(res != ERROR_SUCCESS) - return; - - if(disable) { - DWORD type, size = sizeof(url); - - res = RegQueryValueEx(hkey, "GeckoUrl", NULL, &type, (PVOID)url, &size); - if(res == ERROR_SUCCESS && type == REG_SZ) - has_url = TRUE; - - RegDeleteValue(hkey, "GeckoUrl"); - }else { - RegSetValueEx(hkey, "GeckoUrl", 0, REG_SZ, (PVOID)url, lstrlenA(url)+1); - } - - RegCloseKey(hkey); -} - START_TEST(url) { - gecko_installer_workaround(TRUE); - complete_event = CreateEvent(NULL, FALSE, FALSE, NULL); complete_event2 = CreateEvent(NULL, FALSE, FALSE, NULL); thread_id = GetCurrentThreadId(); @@ -2994,6 +2962,4 @@ START_TEST(url) CloseHandle(complete_event); CloseHandle(complete_event2); CoUninitialize(); - - gecko_installer_workaround(FALSE); } diff --git a/dlls/user32/dde_misc.c b/dlls/user32/dde_misc.c index d2de95429c5..ae1df40b308 100644 --- a/dlls/user32/dde_misc.c +++ b/dlls/user32/dde_misc.c @@ -1983,7 +1983,13 @@ WDML_CONV* WDML_GetConv(HCONV hConv, BOOL checkConnected) /* FIXME: should do better checking */ if (pConv == NULL || pConv->magic != WDML_CONV_MAGIC) return NULL; - if (!pConv->instance || pConv->instance->threadID != GetCurrentThreadId()) + if (!pConv->instance) + { + WARN("wrong thread ID, no instance\n"); + return NULL; + } + + if (pConv->instance->threadID != GetCurrentThreadId()) { WARN("wrong thread ID\n"); pConv->instance->lastError = DMLERR_INVALIDPARAMETER; /* FIXME: check */ diff --git a/dlls/user32/edit.c b/dlls/user32/edit.c index 190e9c6690e..f4143b102de 100644 --- a/dlls/user32/edit.c +++ b/dlls/user32/edit.c @@ -4691,10 +4691,10 @@ static LRESULT EDIT_WM_Create(EDITSTATE *es, LPCWSTR name) /********************************************************************* * - * WM_DESTROY + * WM_NCDESTROY * */ -static LRESULT EDIT_WM_Destroy(EDITSTATE *es) +static LRESULT EDIT_WM_NCDestroy(EDITSTATE *es) { LINEDEF *pc, *pp; @@ -4762,7 +4762,7 @@ static LRESULT EditWndProc_common( HWND hwnd, UINT msg, if (!es && msg != WM_NCCREATE) return DefWindowProcT(hwnd, msg, wParam, lParam, unicode); - if (es && (msg != WM_DESTROY)) EDIT_LockBuffer(es); + if (es && (msg != WM_NCDESTROY)) EDIT_LockBuffer(es); switch (msg) { case EM_GETSEL16: @@ -5102,8 +5102,8 @@ static LRESULT EditWndProc_common( HWND hwnd, UINT msg, result = EDIT_WM_NCCreate(hwnd, (LPCREATESTRUCTW)lParam, unicode); break; - case WM_DESTROY: - result = EDIT_WM_Destroy(es); + case WM_NCDESTROY: + result = EDIT_WM_NCDestroy(es); es = NULL; break; diff --git a/dlls/user32/tests/edit.c b/dlls/user32/tests/edit.c index 5ca012e53f7..e42127f88ad 100644 --- a/dlls/user32/tests/edit.c +++ b/dlls/user32/tests/edit.c @@ -1239,6 +1239,45 @@ static void test_edit_control_5(void) DestroyWindow(hWnd); } +/* Test WM_GETTEXT processing + * after destroy messages + */ +static void test_edit_control_6(void) +{ + static const char *str = "test\r\ntest"; + char buf[MAXLEN]; + LONG ret; + HWND hWnd; + + hWnd = CreateWindowEx(0, + "EDIT", + "Test", + 0, + 10, 10, 1, 1, + NULL, NULL, hinst, NULL); + assert(hWnd); + + ret = SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str); + ok(ret == TRUE, "Expected %d, got %d\n", TRUE, ret); + ret = SendMessageA(hWnd, WM_GETTEXT, MAXLEN, (LPARAM)buf); + ok(ret == lstrlen(str), "Expected %s, got len %d\n", str, ret); + ok(!lstrcmp(buf, str), "Expected %s, got %s\n", str, buf); + buf[0] = 0; + ret = SendMessageA(hWnd, WM_DESTROY, 0, 0); + ok(ret == 0, "Expected 0, got %d\n", ret); + ret = SendMessageA(hWnd, WM_GETTEXT, MAXLEN, (LPARAM)buf); + ok(ret == lstrlen(str), "Expected %s, got len %d\n", str, ret); + ok(!lstrcmp(buf, str), "Expected %s, got %s\n", str, buf); + buf[0] = 0; + ret = SendMessageA(hWnd, WM_NCDESTROY, 0, 0); + ok(ret == 0, "Expected 0, got %d\n", ret); + ret = SendMessageA(hWnd, WM_GETTEXT, MAXLEN, (LPARAM)buf); + ok(ret == 0, "Expected 0, got len %d\n", ret); + ok(!lstrcmp(buf, ""), "Expected empty string, got %s\n", buf); + + DestroyWindow(hWnd); +} + static void test_edit_control_limittext(void) { HWND hwEdit; @@ -2270,6 +2309,7 @@ START_TEST(edit) test_edit_control_3(); test_edit_control_4(); test_edit_control_5(); + test_edit_control_6(); test_edit_control_limittext(); test_margins(); test_margins_font_change(); diff --git a/dlls/user32/win.c b/dlls/user32/win.c index 9e42ff8a94a..46c238817a9 100644 --- a/dlls/user32/win.c +++ b/dlls/user32/win.c @@ -769,7 +769,9 @@ LRESULT WIN_DestroyWindow( HWND hwnd ) free_dce( wndPtr->dce, hwnd ); wndPtr->dce = NULL; icon_title = wndPtr->icon_title; - HeapFree(GetProcessHeap(), 0, wndPtr->pScroll); + HeapFree( GetProcessHeap(), 0, wndPtr->text ); + wndPtr->text = NULL; + HeapFree( GetProcessHeap(), 0, wndPtr->pScroll ); wndPtr->pScroll = NULL; WIN_ReleasePtr( wndPtr ); diff --git a/dlls/usp10/usp10.c b/dlls/usp10/usp10.c index e1c79e61385..aefe6cc65a2 100644 --- a/dlls/usp10/usp10.c +++ b/dlls/usp10/usp10.c @@ -1794,3 +1794,48 @@ HRESULT WINAPI ScriptGetLogicalWidths(const SCRIPT_ANALYSIS *sa, int nbchars, in for (i = 0; i < nbchars; i++) widths[i] = glyph_width[i]; return S_OK; } + +/*********************************************************************** + * ScriptApplyLogicalWidth (USP10.@) + * + * Generate glyph advance widths. + * + * PARAMS + * dx [I] Array of logical advance widths. + * num_chars [I] Number of characters. + * num_glyphs [I] Number of glyphs. + * log_clust [I] Array of logical clusters. + * sva [I] Visual attributes. + * advance [I] Array of glyph advance widths. + * sa [I] Script analysis. + * abc [I/O] Summed ABC widths. + * justify [O] Array of glyph advance widths. + * + * RETURNS + * Success: S_OK + * Failure: a non-zero HRESULT. + */ +HRESULT WINAPI ScriptApplyLogicalWidth(const int *dx, int num_chars, int num_glyphs, + const WORD *log_clust, const SCRIPT_VISATTR *sva, + const int *advance, const SCRIPT_ANALYSIS *sa, + ABC *abc, int *justify) +{ + int i; + + FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n", + dx, num_chars, num_glyphs, log_clust, sva, advance, sa, abc, justify); + + for (i = 0; i < num_chars; i++) justify[i] = advance[i]; + return S_OK; +} + +HRESULT WINAPI ScriptJustify(const SCRIPT_VISATTR *sva, const int *advance, + int num_glyphs, int dx, int min_kashida, int *justify) +{ + int i; + + FIXME("(%p, %p, %d, %d, %d, %p)\n", sva, advance, num_glyphs, dx, min_kashida, justify); + + for (i = 0; i < num_glyphs; i++) justify[i] = advance[i]; + return S_OK; +} diff --git a/dlls/usp10/usp10.spec b/dlls/usp10/usp10.spec index ac1506e9df0..5e358707c41 100644 --- a/dlls/usp10/usp10.spec +++ b/dlls/usp10/usp10.spec @@ -1,6 +1,6 @@ @ stub LpkPresent @ stdcall ScriptApplyDigitSubstitution(ptr ptr ptr) -@ stub ScriptApplyLogicalWidth +@ stdcall ScriptApplyLogicalWidth(ptr long long ptr ptr ptr ptr ptr ptr) @ stdcall ScriptBreak(ptr long ptr ptr) @ stdcall ScriptCPtoX(long long long long ptr ptr ptr ptr ptr) @ stdcall ScriptCacheGetHeight(ptr ptr ptr) @@ -12,7 +12,7 @@ @ stdcall ScriptGetProperties(ptr long) @ stdcall ScriptIsComplex(wstr long long) @ stdcall ScriptItemize(wstr long long ptr ptr ptr ptr) -@ stub ScriptJustify +@ stdcall ScriptJustify(ptr ptr long long long ptr) @ stdcall ScriptLayout(long ptr ptr ptr) @ stdcall ScriptPlace(ptr ptr ptr long ptr ptr ptr ptr ptr) @ stdcall ScriptRecordDigitSubstitution(ptr ptr) diff --git a/dlls/uxtheme/msstyles.c b/dlls/uxtheme/msstyles.c index 825645d2f4b..896a2949685 100644 --- a/dlls/uxtheme/msstyles.c +++ b/dlls/uxtheme/msstyles.c @@ -364,7 +364,10 @@ static BOOL MSSTYLES_ParseIniSectionName(LPCWSTR lpSection, DWORD dwLen, LPWSTR lstrcpynW(part, comp, sizeof(part)/sizeof(part[0])); comp = tmp; /* now get the state */ - *strchrW(comp, ')') = 0; + tmp = strchrW(comp, ')'); + if (!tmp) + return FALSE; + *tmp = 0; lstrcpynW(state, comp, sizeof(state)/sizeof(state[0])); } else { @@ -378,7 +381,10 @@ static BOOL MSSTYLES_ParseIniSectionName(LPCWSTR lpSection, DWORD dwLen, LPWSTR lstrcpynW(szClassName, comp, MAX_THEME_CLASS_NAME); comp = tmp; /* now get the state */ - *strchrW(comp, ')') = 0; + tmp = strchrW(comp, ')'); + if (!tmp) + return FALSE; + *tmp = 0; lstrcpynW(state, comp, sizeof(state)/sizeof(state[0])); } else { diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index a5a6c2e5859..136f3969255 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -6494,31 +6494,6 @@ static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOO return oldVisible; } -static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) { - IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; - IWineD3DResourceImpl *resource; - TRACE("(%p) : state (%u)\n", This, This->state); - - /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */ - switch (This->state) { - case WINED3D_OK: - return WINED3D_OK; - case WINED3DERR_DEVICELOST: - { - LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) { - if (resource->resource.pool == WINED3DPOOL_DEFAULT) - return WINED3DERR_DEVICENOTRESET; - } - return WINED3DERR_DEVICELOST; - } - case WINED3DERR_DRIVERINTERNALERROR: - return WINED3DERR_DRIVERINTERNALERROR; - } - - /* Unknown state */ - return WINED3DERR_DRIVERINTERNALERROR; -} - static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) { TRACE("checking resource %p for eviction\n", resource); if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) { @@ -7106,7 +7081,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3 * IWineD3DDevice VTbl follows **********************************************************/ -const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl = +static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl = { /*** IUnknown methods ***/ IWineD3DDeviceImpl_QueryInterface, @@ -7154,7 +7129,6 @@ const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl = IWineD3DDeviceImpl_SetCursorProperties, IWineD3DDeviceImpl_SetCursorPosition, IWineD3DDeviceImpl_ShowCursor, - IWineD3DDeviceImpl_TestCooperativeLevel, /*** Getters and setters **/ IWineD3DDeviceImpl_SetClipPlane, IWineD3DDeviceImpl_GetClipPlane, @@ -7253,6 +7227,84 @@ const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl = IWineD3DDeviceImpl_EnumResources }; +HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d, + UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags, + IUnknown *parent, IWineD3DDeviceParent *device_parent) +{ + struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx]; + const struct fragment_pipeline *fragment_pipeline; + struct shader_caps shader_caps; + struct fragment_caps ffp_caps; + WINED3DDISPLAYMODE mode; + unsigned int i; + HRESULT hr; + + device->lpVtbl = &IWineD3DDevice_Vtbl; + device->ref = 1; + device->wineD3D = (IWineD3D *)wined3d; + IWineD3D_AddRef(device->wineD3D); + device->adapter = wined3d->adapter_count ? adapter : NULL; + device->parent = parent; + device->device_parent = device_parent; + list_init(&device->resources); + list_init(&device->shaders); + + device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT; + device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */ + + /* Get the initial screen setup for ddraw. */ + hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode); + if (FAILED(hr)) + { + ERR("Failed to get the adapter's display mode, hr %#x.\n", hr); + IWineD3D_Release(device->wineD3D); + return hr; + } + device->ddraw_width = mode.Width; + device->ddraw_height = mode.Height; + device->ddraw_format = mode.Format; + + /* Save the creation parameters. */ + device->createParms.AdapterOrdinal = adapter_idx; + device->createParms.DeviceType = device_type; + device->createParms.hFocusWindow = focus_window; + device->createParms.BehaviorFlags = flags; + + device->adapterNo = adapter_idx; + device->devType = device_type; + for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]); + + select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode); + device->shader_backend = select_shader_backend(adapter, device_type); + + memset(&shader_caps, 0, sizeof(shader_caps)); + device->shader_backend->shader_get_caps(device_type, &adapter->gl_info, &shader_caps); + device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst; + device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst; + device->vs_clipping = shader_caps.VSClipping; + + memset(&ffp_caps, 0, sizeof(ffp_caps)); + fragment_pipeline = select_fragment_implementation(adapter, device_type); + device->frag_pipe = fragment_pipeline; + fragment_pipeline->get_caps(device_type, &adapter->gl_info, &ffp_caps); + device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures; + device->max_ffp_texture_stages = ffp_caps.MaxTextureBlendStages; + + hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info, + ffp_vertexstate_template, fragment_pipeline, misc_state_template); + if (FAILED(hr)) + { + ERR("Failed to compile state table, hr %#x.\n", hr); + IWineD3D_Release(device->wineD3D); + return hr; + } + + device->blitter = select_blit_implementation(adapter, device_type); + + return WINED3D_OK; +} + + void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) { DWORD rep = This->StateTable[state].representative; struct wined3d_context *context; diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c index f9cec29892f..c990ce92b00 100644 --- a/dlls/wined3d/directx.c +++ b/dlls/wined3d/directx.c @@ -155,10 +155,6 @@ static const struct { **********************************************************/ static HRESULT WINAPI IWineD3DImpl_CheckDeviceFormat(IWineD3D *iface, UINT Adapter, WINED3DDEVTYPE DeviceType, WINED3DFORMAT AdapterFormat, DWORD Usage, WINED3DRESOURCETYPE RType, WINED3DFORMAT CheckFormat, WINED3DSURFTYPE SurfaceType); -static const struct fragment_pipeline *select_fragment_implementation(struct wined3d_adapter *adapter, - WINED3DDEVTYPE DeviceType); -static const shader_backend_t *select_shader_backend(struct wined3d_adapter *adapter, WINED3DDEVTYPE DeviceType); -static const struct blit_shader *select_blit_implementation(struct wined3d_adapter *adapter, WINED3DDEVTYPE DeviceType); GLint wrap_lookup[WINED3DTADDRESS_MIRRORONCE - WINED3DTADDRESS_WRAP + 1]; @@ -389,39 +385,6 @@ static ULONG WINAPI IWineD3DImpl_Release(IWineD3D *iface) { return ref; } -/* Set the shader type for this device, depending on the given capabilities - * and the user preferences in wined3d_settings. */ -static void select_shader_mode(const struct wined3d_gl_info *gl_info, int *ps_selected, int *vs_selected) -{ - if (wined3d_settings.vs_mode == VS_NONE) { - *vs_selected = SHADER_NONE; - } else if (gl_info->supported[ARB_VERTEX_SHADER] && wined3d_settings.glslRequested) { - /* Geforce4 cards support GLSL but for vertex shaders only. Further its reported GLSL caps are - * wrong. This combined with the fact that glsl won't offer more features or performance, use ARB - * shaders only on this card. */ - if (gl_info->supported[NV_VERTEX_PROGRAM] && !gl_info->supported[NV_VERTEX_PROGRAM2]) - *vs_selected = SHADER_ARB; - else - *vs_selected = SHADER_GLSL; - } else if (gl_info->supported[ARB_VERTEX_PROGRAM]) { - *vs_selected = SHADER_ARB; - } else { - *vs_selected = SHADER_NONE; - } - - if (wined3d_settings.ps_mode == PS_NONE) { - *ps_selected = SHADER_NONE; - } else if (gl_info->supported[ARB_FRAGMENT_SHADER] && wined3d_settings.glslRequested) { - *ps_selected = SHADER_GLSL; - } else if (gl_info->supported[ARB_FRAGMENT_PROGRAM]) { - *ps_selected = SHADER_ARB; - } else if (gl_info->supported[ATI_FRAGMENT_SHADER]) { - *ps_selected = SHADER_ATI; - } else { - *ps_selected = SHADER_NONE; - } -} - /********************************************************** * IWineD3D parts follows **********************************************************/ @@ -3810,72 +3773,6 @@ static HRESULT WINAPI IWineD3DImpl_CheckDeviceFormatConversion(IWineD3D *iface, return WINED3D_OK; } -static const shader_backend_t *select_shader_backend(struct wined3d_adapter *adapter, WINED3DDEVTYPE DeviceType) -{ - const shader_backend_t *ret; - int vs_selected_mode; - int ps_selected_mode; - - select_shader_mode(&adapter->gl_info, &ps_selected_mode, &vs_selected_mode); - if (vs_selected_mode == SHADER_GLSL || ps_selected_mode == SHADER_GLSL) { - ret = &glsl_shader_backend; - } else if (vs_selected_mode == SHADER_ARB || ps_selected_mode == SHADER_ARB) { - ret = &arb_program_shader_backend; - } else { - ret = &none_shader_backend; - } - return ret; -} - -static const struct fragment_pipeline *select_fragment_implementation(struct wined3d_adapter *adapter, - WINED3DDEVTYPE DeviceType) -{ - const struct wined3d_gl_info *gl_info = &adapter->gl_info; - int vs_selected_mode; - int ps_selected_mode; - - select_shader_mode(&adapter->gl_info, &ps_selected_mode, &vs_selected_mode); - if ((ps_selected_mode == SHADER_ARB || ps_selected_mode == SHADER_GLSL) - && gl_info->supported[ARB_FRAGMENT_PROGRAM]) - { - return &arbfp_fragment_pipeline; - } - else if (ps_selected_mode == SHADER_ATI) - { - return &atifs_fragment_pipeline; - } - else if (gl_info->supported[NV_REGISTER_COMBINERS] && gl_info->supported[NV_TEXTURE_SHADER2]) - { - return &nvts_fragment_pipeline; - } - else if (gl_info->supported[NV_REGISTER_COMBINERS]) - { - return &nvrc_fragment_pipeline; - } - else - { - return &ffp_fragment_pipeline; - } -} - -static const struct blit_shader *select_blit_implementation(struct wined3d_adapter *adapter, WINED3DDEVTYPE DeviceType) -{ - const struct wined3d_gl_info *gl_info = &adapter->gl_info; - int vs_selected_mode; - int ps_selected_mode; - - select_shader_mode(&adapter->gl_info, &ps_selected_mode, &vs_selected_mode); - if ((ps_selected_mode == SHADER_ARB || ps_selected_mode == SHADER_GLSL) - && gl_info->supported[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 */ @@ -4473,113 +4370,45 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter, return WINED3D_OK; } -/* Note due to structure differences between dx8 and dx9 D3DPRESENT_PARAMETERS, - and fields being inserted in the middle, a new structure is used in place */ -static HRESULT WINAPI IWineD3DImpl_CreateDevice(IWineD3D *iface, UINT Adapter, - WINED3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviourFlags, IUnknown *parent, - IWineD3DDeviceParent *device_parent, IWineD3DDevice **ppReturnedDeviceInterface) +static HRESULT WINAPI IWineD3DImpl_CreateDevice(IWineD3D *iface, UINT adapter_idx, + WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags, IUnknown *parent, + IWineD3DDeviceParent *device_parent, IWineD3DDevice **device) { - IWineD3DDeviceImpl *object = NULL; - IWineD3DImpl *This = (IWineD3DImpl *)iface; - struct wined3d_adapter *adapter = &This->adapters[Adapter]; - WINED3DDISPLAYMODE mode; - const struct fragment_pipeline *frag_pipeline = NULL; - int i; - struct fragment_caps ffp_caps; - struct shader_caps shader_caps; + IWineD3DImpl *This = (IWineD3DImpl *)iface; + IWineD3DDeviceImpl *object; HRESULT hr; + TRACE("iface %p, adapter_idx %u, device_type %#x, focus_window %p, flags %#x.\n" + "parent %p, device_parent %p, device %p.\n", + iface, adapter_idx, device_type, focus_window, flags, + parent, device_parent, device); + /* Validate the adapter number. If no adapters are available(no GL), ignore the adapter - * number and create a device without a 3D adapter for 2D only operation. - */ - if (IWineD3D_GetAdapterCount(iface) && Adapter >= IWineD3D_GetAdapterCount(iface)) { + * number and create a device without a 3D adapter for 2D only operation. */ + if (IWineD3D_GetAdapterCount(iface) && adapter_idx >= IWineD3D_GetAdapterCount(iface)) + { return WINED3DERR_INVALIDCALL; } - /* Create a WineD3DDevice object */ - object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DDeviceImpl)); - *ppReturnedDeviceInterface = (IWineD3DDevice *)object; - TRACE("Created WineD3DDevice object @ %p\n", object); - if (NULL == object) { - return WINED3DERR_OUTOFVIDEOMEMORY; - } - - /* Set up initial COM information */ - object->lpVtbl = &IWineD3DDevice_Vtbl; - object->ref = 1; - object->wineD3D = iface; - object->adapter = This->adapter_count ? adapter : NULL; - IWineD3D_AddRef(object->wineD3D); - object->parent = parent; - object->device_parent = device_parent; - list_init(&object->resources); - list_init(&object->shaders); - - if(This->dxVersion == 7) { - object->surface_alignment = DDRAW_PITCH_ALIGNMENT; - } else { - object->surface_alignment = D3D8_PITCH_ALIGNMENT; + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)); + if (!object) + { + ERR("Failed to allocate device memory.\n"); + return E_OUTOFMEMORY; } - object->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */ - - /* Set the state up as invalid until the device is fully created */ - object->state = WINED3DERR_DRIVERINTERNALERROR; - TRACE("(%p)->(Adptr:%d, DevType: %x, FocusHwnd: %p, BehFlags: %x, RetDevInt: %p)\n", This, Adapter, DeviceType, - hFocusWindow, BehaviourFlags, ppReturnedDeviceInterface); - - /* Save the creation parameters */ - object->createParms.AdapterOrdinal = Adapter; - object->createParms.DeviceType = DeviceType; - object->createParms.hFocusWindow = hFocusWindow; - object->createParms.BehaviorFlags = BehaviourFlags; - - /* Initialize other useful values */ - object->adapterNo = Adapter; - object->devType = DeviceType; - - select_shader_mode(&adapter->gl_info, &object->ps_selected_mode, &object->vs_selected_mode); - object->shader_backend = select_shader_backend(adapter, DeviceType); - - memset(&shader_caps, 0, sizeof(shader_caps)); - object->shader_backend->shader_get_caps(DeviceType, &adapter->gl_info, &shader_caps); - object->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst; - object->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst; - object->vs_clipping = shader_caps.VSClipping; - - memset(&ffp_caps, 0, sizeof(ffp_caps)); - frag_pipeline = select_fragment_implementation(adapter, DeviceType); - object->frag_pipe = frag_pipeline; - frag_pipeline->get_caps(DeviceType, &adapter->gl_info, &ffp_caps); - object->max_ffp_textures = ffp_caps.MaxSimultaneousTextures; - object->max_ffp_texture_stages = ffp_caps.MaxTextureBlendStages; - hr = compile_state_table(object->StateTable, object->multistate_funcs, &adapter->gl_info, - ffp_vertexstate_template, frag_pipeline, misc_state_template); - - if (FAILED(hr)) { - IWineD3D_Release(object->wineD3D); + hr = device_init(object, This, adapter_idx, device_type, focus_window, flags, parent, device_parent); + if (FAILED(hr)) + { + WARN("Failed to initialize device, hr %#x.\n", hr); HeapFree(GetProcessHeap(), 0, object); - return hr; } - object->blitter = select_blit_implementation(adapter, DeviceType); - - /* set the state of the device to valid */ - object->state = WINED3D_OK; - - /* Get the initial screen setup for ddraw */ - IWineD3DImpl_GetAdapterDisplayMode(iface, Adapter, &mode); - - object->ddraw_width = mode.Width; - object->ddraw_height = mode.Height; - object->ddraw_format = mode.Format; - - for(i = 0; i < PATCHMAP_SIZE; i++) { - list_init(&object->patches[i]); - } + TRACE("Created device %p.\n", object); + *device = (IWineD3DDevice *)object; - IWineD3DDeviceParent_WineD3DDeviceCreated(device_parent, *ppReturnedDeviceInterface); + IWineD3DDeviceParent_WineD3DDeviceCreated(device_parent, *device); return WINED3D_OK; } diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c index 94fe19ec556..6df6e548b23 100644 --- a/dlls/wined3d/state.c +++ b/dlls/wined3d/state.c @@ -1636,7 +1636,7 @@ static void state_wrap(DWORD state, IWineD3DStateBlockImpl *stateblock, struct w stateblock->renderState[WINED3DRS_WRAP13] || stateblock->renderState[WINED3DRS_WRAP14] || stateblock->renderState[WINED3DRS_WRAP15] ) { - FIXME("(WINED3DRS_WRAP0) Texture wraping not yet supported\n"); + FIXME("(WINED3DRS_WRAP0) Texture wrapping not yet supported\n"); } } diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index 8fe938f0ab8..1b4516afdf4 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -35,7 +35,6 @@ struct StaticPixelFormatDesc DWORD alphaMask, redMask, greenMask, blueMask; UINT bpp; short depthSize, stencilSize; - BOOL isFourcc; }; /***************************************************************************** @@ -50,88 +49,123 @@ struct StaticPixelFormatDesc */ static const struct StaticPixelFormatDesc formats[] = { - /* WINED3DFORMAT alphamask redmask greenmask bluemask bpp depth stencil isFourcc */ - {WINED3DFMT_UNKNOWN, 0x0, 0x0, 0x0, 0x0, 0, 0, 0, FALSE}, + /* WINED3DFORMAT alphamask redmask greenmask bluemask bpp depth stencil */ + {WINED3DFMT_UNKNOWN, 0x0, 0x0, 0x0, 0x0, 0, 0, 0}, /* FourCC formats */ - {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 }, - {WINED3DFMT_DXT3, 0x0, 0x0, 0x0, 0x0, 1, 0, 0, TRUE }, - {WINED3DFMT_DXT4, 0x0, 0x0, 0x0, 0x0, 1, 0, 0, TRUE }, - {WINED3DFMT_DXT5, 0x0, 0x0, 0x0, 0x0, 1, 0, 0, TRUE }, - {WINED3DFMT_MULTI2_ARGB8, 0x0, 0x0, 0x0, 0x0, 1/*?*/, 0, 0, TRUE }, - {WINED3DFMT_G8R8_G8B8, 0x0, 0x0, 0x0, 0x0, 1/*?*/, 0, 0, TRUE }, - {WINED3DFMT_R8G8_B8G8, 0x0, 0x0, 0x0, 0x0, 1/*?*/, 0, 0, TRUE }, + {WINED3DFMT_UYVY, 0x0, 0x0, 0x0, 0x0, 2, 0, 0}, + {WINED3DFMT_YUY2, 0x0, 0x0, 0x0, 0x0, 2, 0, 0}, + {WINED3DFMT_YV12, 0x0, 0x0, 0x0, 0x0, 1, 0, 0}, + {WINED3DFMT_DXT1, 0x0, 0x0, 0x0, 0x0, 1, 0, 0}, + {WINED3DFMT_DXT2, 0x0, 0x0, 0x0, 0x0, 1, 0, 0}, + {WINED3DFMT_DXT3, 0x0, 0x0, 0x0, 0x0, 1, 0, 0}, + {WINED3DFMT_DXT4, 0x0, 0x0, 0x0, 0x0, 1, 0, 0}, + {WINED3DFMT_DXT5, 0x0, 0x0, 0x0, 0x0, 1, 0, 0}, + {WINED3DFMT_MULTI2_ARGB8, 0x0, 0x0, 0x0, 0x0, 1/*?*/, 0, 0}, + {WINED3DFMT_G8R8_G8B8, 0x0, 0x0, 0x0, 0x0, 1/*?*/, 0, 0}, + {WINED3DFMT_R8G8_B8G8, 0x0, 0x0, 0x0, 0x0, 1/*?*/, 0, 0}, /* IEEE formats */ - {WINED3DFMT_R32_FLOAT, 0x0, 0x0, 0x0, 0x0, 4, 0, 0, FALSE}, - {WINED3DFMT_R32G32_FLOAT, 0x0, 0x0, 0x0, 0x0, 8, 0, 0, FALSE}, - {WINED3DFMT_R32G32B32_FLOAT, 0x0, 0x0, 0x0, 0x0, 12, 0, 0, FALSE}, - {WINED3DFMT_R32G32B32A32_FLOAT, 0x1, 0x0, 0x0, 0x0, 16, 0, 0, FALSE}, + {WINED3DFMT_R32_FLOAT, 0x0, 0x0, 0x0, 0x0, 4, 0, 0}, + {WINED3DFMT_R32G32_FLOAT, 0x0, 0x0, 0x0, 0x0, 8, 0, 0}, + {WINED3DFMT_R32G32B32_FLOAT, 0x0, 0x0, 0x0, 0x0, 12, 0, 0}, + {WINED3DFMT_R32G32B32A32_FLOAT, 0x1, 0x0, 0x0, 0x0, 16, 0, 0}, /* Hmm? */ - {WINED3DFMT_R8G8_SNORM_Cx, 0x0, 0x0, 0x0, 0x0, 2, 0, 0, FALSE}, + {WINED3DFMT_R8G8_SNORM_Cx, 0x0, 0x0, 0x0, 0x0, 2, 0, 0}, /* Float */ - {WINED3DFMT_R16_FLOAT, 0x0, 0x0, 0x0, 0x0, 2, 0, 0, FALSE}, - {WINED3DFMT_R16G16_FLOAT, 0x0, 0x0, 0x0, 0x0, 4, 0, 0, FALSE}, - {WINED3DFMT_R16G16_SINT, 0x0, 0x0, 0x0, 0x0, 4, 0, 0, FALSE}, - {WINED3DFMT_R16G16B16A16_FLOAT, 0x1, 0x0, 0x0, 0x0, 8, 0, 0, FALSE}, - {WINED3DFMT_R16G16B16A16_SINT, 0x1, 0x0, 0x0, 0x0, 8, 0, 0, FALSE}, + {WINED3DFMT_R16_FLOAT, 0x0, 0x0, 0x0, 0x0, 2, 0, 0}, + {WINED3DFMT_R16G16_FLOAT, 0x0, 0x0, 0x0, 0x0, 4, 0, 0}, + {WINED3DFMT_R16G16_SINT, 0x0, 0x0, 0x0, 0x0, 4, 0, 0}, + {WINED3DFMT_R16G16B16A16_FLOAT, 0x1, 0x0, 0x0, 0x0, 8, 0, 0}, + {WINED3DFMT_R16G16B16A16_SINT, 0x1, 0x0, 0x0, 0x0, 8, 0, 0}, /* Palettized formats */ - {WINED3DFMT_P8_UINT_A8_UNORM, 0x0000ff00, 0x0, 0x0, 0x0, 2, 0, 0, FALSE}, - {WINED3DFMT_P8_UINT, 0x0, 0x0, 0x0, 0x0, 1, 0, 0, FALSE}, + {WINED3DFMT_P8_UINT_A8_UNORM, 0x0000ff00, 0x0, 0x0, 0x0, 2, 0, 0}, + {WINED3DFMT_P8_UINT, 0x0, 0x0, 0x0, 0x0, 1, 0, 0}, /* Standard ARGB formats. */ - {WINED3DFMT_B8G8R8_UNORM, 0x0, 0x00ff0000, 0x0000ff00, 0x000000ff, 3, 0, 0, FALSE}, - {WINED3DFMT_B8G8R8A8_UNORM, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff, 4, 0, 0, FALSE}, - {WINED3DFMT_B8G8R8X8_UNORM, 0x0, 0x00ff0000, 0x0000ff00, 0x000000ff, 4, 0, 0, FALSE}, - {WINED3DFMT_B5G6R5_UNORM, 0x0, 0x0000f800, 0x000007e0, 0x0000001f, 2, 0, 0, FALSE}, - {WINED3DFMT_B5G5R5X1_UNORM, 0x0, 0x00007c00, 0x000003e0, 0x0000001f, 2, 0, 0, FALSE}, - {WINED3DFMT_B5G5R5A1_UNORM, 0x00008000, 0x00007c00, 0x000003e0, 0x0000001f, 2, 0, 0, FALSE}, - {WINED3DFMT_B4G4R4A4_UNORM, 0x0000f000, 0x00000f00, 0x000000f0, 0x0000000f, 2, 0, 0, FALSE}, - {WINED3DFMT_B2G3R3_UNORM, 0x0, 0x000000e0, 0x0000001c, 0x00000003, 1, 0, 0, FALSE}, - {WINED3DFMT_A8_UNORM, 0x000000ff, 0x0, 0x0, 0x0, 1, 0, 0, FALSE}, - {WINED3DFMT_B2G3R3A8_UNORM, 0x0000ff00, 0x000000e0, 0x0000001c, 0x00000003, 2, 0, 0, FALSE}, - {WINED3DFMT_B4G4R4X4_UNORM, 0x0, 0x00000f00, 0x000000f0, 0x0000000f, 2, 0, 0, FALSE}, - {WINED3DFMT_R10G10B10A2_UNORM, 0xc0000000, 0x000003ff, 0x000ffc00, 0x3ff00000, 4, 0, 0, FALSE}, - {WINED3DFMT_R10G10B10A2_UINT, 0xc0000000, 0x000003ff, 0x000ffc00, 0x3ff00000, 4, 0, 0, FALSE}, - {WINED3DFMT_R10G10B10A2_SNORM, 0xc0000000, 0x000003ff, 0x000ffc00, 0x3ff00000, 4, 0, 0, FALSE}, - {WINED3DFMT_R8G8B8A8_UNORM, 0xff000000, 0x000000ff, 0x0000ff00, 0x00ff0000, 4, 0, 0, FALSE}, - {WINED3DFMT_R8G8B8A8_UINT, 0xff000000, 0x000000ff, 0x0000ff00, 0x00ff0000, 4, 0, 0, FALSE}, - {WINED3DFMT_R8G8B8X8_UNORM, 0x0, 0x000000ff, 0x0000ff00, 0x00ff0000, 4, 0, 0, FALSE}, - {WINED3DFMT_R16G16_UNORM, 0x0, 0x0000ffff, 0xffff0000, 0x0, 4, 0, 0, FALSE}, - {WINED3DFMT_B10G10R10A2_UNORM, 0xc0000000, 0x3ff00000, 0x000ffc00, 0x000003ff, 4, 0, 0, FALSE}, - {WINED3DFMT_R16G16B16A16_UNORM, 0x1, 0x0000ffff, 0xffff0000, 0x0, 8, 0, 0, FALSE}, + {WINED3DFMT_B8G8R8_UNORM, 0x0, 0x00ff0000, 0x0000ff00, 0x000000ff, 3, 0, 0}, + {WINED3DFMT_B8G8R8A8_UNORM, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff, 4, 0, 0}, + {WINED3DFMT_B8G8R8X8_UNORM, 0x0, 0x00ff0000, 0x0000ff00, 0x000000ff, 4, 0, 0}, + {WINED3DFMT_B5G6R5_UNORM, 0x0, 0x0000f800, 0x000007e0, 0x0000001f, 2, 0, 0}, + {WINED3DFMT_B5G5R5X1_UNORM, 0x0, 0x00007c00, 0x000003e0, 0x0000001f, 2, 0, 0}, + {WINED3DFMT_B5G5R5A1_UNORM, 0x00008000, 0x00007c00, 0x000003e0, 0x0000001f, 2, 0, 0}, + {WINED3DFMT_B4G4R4A4_UNORM, 0x0000f000, 0x00000f00, 0x000000f0, 0x0000000f, 2, 0, 0}, + {WINED3DFMT_B2G3R3_UNORM, 0x0, 0x000000e0, 0x0000001c, 0x00000003, 1, 0, 0}, + {WINED3DFMT_A8_UNORM, 0x000000ff, 0x0, 0x0, 0x0, 1, 0, 0}, + {WINED3DFMT_B2G3R3A8_UNORM, 0x0000ff00, 0x000000e0, 0x0000001c, 0x00000003, 2, 0, 0}, + {WINED3DFMT_B4G4R4X4_UNORM, 0x0, 0x00000f00, 0x000000f0, 0x0000000f, 2, 0, 0}, + {WINED3DFMT_R10G10B10A2_UNORM, 0xc0000000, 0x000003ff, 0x000ffc00, 0x3ff00000, 4, 0, 0}, + {WINED3DFMT_R10G10B10A2_UINT, 0xc0000000, 0x000003ff, 0x000ffc00, 0x3ff00000, 4, 0, 0}, + {WINED3DFMT_R10G10B10A2_SNORM, 0xc0000000, 0x000003ff, 0x000ffc00, 0x3ff00000, 4, 0, 0}, + {WINED3DFMT_R8G8B8A8_UNORM, 0xff000000, 0x000000ff, 0x0000ff00, 0x00ff0000, 4, 0, 0}, + {WINED3DFMT_R8G8B8A8_UINT, 0xff000000, 0x000000ff, 0x0000ff00, 0x00ff0000, 4, 0, 0}, + {WINED3DFMT_R8G8B8X8_UNORM, 0x0, 0x000000ff, 0x0000ff00, 0x00ff0000, 4, 0, 0}, + {WINED3DFMT_R16G16_UNORM, 0x0, 0x0000ffff, 0xffff0000, 0x0, 4, 0, 0}, + {WINED3DFMT_B10G10R10A2_UNORM, 0xc0000000, 0x3ff00000, 0x000ffc00, 0x000003ff, 4, 0, 0}, + {WINED3DFMT_R16G16B16A16_UNORM, 0x1, 0x0000ffff, 0xffff0000, 0x0, 8, 0, 0}, /* Luminance */ - {WINED3DFMT_L8_UNORM, 0x0, 0x0, 0x0, 0x0, 1, 0, 0, FALSE}, - {WINED3DFMT_L8A8_UNORM, 0x0000ff00, 0x0, 0x0, 0x0, 2, 0, 0, FALSE}, - {WINED3DFMT_L4A4_UNORM, 0x000000f0, 0x0, 0x0, 0x0, 1, 0, 0, FALSE}, - {WINED3DFMT_L16_UNORM, 0x0, 0x0, 0x0, 0x0, 2, 16, 0, FALSE}, + {WINED3DFMT_L8_UNORM, 0x0, 0x0, 0x0, 0x0, 1, 0, 0}, + {WINED3DFMT_L8A8_UNORM, 0x0000ff00, 0x0, 0x0, 0x0, 2, 0, 0}, + {WINED3DFMT_L4A4_UNORM, 0x000000f0, 0x0, 0x0, 0x0, 1, 0, 0}, + {WINED3DFMT_L16_UNORM, 0x0, 0x0, 0x0, 0x0, 2, 16, 0}, /* Bump mapping stuff */ - {WINED3DFMT_R8G8_SNORM, 0x0, 0x0, 0x0, 0x0, 2, 0, 0, FALSE}, - {WINED3DFMT_R5G5_SNORM_L6_UNORM, 0x0, 0x0, 0x0, 0x0, 2, 0, 0, FALSE}, - {WINED3DFMT_R8G8_SNORM_L8X8_UNORM, 0x0, 0x0, 0x0, 0x0, 4, 0, 0, FALSE}, - {WINED3DFMT_R8G8B8A8_SNORM, 0x0, 0x0, 0x0, 0x0, 4, 0, 0, FALSE}, - {WINED3DFMT_R16G16_SNORM, 0x0, 0x0, 0x0, 0x0, 4, 0, 0, FALSE}, - {WINED3DFMT_R10G11B11_SNORM, 0x0, 0x0, 0x0, 0x0, 4, 0, 0, FALSE}, - {WINED3DFMT_R10G10B10_SNORM_A2_UNORM,0xb0000000,0x0, 0x0, 0x0, 4, 0, 0, FALSE}, + {WINED3DFMT_R8G8_SNORM, 0x0, 0x0, 0x0, 0x0, 2, 0, 0}, + {WINED3DFMT_R5G5_SNORM_L6_UNORM, 0x0, 0x0, 0x0, 0x0, 2, 0, 0}, + {WINED3DFMT_R8G8_SNORM_L8X8_UNORM, 0x0, 0x0, 0x0, 0x0, 4, 0, 0}, + {WINED3DFMT_R8G8B8A8_SNORM, 0x0, 0x0, 0x0, 0x0, 4, 0, 0}, + {WINED3DFMT_R16G16_SNORM, 0x0, 0x0, 0x0, 0x0, 4, 0, 0}, + {WINED3DFMT_R10G11B11_SNORM, 0x0, 0x0, 0x0, 0x0, 4, 0, 0}, + {WINED3DFMT_R10G10B10_SNORM_A2_UNORM, 0xb0000000, 0x0, 0x0, 0x0, 4, 0, 0}, /* Depth stencil formats */ - {WINED3DFMT_D16_LOCKABLE, 0x0, 0x0, 0x0, 0x0, 2, 16, 0, FALSE}, - {WINED3DFMT_D32_UNORM, 0x0, 0x0, 0x0, 0x0, 4, 32, 0, FALSE}, - {WINED3DFMT_S1_UINT_D15_UNORM, 0x0, 0x0, 0x0, 0x0, 2, 15, 1, FALSE}, - {WINED3DFMT_D24_UNORM_S8_UINT, 0x0, 0x0, 0x0, 0x0, 4, 24, 8, FALSE}, - {WINED3DFMT_X8D24_UNORM, 0x0, 0x0, 0x0, 0x0, 4, 24, 0, FALSE}, - {WINED3DFMT_S4X4_UINT_D24_UNORM, 0x0, 0x0, 0x0, 0x0, 4, 24, 4, FALSE}, - {WINED3DFMT_D16_UNORM, 0x0, 0x0, 0x0, 0x0, 2, 16, 0, FALSE}, - {WINED3DFMT_D32_FLOAT, 0x0, 0x0, 0x0, 0x0, 4, 32, 0, FALSE}, - {WINED3DFMT_S8_UINT_D24_FLOAT, 0x0, 0x0, 0x0, 0x0, 4, 24, 8, FALSE}, - {WINED3DFMT_VERTEXDATA, 0x0, 0x0, 0x0, 0x0, 0, 0, 0, FALSE}, - {WINED3DFMT_R16_UINT, 0x0, 0x0, 0x0, 0x0, 2, 0, 0, FALSE}, - {WINED3DFMT_R32_UINT, 0x0, 0x0, 0x0, 0x0, 4, 0, 0, FALSE}, - {WINED3DFMT_R16G16B16A16_SNORM, 0x0, 0x0, 0x0, 0x0, 8, 0, 0, FALSE}, + {WINED3DFMT_D16_LOCKABLE, 0x0, 0x0, 0x0, 0x0, 2, 16, 0}, + {WINED3DFMT_D32_UNORM, 0x0, 0x0, 0x0, 0x0, 4, 32, 0}, + {WINED3DFMT_S1_UINT_D15_UNORM, 0x0, 0x0, 0x0, 0x0, 2, 15, 1}, + {WINED3DFMT_D24_UNORM_S8_UINT, 0x0, 0x0, 0x0, 0x0, 4, 24, 8}, + {WINED3DFMT_X8D24_UNORM, 0x0, 0x0, 0x0, 0x0, 4, 24, 0}, + {WINED3DFMT_S4X4_UINT_D24_UNORM, 0x0, 0x0, 0x0, 0x0, 4, 24, 4}, + {WINED3DFMT_D16_UNORM, 0x0, 0x0, 0x0, 0x0, 2, 16, 0}, + {WINED3DFMT_D32_FLOAT, 0x0, 0x0, 0x0, 0x0, 4, 32, 0}, + {WINED3DFMT_S8_UINT_D24_FLOAT, 0x0, 0x0, 0x0, 0x0, 4, 24, 8}, + {WINED3DFMT_VERTEXDATA, 0x0, 0x0, 0x0, 0x0, 0, 0, 0}, + {WINED3DFMT_R16_UINT, 0x0, 0x0, 0x0, 0x0, 2, 0, 0}, + {WINED3DFMT_R32_UINT, 0x0, 0x0, 0x0, 0x0, 4, 0, 0}, + {WINED3DFMT_R16G16B16A16_SNORM, 0x0, 0x0, 0x0, 0x0, 8, 0, 0}, /* Vendor-specific formats */ - {WINED3DFMT_ATI2N, 0x0, 0x0, 0x0, 0x0, 1, 0, 0, TRUE }, - {WINED3DFMT_NVHU, 0x0, 0x0, 0x0, 0x0, 2, 0, 0, TRUE }, - {WINED3DFMT_NVHS, 0x0, 0x0, 0x0, 0x0, 2, 0, 0, TRUE }, + {WINED3DFMT_ATI2N, 0x0, 0x0, 0x0, 0x0, 1, 0, 0}, + {WINED3DFMT_NVHU, 0x0, 0x0, 0x0, 0x0, 2, 0, 0}, + {WINED3DFMT_NVHS, 0x0, 0x0, 0x0, 0x0, 2, 0, 0}, +}; + +struct wined3d_format_base_flags +{ + WINED3DFORMAT format; + DWORD flags; +}; + +static const struct wined3d_format_base_flags format_base_flags[] = +{ + {WINED3DFMT_UYVY, WINED3DFMT_FLAG_FOURCC}, + {WINED3DFMT_YUY2, WINED3DFMT_FLAG_FOURCC}, + {WINED3DFMT_YV12, WINED3DFMT_FLAG_FOURCC}, + {WINED3DFMT_DXT1, WINED3DFMT_FLAG_FOURCC}, + {WINED3DFMT_DXT2, WINED3DFMT_FLAG_FOURCC}, + {WINED3DFMT_DXT3, WINED3DFMT_FLAG_FOURCC}, + {WINED3DFMT_DXT4, WINED3DFMT_FLAG_FOURCC}, + {WINED3DFMT_DXT5, WINED3DFMT_FLAG_FOURCC}, + {WINED3DFMT_MULTI2_ARGB8, WINED3DFMT_FLAG_FOURCC}, + {WINED3DFMT_G8R8_G8B8, WINED3DFMT_FLAG_FOURCC}, + {WINED3DFMT_R8G8_B8G8, WINED3DFMT_FLAG_FOURCC}, + {WINED3DFMT_P8_UINT, WINED3DFMT_FLAG_GETDC}, + {WINED3DFMT_B8G8R8_UNORM, WINED3DFMT_FLAG_GETDC}, + {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_FLAG_GETDC}, + {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_FLAG_GETDC}, + {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_FLAG_GETDC}, + {WINED3DFMT_B5G5R5X1_UNORM, WINED3DFMT_FLAG_GETDC}, + {WINED3DFMT_B5G5R5A1_UNORM, WINED3DFMT_FLAG_GETDC}, + {WINED3DFMT_B4G4R4A4_UNORM, WINED3DFMT_FLAG_GETDC}, + {WINED3DFMT_B4G4R4X4_UNORM, WINED3DFMT_FLAG_GETDC}, + {WINED3DFMT_R8G8B8A8_UNORM, WINED3DFMT_FLAG_GETDC}, + {WINED3DFMT_R8G8B8X8_UNORM, WINED3DFMT_FLAG_GETDC}, + {WINED3DFMT_ATI2N, WINED3DFMT_FLAG_FOURCC}, + {WINED3DFMT_NVHU, WINED3DFMT_FLAG_FOURCC}, + {WINED3DFMT_NVHS, WINED3DFMT_FLAG_FOURCC}, }; struct wined3d_format_compression_info @@ -294,47 +328,40 @@ static const GlPixelFormatDescTemplate gl_formats_template[] = { /* Palettized formats */ {WINED3DFMT_P8_UINT, GL_RGBA, GL_RGBA, 0, GL_RGBA, GL_UNSIGNED_BYTE, - WINED3DFMT_FLAG_GETDC, + 0, ARB_FRAGMENT_PROGRAM}, {WINED3DFMT_P8_UINT, GL_COLOR_INDEX8_EXT, GL_COLOR_INDEX8_EXT, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, - WINED3DFMT_FLAG_GETDC, + 0, EXT_PALETTED_TEXTURE}, /* Standard ARGB formats */ {WINED3DFMT_B8G8R8_UNORM, GL_RGB8, GL_RGB8, 0, GL_BGR, GL_UNSIGNED_BYTE, - WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING | WINED3DFMT_FLAG_RENDERTARGET | - WINED3DFMT_FLAG_GETDC, + WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING | WINED3DFMT_FLAG_RENDERTARGET, WINED3D_GL_EXT_NONE}, {WINED3DFMT_B8G8R8A8_UNORM, GL_RGBA8, GL_SRGB8_ALPHA8_EXT, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, - WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING | WINED3DFMT_FLAG_RENDERTARGET | - WINED3DFMT_FLAG_GETDC, + WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING | WINED3DFMT_FLAG_RENDERTARGET, WINED3D_GL_EXT_NONE}, {WINED3DFMT_B8G8R8X8_UNORM, GL_RGB8, GL_SRGB8_EXT, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, - WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING | WINED3DFMT_FLAG_RENDERTARGET | - WINED3DFMT_FLAG_GETDC, + WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING | WINED3DFMT_FLAG_RENDERTARGET, WINED3D_GL_EXT_NONE}, {WINED3DFMT_B5G6R5_UNORM, GL_RGB5, GL_RGB5, GL_RGB8, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, - WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING | WINED3DFMT_FLAG_RENDERTARGET | - WINED3DFMT_FLAG_GETDC, + WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING | WINED3DFMT_FLAG_RENDERTARGET, WINED3D_GL_EXT_NONE}, {WINED3DFMT_B5G5R5X1_UNORM, GL_RGB5, GL_RGB5_A1, 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, - WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING | - WINED3DFMT_FLAG_GETDC, + WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING, WINED3D_GL_EXT_NONE}, {WINED3DFMT_B5G5R5A1_UNORM, GL_RGB5_A1, GL_RGB5_A1, 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, - WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING | - WINED3DFMT_FLAG_GETDC, + WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING, WINED3D_GL_EXT_NONE}, {WINED3DFMT_B4G4R4A4_UNORM, GL_RGBA4, GL_SRGB8_ALPHA8_EXT, 0, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, - WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING | - WINED3DFMT_FLAG_GETDC, + WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING, WINED3D_GL_EXT_NONE}, {WINED3DFMT_B2G3R3_UNORM, GL_R3_G3_B2, GL_R3_G3_B2, 0, GL_RGB, GL_UNSIGNED_BYTE_3_3_2, @@ -346,7 +373,7 @@ static const GlPixelFormatDescTemplate gl_formats_template[] = { WINED3D_GL_EXT_NONE}, {WINED3DFMT_B4G4R4X4_UNORM, GL_RGB4, GL_RGB4, 0, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, - WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING | WINED3DFMT_FLAG_GETDC, + WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING, WINED3D_GL_EXT_NONE}, {WINED3DFMT_R10G10B10A2_UNORM, GL_RGB10_A2, GL_RGB10_A2, 0, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, @@ -354,11 +381,11 @@ static const GlPixelFormatDescTemplate gl_formats_template[] = { WINED3D_GL_EXT_NONE}, {WINED3DFMT_R8G8B8A8_UNORM, GL_RGBA8, GL_RGBA8, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, - WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING | WINED3DFMT_FLAG_GETDC, + WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING, WINED3D_GL_EXT_NONE}, {WINED3DFMT_R8G8B8X8_UNORM, GL_RGB8, GL_RGB8, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, - WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING | WINED3DFMT_FLAG_GETDC, + WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING | WINED3DFMT_FLAG_FILTERING, WINED3D_GL_EXT_NONE}, {WINED3DFMT_R16G16_UNORM, GL_RGB16_EXT, GL_RGB16_EXT, GL_RGBA16_EXT, GL_RGB, GL_UNSIGNED_SHORT, @@ -542,7 +569,21 @@ static BOOL init_format_base_info(struct wined3d_gl_info *gl_info) desc->byte_count = formats[i].bpp; desc->depth_size = formats[i].depthSize; desc->stencil_size = formats[i].stencilSize; - if (formats[i].isFourcc) desc->Flags |= WINED3DFMT_FLAG_FOURCC; + } + + for (i = 0; i < (sizeof(format_base_flags) / sizeof(*format_base_flags)); ++i) + { + int fmt_idx = getFmtIdx(format_base_flags[i].format); + + if (fmt_idx == -1) + { + ERR("Format %s (%#x) not found.\n", + debug_d3dformat(format_base_flags[i].format), format_base_flags[i].format); + HeapFree(GetProcessHeap(), 0, gl_info->gl_formats); + return FALSE; + } + + gl_info->gl_formats[fmt_idx].Flags |= format_base_flags[i].flags; } return TRUE; @@ -2731,3 +2772,63 @@ UINT wined3d_log2i(UINT32 x) return (i = x >> 16) ? (x = i >> 8) ? l[x] + 24 : l[i] + 16 : (i = x >> 8) ? l[i] + 8 : l[x]; } + +/* Set the shader type for this device, depending on the given capabilities + * and the user preferences in wined3d_settings. */ +void select_shader_mode(const struct wined3d_gl_info *gl_info, int *ps_selected, int *vs_selected) +{ + if (wined3d_settings.vs_mode == VS_NONE) *vs_selected = SHADER_NONE; + else if (gl_info->supported[ARB_VERTEX_SHADER] && wined3d_settings.glslRequested) + { + /* Geforce4 cards support GLSL but for vertex shaders only. Further its reported GLSL caps are + * wrong. This combined with the fact that glsl won't offer more features or performance, use ARB + * shaders only on this card. */ + if (gl_info->supported[NV_VERTEX_PROGRAM] && !gl_info->supported[NV_VERTEX_PROGRAM2]) *vs_selected = SHADER_ARB; + else *vs_selected = SHADER_GLSL; + } + else if (gl_info->supported[ARB_VERTEX_PROGRAM]) *vs_selected = SHADER_ARB; + else *vs_selected = SHADER_NONE; + + if (wined3d_settings.ps_mode == PS_NONE) *ps_selected = SHADER_NONE; + else if (gl_info->supported[ARB_FRAGMENT_SHADER] && wined3d_settings.glslRequested) *ps_selected = SHADER_GLSL; + else if (gl_info->supported[ARB_FRAGMENT_PROGRAM]) *ps_selected = SHADER_ARB; + else if (gl_info->supported[ATI_FRAGMENT_SHADER]) *ps_selected = SHADER_ATI; + else *ps_selected = SHADER_NONE; +} + +const shader_backend_t *select_shader_backend(struct wined3d_adapter *adapter, WINED3DDEVTYPE device_type) +{ + int vs_selected_mode, ps_selected_mode; + + select_shader_mode(&adapter->gl_info, &ps_selected_mode, &vs_selected_mode); + if (vs_selected_mode == SHADER_GLSL || ps_selected_mode == SHADER_GLSL) return &glsl_shader_backend; + if (vs_selected_mode == SHADER_ARB || ps_selected_mode == SHADER_ARB) return &arb_program_shader_backend; + return &none_shader_backend; +} + +const struct fragment_pipeline *select_fragment_implementation(struct wined3d_adapter *adapter, + WINED3DDEVTYPE device_type) +{ + const struct wined3d_gl_info *gl_info = &adapter->gl_info; + int vs_selected_mode, ps_selected_mode; + + select_shader_mode(gl_info, &ps_selected_mode, &vs_selected_mode); + if ((ps_selected_mode == SHADER_ARB || ps_selected_mode == SHADER_GLSL) + && gl_info->supported[ARB_FRAGMENT_PROGRAM]) return &arbfp_fragment_pipeline; + else if (ps_selected_mode == SHADER_ATI) return &atifs_fragment_pipeline; + else if (gl_info->supported[NV_REGISTER_COMBINERS] + && gl_info->supported[NV_TEXTURE_SHADER2]) return &nvts_fragment_pipeline; + else if (gl_info->supported[NV_REGISTER_COMBINERS]) return &nvrc_fragment_pipeline; + else return &ffp_fragment_pipeline; +} + +const struct blit_shader *select_blit_implementation(struct wined3d_adapter *adapter, WINED3DDEVTYPE device_type) +{ + const struct wined3d_gl_info *gl_info = &adapter->gl_info; + int vs_selected_mode, ps_selected_mode; + + select_shader_mode(gl_info, &ps_selected_mode, &vs_selected_mode); + if ((ps_selected_mode == SHADER_ARB || ps_selected_mode == SHADER_GLSL) + && gl_info->supported[ARB_FRAGMENT_PROGRAM]) return &arbfp_blit; + else return &ffp_blit; +} diff --git a/dlls/wined3d/volume.c b/dlls/wined3d/volume.c index bb5827e9020..5a80cb6fd52 100644 --- a/dlls/wined3d/volume.c +++ b/dlls/wined3d/volume.c @@ -187,11 +187,13 @@ static HRESULT WINAPI IWineD3DVolumeImpl_GetContainer(IWineD3DVolume *iface, REF if (!ppContainer) { ERR("Called without a valid ppContainer.\n"); + return E_FAIL; } /* Although surfaces can be standalone, volumes can't */ if (!This->container) { ERR("Volume without an container. Should not happen.\n"); + return E_FAIL; } TRACE("Relaying to QueryInterface\n"); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index f4237335cf3..12685d20518 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1555,9 +1555,6 @@ struct IWineD3DDeviceImpl /* Textures for when no other textures are mapped */ UINT dummyTextureName[MAX_TEXTURES]; - /* Device state management */ - HRESULT state; - /* DirectDraw stuff */ DWORD ddraw_width, ddraw_height; WINED3DFORMAT ddraw_format; @@ -1586,8 +1583,9 @@ struct IWineD3DDeviceImpl struct WineD3DRectPatch *currentPatch; }; -extern const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl DECLSPEC_HIDDEN; - +HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d, + UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags, + IUnknown *parent, IWineD3DDeviceParent *device_parent) DECLSPEC_HIDDEN; void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource) DECLSPEC_HIDDEN; void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource) DECLSPEC_HIDDEN; void device_stream_info_from_declaration(IWineD3DDeviceImpl *This, @@ -2525,6 +2523,14 @@ void multiply_matrix(WINED3DMATRIX *dest, const WINED3DMATRIX *src1, const WINED UINT wined3d_log2i(UINT32 x) DECLSPEC_HIDDEN; unsigned int count_bits(unsigned int mask) DECLSPEC_HIDDEN; +const struct blit_shader *select_blit_implementation(struct wined3d_adapter *adapter, + WINED3DDEVTYPE device_type) DECLSPEC_HIDDEN; +const struct fragment_pipeline *select_fragment_implementation(struct wined3d_adapter *adapter, + WINED3DDEVTYPE device_type) DECLSPEC_HIDDEN; +const shader_backend_t *select_shader_backend(struct wined3d_adapter *adapter, + WINED3DDEVTYPE device_type) DECLSPEC_HIDDEN; +void select_shader_mode(const struct wined3d_gl_info *gl_info, int *ps_selected, int *vs_selected) DECLSPEC_HIDDEN; + typedef struct local_constant { struct list entry; unsigned int idx; diff --git a/dlls/wineps.drv/bitmap.c b/dlls/wineps.drv/bitmap.c index 0c350d2206c..c450bcad5d1 100644 --- a/dlls/wineps.drv/bitmap.c +++ b/dlls/wineps.drv/bitmap.c @@ -228,7 +228,7 @@ INT CDECL PSDRV_StretchDIBits( PSDRV_PDEVICE *physDev, INT xDst, INT yDst, INT w const BITMAPINFO *info, UINT wUsage, DWORD dwRop ) { LONG fullSrcWidth, fullSrcHeight; - INT widthbytes; + INT stride; WORD bpp, compression; INT line; POINT pt[2]; @@ -241,7 +241,8 @@ INT CDECL PSDRV_StretchDIBits( PSDRV_PDEVICE *physDev, INT xDst, INT yDst, INT w if (!get_bitmap_info( info, &fullSrcWidth, &fullSrcHeight, &bpp, &compression )) return FALSE; - widthbytes = get_dib_width_bytes(fullSrcWidth, bpp); + stride = get_dib_width_bytes(fullSrcWidth, bpp); + if(fullSrcHeight < 0) stride = -stride; /* top-down */ TRACE("full size=%dx%d bpp=%d compression=%d rop=%08x\n", fullSrcWidth, fullSrcHeight, bpp, compression, dwRop); @@ -272,12 +273,13 @@ INT CDECL PSDRV_StretchDIBits( PSDRV_PDEVICE *physDev, INT xDst, INT yDst, INT w PSDRV_WriteImageMaskHeader(physDev, info, xDst, yDst, widthDst, heightDst, widthSrc, heightSrc); src_ptr = bits; - src_ptr += (ySrc * widthbytes); + if(stride < 0) src_ptr += (fullSrcHeight + 1) * stride; + src_ptr += (ySrc * stride); if(xSrc & 7) FIXME("This won't work...\n"); bitmap_size = heightSrc * ((widthSrc + 7) / 8); dst_ptr = bitmap = HeapAlloc(GetProcessHeap(), 0, bitmap_size); - for(line = 0; line < heightSrc; line++, src_ptr += widthbytes, dst_ptr += ((widthSrc + 7) / 8)) + for(line = 0; line < heightSrc; line++, src_ptr += stride, dst_ptr += ((widthSrc + 7) / 8)) memcpy(dst_ptr, src_ptr + xSrc / 8, (widthSrc + 7) / 8); break; @@ -287,12 +289,13 @@ INT CDECL PSDRV_StretchDIBits( PSDRV_PDEVICE *physDev, INT xDst, INT yDst, INT w PSDRV_WriteImageHeader(physDev, info, xDst, yDst, widthDst, heightDst, widthSrc, heightSrc); src_ptr = bits; - src_ptr += (ySrc * widthbytes); + if(stride < 0) src_ptr += (fullSrcHeight + 1) * stride; + src_ptr += (ySrc * stride); if(xSrc & 1) FIXME("This won't work...\n"); bitmap_size = heightSrc * ((widthSrc + 1) / 2); dst_ptr = bitmap = HeapAlloc(GetProcessHeap(), 0, bitmap_size); - for(line = 0; line < heightSrc; line++, src_ptr += widthbytes, dst_ptr += ((widthSrc + 1) / 2)) + for(line = 0; line < heightSrc; line++, src_ptr += stride, dst_ptr += ((widthSrc + 1) / 2)) memcpy(dst_ptr, src_ptr + xSrc/2, (widthSrc+1)/2); break; @@ -302,10 +305,11 @@ INT CDECL PSDRV_StretchDIBits( PSDRV_PDEVICE *physDev, INT xDst, INT yDst, INT w PSDRV_WriteImageHeader(physDev, info, xDst, yDst, widthDst, heightDst, widthSrc, heightSrc); src_ptr = bits; - src_ptr += (ySrc * widthbytes); + if(stride < 0) src_ptr += (fullSrcHeight + 1) * stride; + src_ptr += (ySrc * stride); bitmap_size = heightSrc * widthSrc; dst_ptr = bitmap = HeapAlloc(GetProcessHeap(), 0, bitmap_size); - for(line = 0; line < heightSrc; line++, src_ptr += widthbytes, dst_ptr += widthSrc) + for(line = 0; line < heightSrc; line++, src_ptr += stride, dst_ptr += widthSrc) memcpy(dst_ptr, src_ptr + xSrc, widthSrc); break; @@ -318,11 +322,12 @@ INT CDECL PSDRV_StretchDIBits( PSDRV_PDEVICE *physDev, INT xDst, INT yDst, INT w src_ptr = bits; - src_ptr += (ySrc * widthbytes); + if(stride < 0) src_ptr += (fullSrcHeight + 1) * stride; + src_ptr += (ySrc * stride); bitmap_size = heightSrc * widthSrc * 3; dst_ptr = bitmap = HeapAlloc(GetProcessHeap(), 0, bitmap_size); - for(line = 0; line < heightSrc; line++, src_ptr += widthbytes) { + for(line = 0; line < heightSrc; line++, src_ptr += stride) { const WORD *words = (const WORD *)src_ptr + xSrc; int i; for(i = 0; i < widthSrc; i++) { @@ -350,10 +355,11 @@ INT CDECL PSDRV_StretchDIBits( PSDRV_PDEVICE *physDev, INT xDst, INT yDst, INT w widthSrc, heightSrc); src_ptr = bits; - src_ptr += (ySrc * widthbytes); + if(stride < 0) src_ptr += (fullSrcHeight + 1) * stride; + src_ptr += (ySrc * stride); bitmap_size = heightSrc * widthSrc * 3; dst_ptr = bitmap = HeapAlloc(GetProcessHeap(), 0, bitmap_size); - for(line = 0; line < heightSrc; line++, src_ptr += widthbytes) { + for(line = 0; line < heightSrc; line++, src_ptr += stride) { const BYTE *byte = src_ptr + xSrc * 3; int i; for(i = 0; i < widthSrc; i++) { @@ -372,10 +378,11 @@ INT CDECL PSDRV_StretchDIBits( PSDRV_PDEVICE *physDev, INT xDst, INT yDst, INT w widthSrc, heightSrc); src_ptr = bits; - src_ptr += (ySrc * widthbytes); + if(stride < 0) src_ptr += (fullSrcHeight + 1) * stride; + src_ptr += (ySrc * stride); bitmap_size = heightSrc * widthSrc * 3; dst_ptr = bitmap = HeapAlloc(GetProcessHeap(), 0, bitmap_size); - for(line = 0; line < heightSrc; line++, src_ptr += widthbytes) { + for(line = 0; line < heightSrc; line++, src_ptr += stride) { const BYTE *byte = src_ptr + xSrc * 4; int i; for(i = 0; i < widthSrc; i++) { diff --git a/dlls/wineps.drv/init.c b/dlls/wineps.drv/init.c index 78aa0cb4f6d..152ee03c975 100644 --- a/dlls/wineps.drv/init.c +++ b/dlls/wineps.drv/init.c @@ -111,6 +111,8 @@ static const LOGFONTA DefaultLogFont = { DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, "" }; +static const CHAR default_devmodeA[] = "Default DevMode"; + /********************************************************************* * DllMain * @@ -399,14 +401,10 @@ BOOL CDECL PSDRV_DeleteDC( PSDRV_PDEVICE *physDev ) HDC CDECL PSDRV_ResetDC( PSDRV_PDEVICE *physDev, const DEVMODEW *lpInitData ) { if(lpInitData) { - HRGN hrgn; DEVMODEA *devmodeA = DEVMODEdupWtoA(PSDRV_Heap, lpInitData); PSDRV_MergeDevmodes(physDev->Devmode, (PSDRV_DEVMODEA *)devmodeA, physDev->pi); HeapFree(PSDRV_Heap, 0, devmodeA); PSDRV_UpdateDevCaps(physDev); - hrgn = CreateRectRgn(0, 0, physDev->horzRes, physDev->vertRes); - SelectVisRgn( physDev->hdc, hrgn ); - DeleteObject(hrgn); } return physDev->hdc; } @@ -532,7 +530,7 @@ PRINTERINFO *PSDRV_FindPrinterInfo(LPCSTR name) PRINTERINFO *pi = PSDRV_PrinterList, **last = &PSDRV_PrinterList; FONTNAME *font; const AFM *afm; - HANDLE hPrinter; + HANDLE hPrinter = 0; const char *ppd = NULL; DWORD ppdType; char* ppdFileName = NULL; @@ -556,32 +554,33 @@ PRINTERINFO *PSDRV_FindPrinterInfo(LPCSTR name) if (!(pi->FriendlyName = HeapAlloc( PSDRV_Heap, 0, strlen(name)+1 ))) goto fail; strcpy( pi->FriendlyName, name ); - /* Use Get|SetPrinterDataExA instead? */ + if (OpenPrinterA (pi->FriendlyName, &hPrinter, NULL) == 0) { + ERR ("OpenPrinterA failed with code %i\n", GetLastError ()); + goto cleanup; + } - res = DrvGetPrinterData16((LPSTR)name, (LPSTR)INT_PD_DEFAULT_DEVMODE, &type, - NULL, 0, &needed ); + needed = 0; + res = GetPrinterDataExA(hPrinter, NULL, default_devmodeA, &type, NULL, 0, &needed); - if(res == ERROR_INVALID_PRINTER_NAME || needed != sizeof(DefaultDevmode)) { + if (needed < sizeof(DefaultDevmode)) { pi->Devmode = HeapAlloc( PSDRV_Heap, 0, sizeof(DefaultDevmode) ); - if (pi->Devmode == NULL) - goto cleanup; - *pi->Devmode = DefaultDevmode; - lstrcpynA((LPSTR)pi->Devmode->dmPublic.dmDeviceName,name,CCHDEVICENAME); - using_default_devmode = TRUE; + if (pi->Devmode == NULL) + goto closeprinter; - /* need to do something here AddPrinter?? */ + *pi->Devmode = DefaultDevmode; + lstrcpynA((LPSTR)pi->Devmode->dmPublic.dmDeviceName,name,CCHDEVICENAME); + using_default_devmode = TRUE; } else { pi->Devmode = HeapAlloc( PSDRV_Heap, 0, needed ); - DrvGetPrinterData16((LPSTR)name, (LPSTR)INT_PD_DEFAULT_DEVMODE, &type, - (LPBYTE)pi->Devmode, needed, &needed); - } + if (pi->Devmode == NULL) + goto closeprinter; - if (OpenPrinterA (pi->FriendlyName, &hPrinter, NULL) == 0) { - ERR ("OpenPrinterA failed with code %i\n", GetLastError ()); - goto cleanup; + GetPrinterDataExA(hPrinter, NULL, default_devmodeA, &type, (LPBYTE)pi->Devmode, needed, &needed); } + + #ifdef SONAME_LIBCUPS if (cupshandle != (void*)-1) { typeof(cupsGetPPD) * pcupsGetPPD = NULL; @@ -687,8 +686,9 @@ PRINTERINFO *PSDRV_FindPrinterInfo(LPCSTR name) dm.dmPublic.u1.s1.dmPaperSize = papersize; PSDRV_MergeDevmodes(pi->Devmode, &dm, pi); } - DrvSetPrinterData16((LPSTR)name, (LPSTR)INT_PD_DEFAULT_DEVMODE, - REG_BINARY, (LPBYTE)pi->Devmode, sizeof(DefaultDevmode) ); + + SetPrinterDataExA(hPrinter, NULL, default_devmodeA, REG_BINARY, + (LPBYTE)pi->Devmode, sizeof(DefaultDevmode)); } if(pi->ppd->DefaultPageSize) { /* We'll let the ppd override the devmode */ diff --git a/dlls/winex11.drv/bitmap.c b/dlls/winex11.drv/bitmap.c index 47d2562a507..5992b316359 100644 --- a/dlls/winex11.drv/bitmap.c +++ b/dlls/winex11.drv/bitmap.c @@ -144,7 +144,7 @@ BOOL CDECL X11DRV_CreateBitmap( X11DRV_PDEVICE *physDev, HBITMAP hbitmap, LPVOID /* check if bpp is compatible with screen depth */ if (!((bitmap.bmBitsPixel == 1) || (bitmap.bmBitsPixel == screen_bpp))) { - ERR("Trying to make bitmap with planes=%d, bpp=%d\n", + WARN("Trying to make bitmap with planes=%d, bpp=%d\n", bitmap.bmPlanes, bitmap.bmBitsPixel); return FALSE; } diff --git a/dlls/winex11.drv/clipboard.c b/dlls/winex11.drv/clipboard.c index 82928a228aa..2740264e976 100644 --- a/dlls/winex11.drv/clipboard.c +++ b/dlls/winex11.drv/clipboard.c @@ -167,6 +167,8 @@ static HANDLE X11DRV_CLIPBOARD_ExportMetaFilePict(Display *display, Window reque Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes); static HANDLE X11DRV_CLIPBOARD_ExportEnhMetaFile(Display *display, Window requestor, Atom aTarget, Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes); +static HANDLE X11DRV_CLIPBOARD_ExportTextHtml(Display *display, Window requestor, Atom aTarget, + Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes); static WINE_CLIPFORMAT *X11DRV_CLIPBOARD_InsertClipboardFormat(LPCWSTR FormatName, Atom prop); static BOOL X11DRV_CLIPBOARD_RenderSynthesizedText(Display *display, UINT wFormatID); static void X11DRV_CLIPBOARD_FreeData(LPWINE_CLIPDATA lpData); @@ -307,7 +309,7 @@ static const struct { wszGIF, XATOM_image_gif }, { wszJFIF, XATOM_image_jpeg }, { wszPNG, XATOM_image_png }, - { wszHTMLFormat, XATOM_text_html }, + { wszHTMLFormat, XATOM_HTML_Format }, /* prefer this to text/html */ }; @@ -358,10 +360,15 @@ static Window thread_selection_wnd(void) void X11DRV_InitClipboard(void) { UINT i; + WINE_CLIPFORMAT *format; /* Register known mapping between window formats and X properties */ for (i = 0; i < sizeof(PropertyFormatMap)/sizeof(PropertyFormatMap[0]); i++) X11DRV_CLIPBOARD_InsertClipboardFormat(PropertyFormatMap[i].lpszFormat, GET_ATOM(PropertyFormatMap[i].prop)); + + /* Set up a conversion function from "HTML Format" to "text/html" */ + format = X11DRV_CLIPBOARD_InsertClipboardFormat(wszHTMLFormat, GET_ATOM(XATOM_text_html)); + format->lpDrvExportFunc = X11DRV_CLIPBOARD_ExportTextHtml; } @@ -1820,6 +1827,113 @@ static HANDLE X11DRV_CLIPBOARD_ExportEnhMetaFile(Display *display, Window reques /************************************************************************** + * get_html_description_field + * + * Find the value of a field in an HTML Format description. + */ +static LPCSTR get_html_description_field(LPCSTR data, LPCSTR keyword) +{ + LPCSTR pos=data; + + while (pos && *pos && *pos != '<') + { + if (memcmp(pos, keyword, strlen(keyword)) == 0) + return pos+strlen(keyword); + + pos = strchr(pos, '\n'); + if (pos) pos++; + } + + return NULL; +} + + +/************************************************************************** + * X11DRV_CLIPBOARD_ExportTextHtml + * + * Export HTML Format to text/html. + * + * FIXME: We should attempt to add an tag and convert windows paths. + */ +static HANDLE X11DRV_CLIPBOARD_ExportTextHtml(Display *display, Window requestor, Atom aTarget, + Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes) +{ + HANDLE hdata; + UINT datasize; + LPCSTR data, field_value; + UINT fragmentstart, fragmentend, htmlsize; + HANDLE hhtmldata=NULL; + LPSTR htmldata; + + *lpBytes = 0; + + if (!X11DRV_CLIPBOARD_RenderFormat(display, lpdata)) + { + ERR("Failed to export %04x format\n", lpdata->wFormatID); + return 0; + } + + hdata = lpdata->hData32; + + datasize = GlobalSize(hdata); + + data = GlobalLock(hdata); + if (!data) + { + ERR("Failed to lock HTML Format data\n"); + return 0; + } + + /* read the important fields */ + field_value = get_html_description_field(data, "StartFragment:"); + if (!field_value) + { + ERR("Couldn't find StartFragment value\n"); + goto end; + } + fragmentstart = atoi(field_value); + + field_value = get_html_description_field(data, "EndFragment:"); + if (!field_value) + { + ERR("Couldn't find EndFragment value\n"); + goto end; + } + fragmentend = atoi(field_value); + + /* export only the fragment */ + htmlsize = fragmentend - fragmentstart + 1; + + hhtmldata = GlobalAlloc(0, htmlsize); + + if (hhtmldata) + { + htmldata = GlobalLock(hhtmldata); + + if (!htmldata) + { + GlobalFree(hhtmldata); + htmldata = NULL; + goto end; + } + + memcpy(htmldata, &data[fragmentstart], fragmentend-fragmentstart); + htmldata[htmlsize-1] = '\0'; + + *lpBytes = htmlsize; + + GlobalUnlock(htmldata); + } + +end: + + GlobalUnlock(hdata); + + return hhtmldata; +} + + +/************************************************************************** * X11DRV_CLIPBOARD_QueryTargets */ static BOOL X11DRV_CLIPBOARD_QueryTargets(Display *display, Window w, Atom selection, diff --git a/dlls/winex11.drv/graphics.c b/dlls/winex11.drv/graphics.c index e6cedfb078e..bc00e854f73 100644 --- a/dlls/winex11.drv/graphics.c +++ b/dlls/winex11.drv/graphics.c @@ -1476,18 +1476,6 @@ BOOL CDECL X11DRV_GetDCOrgEx( X11DRV_PDEVICE *physDev, LPPOINT lpp ) } -/*********************************************************************** - * SetDCOrg (X11DRV.@) - */ -DWORD CDECL X11DRV_SetDCOrg( X11DRV_PDEVICE *physDev, INT x, INT y ) -{ - DWORD ret = MAKELONG( physDev->dc_rect.left + physDev->drawable_rect.left, - physDev->dc_rect.top + physDev->drawable_rect.top ); - physDev->dc_rect.left = x - physDev->drawable_rect.left; - physDev->dc_rect.top = y - physDev->drawable_rect.top; - return ret; -} - static unsigned char *get_icm_profile( unsigned long *size ) { Atom type; diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 45da4791ca1..19e3fe3bfce 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -103,8 +103,13 @@ typedef struct wine_glpixelformat { typedef struct wine_glcontext { HDC hdc; BOOL do_escape; + BOOL has_been_current; + BOOL sharing; + BOOL gl3_context; XVisualInfo *vis; WineGLPixelFormat *fmt; + int numAttribs; /* This is needed for delaying wglCreateContextAttribsARB */ + int attribList[16]; /* This is needed for delaying wglCreateContextAttribsARB */ GLXContext ctx; HDC read_hdc; Drawable drawables[2]; @@ -238,6 +243,7 @@ MAKE_FUNCPTR(glXQueryDrawable) MAKE_FUNCPTR(glXGetCurrentReadDrawable) /* GLX Extensions */ +static GLXContext (*pglXCreateContextAttribsARB)(Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list); static void* (*pglXGetProcAddressARB)(const GLubyte *); static int (*pglXSwapIntervalSGI)(int); @@ -272,6 +278,12 @@ MAKE_FUNCPTR(glFinish) MAKE_FUNCPTR(glFlush) #undef MAKE_FUNCPTR +static int GLXErrorHandler(Display *dpy, XErrorEvent *event, void *arg) +{ + /* In the future we might want to find the exact X or GLX error to report back to the app */ + return 1; +} + static BOOL infoInitialized = FALSE; static BOOL X11DRV_WineGL_InitOpenglInfo(void) { @@ -440,6 +452,8 @@ static BOOL has_opengl(void) the associated extension is available (and if a driver reports the extension is available but fails to provide the functions, it's quite broken) */ #define LOAD_FUNCPTR(f) p##f = (void*)pglXGetProcAddressARB((const unsigned char*)#f) + /* ARB GLX Extension */ + LOAD_FUNCPTR(glXCreateContextAttribsARB); /* NV GLX Extension */ LOAD_FUNCPTR(glXAllocateMemoryNV); LOAD_FUNCPTR(glXFreeMemoryNV); @@ -1064,7 +1078,14 @@ static GLXContext create_glxcontext(Display *display, Wine_GLContext *context, G /* We use indirect rendering for rendering to bitmaps. See get_formats for a comment about this. */ BOOL indirect = (context->fmt->dwFlags & PFD_DRAW_TO_BITMAP) ? FALSE : TRUE; - if(context->vis) + if(context->gl3_context) + { + if(context->numAttribs) + ctx = pglXCreateContextAttribsARB(gdi_display, context->fmt->fbconfig, shareList, indirect, context->attribList); + else + ctx = pglXCreateContextAttribsARB(gdi_display, context->fmt->fbconfig, shareList, indirect, NULL); + } + else if(context->vis) ctx = pglXCreateContext(gdi_display, context->vis, shareList, indirect); else /* Create a GLX Context for a pbuffer */ ctx = pglXCreateNewContext(gdi_display, context->fmt->fbconfig, context->fmt->render_type, shareList, TRUE); @@ -1628,41 +1649,7 @@ BOOL CDECL X11DRV_wglCopyContext(HGLRC hglrcSrc, HGLRC hglrcDst, UINT mask) { TRACE("hglrcSrc: (%p), hglrcDst: (%p), mask: %#x\n", hglrcSrc, hglrcDst, mask); - /* There is a slight difference in the way GL contexts share display lists in WGL and GLX. - * In case of GLX you need to specify this at context creation time but in case of WGL you - * do this using wglShareLists which you can call after creating the context. - * To emulate WGL we try to delay the creation of the context until wglShareLists or wglMakeCurrent. - * Up to now that works fine. - * - * The delayed GLX context creation could cause issues for wglCopyContext as it might get called - * when there is no GLX context yet. The chance this will cause problems is small as at the time of - * writing Wine has had OpenGL support for more than 7 years and this function has remained a stub - * ever since then. - */ - if(!src->ctx || !dst->ctx) { - /* NOTE: As a special case, if both GLX contexts are NULL, that means - * neither WGL context was made current. In that case, both contexts - * are in a default state, so any copy would no-op. - */ - if(!src->ctx && !dst->ctx) { - TRACE("No source or destination contexts set. No-op.\n"); - return TRUE; - } - - if (!src->ctx) { - wine_tsx11_lock(); - src->ctx = create_glxcontext(gdi_display, src, NULL); - TRACE(" created a delayed OpenGL context (%p)\n", src->ctx); - } - else if (!dst->ctx) { - wine_tsx11_lock(); - dst->ctx = create_glxcontext(gdi_display, dst, NULL); - TRACE(" created a delayed OpenGL context (%p)\n", dst->ctx); - } - } - else - wine_tsx11_lock(); - + wine_tsx11_lock(); pglXCopyContext(gdi_display, src->ctx, dst->ctx, mask); wine_tsx11_unlock(); @@ -1698,15 +1685,16 @@ HGLRC CDECL X11DRV_wglCreateContext(X11DRV_PDEVICE *physDev) return NULL; } - /* The context will be allocated in the wglMakeCurrent call */ wine_tsx11_lock(); ret = alloc_context(); - wine_tsx11_unlock(); ret->hdc = hdc; ret->fmt = fmt; + ret->has_been_current = FALSE; + ret->sharing = FALSE; - /*ret->vis = vis;*/ ret->vis = pglXGetVisualFromFBConfig(gdi_display, fmt->fbconfig); + ret->ctx = create_glxcontext(gdi_display, ret, NULL); + wine_tsx11_unlock(); TRACE(" creating context %p (GL context creation delayed)\n", ret); return (HGLRC) ret; @@ -1824,25 +1812,20 @@ BOOL CDECL X11DRV_wglMakeCurrent(X11DRV_PDEVICE *physDev, HGLRC hglrc) { ret = FALSE; } else { Drawable drawable = get_glxdrawable(physDev); - if (ctx->ctx == NULL) { - /* The describe lines below are for debugging purposes only */ - if (TRACE_ON(wgl)) { - describeDrawable(physDev); - describeContext(ctx); - } - /* Create a GLX context using the same visual as chosen earlier in wglCreateContext. - * We are certain that the drawable and context are compatible as we only allow compatible formats. - */ - TRACE(" Creating GLX Context\n"); - ctx->ctx = create_glxcontext(gdi_display, ctx, NULL); - TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx); + /* The describe lines below are for debugging purposes only */ + if (TRACE_ON(wgl)) { + describeDrawable(physDev); + describeContext(ctx); } + TRACE(" make current for dis %p, drawable %p, ctx %p\n", gdi_display, (void*) drawable, ctx->ctx); ret = pglXMakeCurrent(gdi_display, drawable, ctx->ctx); NtCurrentTeb()->glContext = ctx; + if(ret) { + ctx->has_been_current = TRUE; ctx->hdc = hdc; ctx->read_hdc = hdc; ctx->drawables[0] = drawable; @@ -1886,10 +1869,7 @@ BOOL CDECL X11DRV_wglMakeContextCurrentARB(X11DRV_PDEVICE* pDrawDev, X11DRV_PDEV Drawable d_draw = get_glxdrawable(pDrawDev); Drawable d_read = get_glxdrawable(pReadDev); - if (ctx->ctx == NULL) { - ctx->ctx = create_glxcontext(gdi_display, ctx, NULL); - TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx); - } + ctx->has_been_current = TRUE; ctx->hdc = pDrawDev->hdc; ctx->read_hdc = pReadDev->hdc; ctx->drawables[0] = d_draw; @@ -1918,30 +1898,48 @@ BOOL CDECL X11DRV_wglShareLists(HGLRC hglrc1, HGLRC hglrc2) { if (!has_opengl()) return FALSE; - if (NULL != dest && dest->ctx != NULL) { - ERR("Could not share display lists, context already created !\n"); + /* Sharing of display lists works differently in GLX and WGL. In case of GLX it is done + * at context creation time but in case of WGL it is done using wglShareLists. + * In the past we tried to emulate wglShareLists by delaying GLX context creation until + * either a wglMakeCurrent or wglShareLists. This worked fine for most apps but it causes + * issues for OpenGL 3 because there wglCreateContextAttribsARB can fail in a lot of cases, + * so there delaying context creation doesn't work. + * + * The new approach is to create a GLX context in wglCreateContext / wglCreateContextAttribsARB + * and when a program requests sharing we recreate the destination context if it hasn't been made + * current or when it hasn't shared display lists before. + */ + + if((org->has_been_current && dest->has_been_current) || dest->has_been_current) + { + ERR("Could not share display lists, one of the contexts has been current already !\n"); return FALSE; - } else { - if(org && dest && (GetObjectType(org->hdc) == OBJ_MEMDC) ^ (GetObjectType(dest->hdc) == OBJ_MEMDC)) { + } + else if(dest->sharing) + { + ERR("Could not share display lists because hglrc2 has already shared lists before\n"); + return FALSE; + } + else + { + if((GetObjectType(org->hdc) == OBJ_MEMDC) ^ (GetObjectType(dest->hdc) == OBJ_MEMDC)) + { WARN("Attempting to share a context between a direct and indirect rendering context, expect issues!\n"); } - if (org->ctx == NULL) { - wine_tsx11_lock(); - describeContext(org); + wine_tsx11_lock(); + describeContext(org); + describeContext(dest); - org->ctx = create_glxcontext(gdi_display, org, NULL); - wine_tsx11_unlock(); - TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org); - } - if (NULL != dest) { - wine_tsx11_lock(); - describeContext(dest); - dest->ctx = create_glxcontext(gdi_display, dest, org->ctx); - wine_tsx11_unlock(); - TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx); - return TRUE; - } + /* Re-create the GLX context and share display lists */ + pglXDestroyContext(gdi_display, dest->ctx); + dest->ctx = create_glxcontext(gdi_display, dest, org->ctx); + wine_tsx11_unlock(); + TRACE(" re-created an OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx); + + org->sharing = TRUE; + dest->sharing = TRUE; + return TRUE; } return FALSE; } @@ -2193,6 +2191,98 @@ static void WINAPI X11DRV_wglFlush(void) } /** + * X11DRV_wglCreateContextAttribsARB + * + * WGL_ARB_create_context: wglCreateContextAttribsARB + */ +HGLRC X11DRV_wglCreateContextAttribsARB(X11DRV_PDEVICE *physDev, HGLRC hShareContext, const int* attribList) +{ + Wine_GLContext *ret; + WineGLPixelFormat *fmt; + int hdcPF = physDev->current_pf; + int fmt_count = 0; + + TRACE("(%p %p %p)\n", physDev, hShareContext, attribList); + + if (!has_opengl()) return 0; + + fmt = ConvertPixelFormatWGLtoGLX(gdi_display, hdcPF, TRUE /* Offscreen */, &fmt_count); + /* wglCreateContextAttribsARB supports ALL pixel formats, so also offscreen ones. + * If this fails something is very wrong on the system. */ + if(!fmt) + { + ERR("Cannot get FB Config for iPixelFormat %d, expect problems!\n", hdcPF); + SetLastError(ERROR_INVALID_PIXEL_FORMAT); + return NULL; + } + + wine_tsx11_lock(); + ret = alloc_context(); + wine_tsx11_unlock(); + ret->hdc = physDev->hdc; + ret->fmt = fmt; + ret->vis = NULL; /* glXCreateContextAttribsARB requires a fbconfig instead of a visual */ + ret->gl3_context = TRUE; + + ret->numAttribs = 0; + if(attribList) + { + int *pAttribList = (int*)attribList; + int *pContextAttribList = &ret->attribList[0]; + /* attribList consists of pairs {token, value] terminated with 0 */ + while(pAttribList[0] != 0) + { + TRACE("%#x %#x\n", pAttribList[0], pAttribList[1]); + switch(pAttribList[0]) + { + case WGL_CONTEXT_MAJOR_VERSION_ARB: + pContextAttribList[0] = GLX_CONTEXT_MAJOR_VERSION_ARB; + pContextAttribList[1] = pAttribList[1]; + break; + case WGL_CONTEXT_MINOR_VERSION_ARB: + pContextAttribList[0] = GLX_CONTEXT_MINOR_VERSION_ARB; + pContextAttribList[1] = pAttribList[1]; + break; + case WGL_CONTEXT_LAYER_PLANE_ARB: + break; + case WGL_CONTEXT_FLAGS_ARB: + pContextAttribList[0] = GLX_CONTEXT_FLAGS_ARB; + pContextAttribList[1] = pAttribList[1]; + break; + case WGL_CONTEXT_PROFILE_MASK_ARB: + pContextAttribList[0] = GLX_CONTEXT_PROFILE_MASK_ARB; + pContextAttribList[1] = pAttribList[1]; + break; + default: + ERR("Unhandled attribList pair: %#x %#x\n", pAttribList[0], pAttribList[1]); + } + + ret->numAttribs++; + pAttribList += 2; + pContextAttribList += 2; + } + } + + wine_tsx11_lock(); + X11DRV_expect_error(gdi_display, GLXErrorHandler, NULL); + ret->ctx = create_glxcontext(gdi_display, ret, NULL); + + XSync(gdi_display, False); + if(X11DRV_check_error() || !ret->ctx) + { + /* In the future we should convert the GLX error to a win32 one here if needed */ + ERR("Context creation failed\n"); + free_context(ret); + wine_tsx11_unlock(); + return NULL; + } + + wine_tsx11_unlock(); + TRACE(" creating context %p\n", ret); + return (HGLRC) ret; +} + +/** * X11DRV_wglGetExtensionsStringARB * * WGL_ARB_extensions_string: wglGetExtensionsStringARB @@ -3343,6 +3433,14 @@ static const WineGLExtension WGL_internal_functions = }; +static const WineGLExtension WGL_ARB_create_context = +{ + "WGL_ARB_create_context", + { + { "wglCreateContextAttribsARB", X11DRV_wglCreateContextAttribsARB }, + } +}; + static const WineGLExtension WGL_ARB_extensions_string = { "WGL_ARB_extensions_string", @@ -3443,6 +3541,14 @@ static void X11DRV_WineGL_LoadExtensions(void) /* ARB Extensions */ + if(glxRequireExtension("GLX_ARB_create_context")) + { + register_extension(&WGL_ARB_create_context); + + if(glxRequireExtension("GLX_ARB_create_context_profile")) + register_extension_string("WGL_ARB_create_context_profile"); + } + if(glxRequireExtension("GLX_ARB_fbconfig_float")) { register_extension_string("WGL_ARB_pixel_format_float"); @@ -3715,6 +3821,17 @@ HGLRC CDECL X11DRV_wglCreateContext(X11DRV_PDEVICE *physDev) { } /** + * X11DRV_wglCreateContextAttribsARB + * + * WGL_ARB_create_context: wglCreateContextAttribsARB + */ +HGLRC X11DRV_wglCreateContextAttribsARB(X11DRV_PDEVICE *physDev, HGLRC hShareContext, const int* attribList) +{ + opengl_error(); + return NULL; +} + +/** * X11DRV_wglDeleteContext * * For OpenGL32 wglDeleteContext. diff --git a/dlls/winex11.drv/winex11.drv.spec b/dlls/winex11.drv/winex11.drv.spec index 6fd8831ffad..27f2fb3cf47 100644 --- a/dlls/winex11.drv/winex11.drv.spec +++ b/dlls/winex11.drv/winex11.drv.spec @@ -46,7 +46,6 @@ @ cdecl SetBitmapBits(long ptr long) X11DRV_SetBitmapBits @ cdecl SetBkColor(ptr long) X11DRV_SetBkColor @ cdecl SetDCBrushColor(ptr long) X11DRV_SetDCBrushColor -@ cdecl SetDCOrg(ptr long long) X11DRV_SetDCOrg @ cdecl SetDCPenColor(ptr long) X11DRV_SetDCPenColor @ cdecl SetDIBColorTable(ptr long long ptr) X11DRV_SetDIBColorTable @ cdecl SetDIBits(ptr long long long ptr ptr long) X11DRV_SetDIBits @@ -134,6 +133,7 @@ # OpenGL @ cdecl wglCopyContext(long long long) X11DRV_wglCopyContext @ cdecl wglCreateContext(ptr) X11DRV_wglCreateContext +@ cdecl wglCreateContextAttribsARB(ptr long ptr) X11DRV_wglCreateContextAttribsARB @ cdecl wglDeleteContext(long) X11DRV_wglDeleteContext @ cdecl wglGetProcAddress(str) X11DRV_wglGetProcAddress @ cdecl wglGetPbufferDCARB(ptr ptr) X11DRV_wglGetPbufferDCARB diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 11f8e0d03e0..3dd5edf3e34 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -661,6 +661,7 @@ enum x11drv_atoms XATOM_XdndSelection, XATOM_XdndTarget, XATOM_XdndTypeList, + XATOM_HTML_Format, XATOM_WCF_DIB, XATOM_image_gif, XATOM_image_jpeg, diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index b97426ebd27..3600cd0f850 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -170,6 +170,7 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = "XdndSelection", "XdndTarget", "XdndTypeList", + "HTML Format", "WCF_DIB", "image/gif", "image/jpeg", diff --git a/dlls/wing.dll16/wing.c b/dlls/wing.dll16/wing.c index 750c8daec04..fb4aa56daeb 100644 --- a/dlls/wing.dll16/wing.c +++ b/dlls/wing.dll16/wing.c @@ -27,10 +27,64 @@ #include "wingdi.h" #include "wownt32.h" #include "wine/wingdi16.h" +#include "wine/list.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(wing); +struct dib_segptr_bits +{ + struct list entry; + HBITMAP bmp; + WORD sel; + WORD count; +}; + +static struct list dib_segptr_list = LIST_INIT( dib_segptr_list ); + +/* remove saved bits for bitmaps that no longer exist */ +static void cleanup_segptr_bits(void) +{ + unsigned int i; + struct dib_segptr_bits *bits, *next; + + LIST_FOR_EACH_ENTRY_SAFE( bits, next, &dib_segptr_list, struct dib_segptr_bits, entry ) + { + if (GetObjectType( bits->bmp ) == OBJ_BITMAP) continue; + for (i = 0; i < bits->count; i++) FreeSelector16( bits->sel + (i << __AHSHIFT) ); + list_remove( &bits->entry ); + HeapFree( GetProcessHeap(), 0, bits ); + } +} + +static SEGPTR alloc_segptr_bits( HBITMAP bmp, void *bits32 ) +{ + DIBSECTION dib; + unsigned int i, size; + struct dib_segptr_bits *bits; + + cleanup_segptr_bits(); + + if (!(bits = HeapAlloc( GetProcessHeap(), 0, sizeof(*bits) ))) return 0; + + GetObjectW( bmp, sizeof(dib), &dib ); + size = dib.dsBm.bmHeight * dib.dsBm.bmWidthBytes; + + /* calculate number of sel's needed for size with 64K steps */ + bits->bmp = bmp; + bits->count = (size + 0xffff) / 0x10000; + bits->sel = AllocSelectorArray16( bits->count ); + + for (i = 0; i < bits->count; i++) + { + SetSelectorBase(bits->sel + (i << __AHSHIFT), (DWORD)bits32 + i * 0x10000); + SetSelectorLimit16(bits->sel + (i << __AHSHIFT), size - 1); /* yep, limit is correct */ + size -= 0x10000; + } + list_add_head( &dib_segptr_list, &bits->entry ); + return MAKESEGPTR( bits->sel, 0 ); +} + /************************************************************************* * WING {WING} * @@ -127,25 +181,8 @@ HBITMAP16 WINAPI WinGCreateBitmap16(HDC16 hdc, BITMAPINFO *bmpi, SEGPTR *bits) hbitmap = CreateDIBSection( HDC_32(hdc), bmpi, BI_RGB, &bits32, 0, 0 ); if (hbitmap) { - DIBSECTION dib; - DWORD size; - WORD count, sel; - int i; - - GetObjectW( hbitmap, sizeof(dib), &dib ); - size = dib.dsBm.bmHeight * dib.dsBm.bmWidthBytes; - - /* calculate number of sel's needed for size with 64K steps */ - count = (size + 0xffff) / 0x10000; - sel = AllocSelectorArray16(count); - - for (i = 0; i < count; i++) - { - SetSelectorBase(sel + (i << __AHSHIFT), (DWORD)bits32 + i * 0x10000); - SetSelectorLimit16(sel + (i << __AHSHIFT), size - 1); /* yep, limit is correct */ - size -= 0x10000; - } - if (bits) *bits = MAKESEGPTR( sel, 0 ); + SEGPTR segptr = alloc_segptr_bits( hbitmap, bits32 ); + if (bits) *bits = segptr; } return HBITMAP_16(hbitmap); } @@ -155,7 +192,13 @@ HBITMAP16 WINAPI WinGCreateBitmap16(HDC16 hdc, BITMAPINFO *bmpi, SEGPTR *bits) */ SEGPTR WINAPI WinGGetDIBPointer16(HBITMAP16 hWinGBitmap, BITMAPINFO* bmpi) { - FIXME("%x, %p: not supported\n", hWinGBitmap, bmpi ); + struct dib_segptr_bits *bits; + + if (bmpi) FIXME( "%04x %p: setting BITMAPINFO not supported\n", hWinGBitmap, bmpi ); + + LIST_FOR_EACH_ENTRY( bits, &dib_segptr_list, struct dib_segptr_bits, entry ) + if (HBITMAP_16(bits->bmp) == hWinGBitmap) return MAKESEGPTR( bits->sel, 0 ); + return 0; } diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c index 1426439c097..36037616123 100644 --- a/dlls/wininet/http.c +++ b/dlls/wininet/http.c @@ -3338,17 +3338,21 @@ BOOL WINAPI HttpSendRequestExW(HINTERNET hRequest, req = &workRequest.u.HttpSendRequestW; if (lpBuffersIn) { - DWORD size; + DWORD size = 0; - if (lpBuffersIn->dwHeadersLength == ~0u) - size = (strlenW( lpBuffersIn->lpcszHeader ) + 1) * sizeof(WCHAR); - else - size = lpBuffersIn->dwHeadersLength * sizeof(WCHAR); + if (lpBuffersIn->lpcszHeader) + { + if (lpBuffersIn->dwHeadersLength == ~0u) + size = (strlenW( lpBuffersIn->lpcszHeader ) + 1) * sizeof(WCHAR); + else + size = lpBuffersIn->dwHeadersLength * sizeof(WCHAR); - req->lpszHeader = HeapAlloc( GetProcessHeap(), 0, size ); - memcpy( req->lpszHeader, lpBuffersIn->lpcszHeader, size ); + req->lpszHeader = HeapAlloc( GetProcessHeap(), 0, size ); + memcpy( req->lpszHeader, lpBuffersIn->lpcszHeader, size ); + } + else req->lpszHeader = NULL; - req->dwHeaderLength = lpBuffersIn->dwHeadersLength; + req->dwHeaderLength = size / sizeof(WCHAR); req->lpOptional = lpBuffersIn->lpvBuffer; req->dwOptionalLength = lpBuffersIn->dwBufferLength; req->dwContentLength = lpBuffersIn->dwBufferTotal; diff --git a/dlls/winmm/mci.c b/dlls/winmm/mci.c index 9198f87358f..49e859859bd 100644 --- a/dlls/winmm/mci.c +++ b/dlls/winmm/mci.c @@ -99,7 +99,7 @@ static inline LPWSTR str_dup_upper( LPCWSTR str ) /************************************************************************** * MCI_GetDriver [internal] */ -static LPWINE_MCIDRIVER MCI_GetDriver(UINT16 wDevID) +static LPWINE_MCIDRIVER MCI_GetDriver(UINT wDevID) { LPWINE_MCIDRIVER wmd = 0; @@ -1232,7 +1232,6 @@ DWORD WINAPI mciSendStringW(LPCWSTR lpstrCommand, LPWSTR lpstrRet, DWORD data[MCI_DATA_SIZE]; DWORD retType; LPCWSTR lpCmd = 0; - LPWSTR devAlias = NULL; static const WCHAR wszNew[] = {'n','e','w',0}; static const WCHAR wszSAliasS[] = {' ','a','l','i','a','s',' ',0}; static const WCHAR wszTypeS[] = {'t','y','p','e',' ',0}; @@ -1311,19 +1310,7 @@ DWORD WINAPI mciSendStringW(LPCWSTR lpstrCommand, LPWSTR lpstrRet, dwFlags |= MCI_OPEN_ELEMENT; data[3] = (DWORD)dev; } - if ((devAlias = strstrW(args, wszSAliasS))) { - WCHAR* tmp2; - devAlias += 7; - if (!(tmp = strchrW(devAlias,' '))) tmp = devAlias + strlenW(devAlias); - if (tmp) *tmp = '\0'; - tmp2 = HeapAlloc(GetProcessHeap(), 0, (tmp - devAlias + 1) * sizeof(WCHAR) ); - memcpy( tmp2, devAlias, (tmp - devAlias) * sizeof(WCHAR) ); - tmp2[tmp - devAlias] = 0; - data[4] = (DWORD)tmp2; - /* should be done in regular options parsing */ - /* dwFlags |= MCI_OPEN_ALIAS; */ - } else if (dev == 0) { - /* "open new" requires alias */ + if (!strstrW(args, wszSAliasS) && !dev) { dwRet = MCIERR_NEW_REQUIRES_ALIAS; goto errCleanUp; } @@ -1669,7 +1656,7 @@ errCleanUp: /************************************************************************** * MCI_Close [internal] */ -static DWORD MCI_Close(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms) +static DWORD MCI_Close(UINT wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms) { DWORD dwRet; LPWINE_MCIDRIVER wmd; @@ -1677,7 +1664,7 @@ static DWORD MCI_Close(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms TRACE("(%04x, %08X, %p)\n", wDevID, dwParam, lpParms); /* Every device must handle MCI_NOTIFY on its own. */ - if (wDevID == MCI_ALL_DEVICE_ID) { + if ((UINT16)wDevID == (UINT16)MCI_ALL_DEVICE_ID) { while (MciDrivers) { /* Retrieve the device ID under lock, but send the message without, * the driver might be calling some winmm functions from another @@ -1894,7 +1881,7 @@ DWORD MCI_SendCommand(UINT wDevID, UINT16 wMsg, DWORD_PTR dwParam1, DWORD_PTR dw dwRet = MCI_Sound(wDevID, dwParam1, (LPMCI_SOUND_PARMSW)dwParam2); break; default: - if (wDevID == MCI_ALL_DEVICE_ID) { + if ((UINT16)wDevID == (UINT16)MCI_ALL_DEVICE_ID) { FIXME("unhandled MCI_ALL_DEVICE_ID\n"); dwRet = MCIERR_CANNOT_USE_ALL; } else { diff --git a/dlls/winmm/tests/mci.c b/dlls/winmm/tests/mci.c index d1c7dab4e33..6607e17c99f 100644 --- a/dlls/winmm/tests/mci.c +++ b/dlls/winmm/tests/mci.c @@ -25,10 +25,15 @@ #include "mmreg.h" #include "wine/test.h" +/* The tests use the MCI's own save capability to create the tempfile.wav to play. + * To use a pre-existing file, write-protect it. */ +static MCIERROR ok_saved = MCIERR_FILE_NOT_FOUND; + typedef union { MCI_STATUS_PARMS status; MCI_WAVE_SET_PARMS set; MCI_WAVE_OPEN_PARMS open; + MCI_SEEK_PARMS seek; } MCI_PARMS_UNION; static const char* dbg_mcierr(MCIERROR err) @@ -112,7 +117,11 @@ static const char* dbg_mcierr(MCIERROR err) X(MCIERR_FILE_WRITE) X(MCIERR_NO_IDENTITY) #undef X - default: return "unknown error"; + default: { + static char name[20]; /* Not to be called twice in a parameter list! */ + sprintf(name, "MMSYSERR %u", err); + return name; + } } } @@ -159,7 +168,7 @@ static void test_openCloseWAVE(HWND hwnd) { MCIERROR err; MCI_GENERIC_PARMS parm; - const char command_open[] = "open new type waveaudio alias mysound"; + const char command_open[] = "open new type waveaudio alias mysound notify"; const char command_close_my[] = "close mysound notify"; const char command_close_all[] = "close all notify"; const char command_sysinfo[] = "sysinfo waveaudio quantity open"; @@ -167,12 +176,25 @@ static void test_openCloseWAVE(HWND hwnd) memset(buf, 0, sizeof(buf)); test_notification(hwnd, "-prior to any command-", 0); - err = mciSendString(command_open, buf, sizeof(buf), NULL); - ok(!err,"mci %s returned error: %d\n", command_open, err); + err = mciSendString("sysinfo all quantity", buf, sizeof(buf), hwnd); + todo_wine ok(!err,"mci %s returned %s\n", command_open, dbg_mcierr(err)); + if(!err) trace("[MCI] with %s drivers\n", buf); + + err = mciSendString("open new type waveaudio alias r shareable", buf, sizeof(buf), NULL); + ok(err==MCIERR_UNSUPPORTED_FUNCTION,"mci open new shareable returned %s\n", dbg_mcierr(err)); + if(!err) { + err = mciSendString("close r", NULL, 0, NULL); + ok(!err,"mci close shareable returned %s\n", dbg_mcierr(err)); + } + + err = mciSendString(command_open, buf, sizeof(buf), hwnd); + ok(!err,"mci %s returned %s\n", command_open, dbg_mcierr(err)); ok(!strcmp(buf,"1"), "mci open deviceId: %s, expected 1\n", buf); + /* Wine<=1.1.33 used to ignore anything past alias XY */ + test_notification(hwnd,"open new alias notify",MCI_NOTIFY_SUCCESSFUL); err = mciSendString("status mysound time format", buf, sizeof(buf), hwnd); - ok(!err,"mci status time format returned error: %d\n", err); + ok(!err,"mci status time format returned %s\n", dbg_mcierr(err)); if(!err) { if (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) == LANG_ENGLISH) ok(!strcmp(buf,"milliseconds"), "mci status time format: %s\n", buf); @@ -180,17 +202,31 @@ static void test_openCloseWAVE(HWND hwnd) } err = mciSendString(command_close_my, NULL, 0, hwnd); - ok(!err,"mci %s returned error: %d\n", command_close_my, err); + ok(!err,"mci %s returned %s\n", command_close_my, dbg_mcierr(err)); test_notification(hwnd, command_close_my, MCI_NOTIFY_SUCCESSFUL); Sleep(5); test_notification(hwnd, command_close_my, 0); + err = mciSendString("open no-such-file-exists.wav alias y", buf, sizeof(buf), NULL); + ok(err==MCIERR_FILE_NOT_FOUND,"open no-such-file.wav returned %s\n", dbg_mcierr(err)); + if(!err) { + err = mciSendString("close y", NULL, 0, NULL); + ok(!err,"close y returned %s\n", dbg_mcierr(err)); + } + + err = mciSendString("open no-such-dir\\file.wav alias y type waveaudio", buf, sizeof(buf), NULL); + ok(err==MCIERR_FILE_NOT_FOUND || broken(err==MCIERR_INVALID_FILE /* Win9X */),"open no-such-dir/file.wav returned %s\n", dbg_mcierr(err)); + if(!err) { + err = mciSendString("close y", NULL, 0, NULL); + ok(!err,"close y returned %s\n", dbg_mcierr(err)); + } + err = mciSendString(command_close_all, NULL, 0, NULL); - todo_wine ok(!err,"mci %s (without buffer) returned error: %d\n", command_close_all, err); + todo_wine ok(!err,"mci %s (without buffer) returned %s\n", command_close_all, dbg_mcierr(err)); memset(buf, 0, sizeof(buf)); err = mciSendString(command_close_all, buf, sizeof(buf), hwnd); - todo_wine ok(!err,"mci %s (with output buffer) returned error: %d\n", command_close_all, err); + todo_wine ok(!err,"mci %s (with output buffer) returned %s\n", command_close_all, dbg_mcierr(err)); ok(buf[0] == 0, "mci %s changed output buffer: %s\n", command_close_all, buf); /* No notification left, everything closed already */ test_notification(hwnd, command_close_all, 0); @@ -198,9 +234,12 @@ static void test_openCloseWAVE(HWND hwnd) memset(buf, 0, sizeof(buf)); err = mciSendString(command_sysinfo, buf, sizeof(buf), NULL); - ok(!err,"mci %s returned error: %d\n", command_sysinfo, err); + ok(!err,"mci %s returned %s\n", command_sysinfo, dbg_mcierr(err)); todo_wine ok(buf[0] == '0' && buf[1] == 0, "mci %s, expected output buffer '0', got: '%s'\n", command_sysinfo, buf); + err = mciSendString("open new type waveaudio", buf, sizeof(buf), NULL); + ok(err==MCIERR_NEW_REQUIRES_ALIAS,"mci open new without alias returned %s\n", dbg_mcierr(err)); + err = mciSendCommand(MCI_ALL_DEVICE_ID, MCI_CLOSE, MCI_WAIT, 0); /* from MSDN */ ok(!err,"mciSendCommand(MCI_ALL_DEVICE_ID, MCI_CLOSE, MCI_NOTIFY, 0) returned %s\n", dbg_mcierr(err)); @@ -218,45 +257,59 @@ static void test_recordWAVE(HWND hwnd) WORD nch = 1; WORD nbits = 16; DWORD nsamp = 16000, expect; - MCIERROR err; + MCIERROR err, ok_pcm; MCIDEVICEID wDeviceID; MCI_PARMS_UNION parm; char buf[1024]; memset(buf, 0, sizeof(buf)); + test_notification(hwnd, "-prior to recording-", 0); parm.open.lpstrDeviceType = "waveaudio"; parm.open.lpstrElementName = ""; /* "new" at the command level */ parm.open.lpstrAlias = "x"; /* to enable mciSendString */ + parm.open.dwCallback = (DWORD_PTR)hwnd; err = mciSendCommand(0, MCI_OPEN, - MCI_OPEN_ELEMENT | MCI_OPEN_TYPE | MCI_OPEN_ALIAS, + MCI_OPEN_ELEMENT | MCI_OPEN_TYPE | MCI_OPEN_ALIAS | MCI_NOTIFY, (DWORD_PTR)&parm); - ok(!err,"mciCommand open new type waveaudio alias x: %d\n",err); + ok(!err,"mciCommand open new type waveaudio alias x notify: %s\n", dbg_mcierr(err)); wDeviceID = parm.open.wDeviceID; + /* In Wine, both MCI_Open and the individual drivers send notifications. */ + test_notification(hwnd, "open new", MCI_NOTIFY_SUCCESSFUL); + todo_wine test_notification1(hwnd, "open new no #2", 0); + /* Do not query time format as string because result depends on locale! */ parm.status.dwItem = MCI_STATUS_TIME_FORMAT; err = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&parm); - ok(!err,"mciCommand status time format: %d\n",err); + ok(!err,"mciCommand status time format: %s\n", dbg_mcierr(err)); ok(parm.status.dwReturn==MCI_FORMAT_MILLISECONDS,"status time format: %ld\n",parm.status.dwReturn); + /* Info file fails until named in Open or Save. */ + err = mciSendString("info x file", buf, sizeof(buf), NULL); + todo_wine ok(err==MCIERR_NONAPPLICABLE_FUNCTION,"mci info new file returned %s\n", dbg_mcierr(err)); + /* Check the default recording: 8-bits per sample, mono, 11kHz */ err = mciSendString("status x samplespersec", buf, sizeof(buf), NULL); - ok(!err,"mci status samplespersec returned error: %d\n", err); + ok(!err,"mci status samplespersec returned %s\n", dbg_mcierr(err)); if(!err) ok(!strcmp(buf,"11025"), "mci status samplespersec expected 11025, got: %s\n", buf); /* MCI seems to solely support PCM, no need for ACM conversion. */ err = mciSendString("set x format tag 2", NULL, 0, NULL); - ok(err==MCIERR_OUTOFRANGE,"mci set format tag 2 returned error: %d\n", err); + ok(err==MCIERR_OUTOFRANGE,"mci set format tag 2 returned %s\n", dbg_mcierr(err)); /* MCI appears to scan the available devices for support of this format, * returning MCIERR_OUTOFRANGE on machines with no sound. * Don't skip here, record will fail below. */ err = mciSendString("set x format tag pcm", NULL, 0, NULL); - ok(!err || err==MCIERR_OUTOFRANGE,"mci set format tag pcm returned error: %d\n", err); + ok(!err || err==MCIERR_OUTOFRANGE,"mci set format tag pcm returned %s\n", dbg_mcierr(err)); + ok_pcm = err; + + err = mciSendString("set x samplespersec 41000 alignment 4 channels 2", NULL, 0, NULL); + ok(err==ok_pcm,"mci set samples+align+channels returned %s\n", dbg_mcierr(err)); /* Investigate: on w2k, set samplespersec 22050 sets nChannels to 2! * err = mciSendString("set x samplespersec 22050", NULL, 0, NULL); - * ok(!err,"mci set samplespersec returned error: %d\n", err); + * ok(!err,"mci set samplespersec returned %s\n", dbg_mcierr(err)); */ parm.set.wFormatTag = WAVE_FORMAT_PCM; @@ -269,54 +322,79 @@ static void test_recordWAVE(HWND hwnd) MCI_WAVE_SET_SAMPLESPERSEC | MCI_WAVE_SET_CHANNELS | MCI_WAVE_SET_BITSPERSAMPLE | MCI_WAVE_SET_BLOCKALIGN | MCI_WAVE_SET_AVGBYTESPERSEC| MCI_WAVE_SET_FORMATTAG, (DWORD_PTR)&parm); - ok(!err || err==MCIERR_OUTOFRANGE,"mciCommand set wave format returned error: %d\n", err); + ok(err==ok_pcm,"mciCommand set wave format: %s\n", dbg_mcierr(err)); + /* A few ME machines pass all tests except set format tag pcm! */ err = mciSendString("record x to 2000 wait", NULL, 0, hwnd); - ok(!err,"mci record to 2000 returned error: %d\n", err); - if(err==MCIERR_WAVE_INPUTSUNSUITABLE) { - skip("Please install audio driver. Tests will fail\n"); + ok(err || !ok_pcm,"can record yet set wave format pcm returned %s\n", dbg_mcierr(ok_pcm)); + ok(!err || err==(ok_pcm==MCIERR_OUTOFRANGE ? MCIERR_WAVE_INPUTSUNSUITABLE : 0),"mci record to 2000 returned %s\n", dbg_mcierr(err)); + if(err) { + if (err==MCIERR_WAVE_INPUTSUNSUITABLE) + skip("Please install audio driver. Everything is skipped.\n"); + else skip("Cannot record cause %s. Everything is skipped.\n", dbg_mcierr(err)); err = mciSendString("close x", NULL, 0, NULL); - ok(!err,"mci close returned error: %d\n", err); + ok(!err,"mci close returned %s\n", dbg_mcierr(err)); test_notification(hwnd,"record skipped",0); return; } /* Query some wave format parameters depending on the time format. */ err = mciSendString("status x position", buf, sizeof(buf), NULL); - ok(!err,"mci status position returned error: %d\n", err); + ok(!err,"mci status position returned %s\n", dbg_mcierr(err)); if(!err) todo_wine ok(!strcmp(buf,"2000"), "mci status position gave %s, expected 2000, some tests will fail\n", buf); err = mciSendString("set x time format 8", NULL, 0, NULL); /* bytes */ - ok(!err,"mci returned error: %d\n", err); + ok(!err,"mci returned %s\n", dbg_mcierr(err)); parm.status.dwItem = MCI_STATUS_POSITION; err = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&parm); - ok(!err,"mci returned error: %d\n", err); + ok(!err,"mciCommand status position: %s\n", dbg_mcierr(err)); expect = 2 * nsamp * nch * nbits/8; if(!err) todo_wine ok(parm.status.dwReturn==expect,"recorded %lu bytes, expected %u\n",parm.status.dwReturn,expect); parm.set.dwTimeFormat = MCI_FORMAT_SAMPLES; err = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)&parm); - ok(!err,"mci returned error: %d\n", err); + ok(!err,"mciCommand set time format samples: %s\n", dbg_mcierr(err)); parm.status.dwItem = MCI_STATUS_POSITION; err = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&parm); - ok(!err,"mci returned error: %d\n", err); + ok(!err,"mciCommand status position: %s\n", dbg_mcierr(err)); expect = 2 * nsamp; if(!err) todo_wine ok(parm.status.dwReturn==expect,"recorded %lu samples, expected %u\n",parm.status.dwReturn,expect); err = mciSendString("set x time format milliseconds", NULL, 0, NULL); - ok(!err,"mci returned error: %d\n", err); + ok(!err,"mci set time format milliseconds returned %s\n", dbg_mcierr(err)); + + err = mciSendString("save x tempfile1.wav", NULL, 0, NULL); + ok(!err,"mci save returned %s\n", dbg_mcierr(err)); err = mciSendString("save x tempfile.wav", NULL, 0, NULL); - ok(!err,"mci save returned error: %d\n", err); + ok(!err,"mci save returned %s\n", dbg_mcierr(err)); + if(!err) ok_saved = 0; + + /* Save must not rename the original file. */ + if (!DeleteFile("tempfile1.wav")) + todo_wine ok(FALSE, "Save must not rename the original file; DeleteFile returned %d\n", GetLastError()); err = mciSendString("set x channels 2", NULL, 0, NULL); - ok(err==MCIERR_NONAPPLICABLE_FUNCTION,"mci set channels after saving returned error: %d\n", err); + ok(err==MCIERR_NONAPPLICABLE_FUNCTION,"mci set channels after saving returned %s\n", dbg_mcierr(err)); + + parm.seek.dwTo = 600; + err = mciSendCommand(wDeviceID, MCI_SEEK, MCI_TO | MCI_WAIT, (DWORD_PTR)&parm); + ok(!err,"mciCommand seek to 600: %s\n", dbg_mcierr(err)); + + /* Truncate to current position */ + err = mciSendString("delete x", NULL, 0, NULL); + todo_wine ok(!err,"mci delete returned %s\n", dbg_mcierr(err)); + + buf[0]='\0'; + err = mciSendString("status x length", buf, sizeof(buf), NULL); + ok(!err,"mci status length returned %s\n", dbg_mcierr(err)); + todo_wine ok(!strcmp(buf,"600"), "mci status length after delete gave %s, expected 600\n", buf); err = mciSendString("close x", NULL, 0, NULL); - ok(!err,"mci close returned error: %d\n", err); + ok(!err,"mci close returned %s\n", dbg_mcierr(err)); test_notification(hwnd,"record complete",0); } @@ -327,88 +405,113 @@ static void test_playWAVE(HWND hwnd) memset(buf, 0, sizeof(buf)); err = mciSendString("open waveaudio!tempfile.wav alias mysound", NULL, 0, NULL); - ok(!err,"mci open waveaudio!tempfile.wav returned %s\n", dbg_mcierr(err)); + ok(err==ok_saved,"mci open waveaudio!tempfile.wav returned %s\n", dbg_mcierr(err)); if(err) { - skip("Cannot open tempfile.wav for playing #1, skipping\n"); + skip("Cannot open waveaudio!tempfile.wav for playing (%s), skipping\n", dbg_mcierr(err)); return; } err = mciSendString("status mysound length", buf, sizeof(buf), NULL); - ok(!err,"mci status length returned error: %d\n", err); + ok(!err,"mci status length returned %s\n", dbg_mcierr(err)); todo_wine ok(!strcmp(buf,"2000"), "mci status length gave %s, expected 2000, some tests will fail.\n", buf); err = mciSendString("cue output", NULL, 0, NULL); - todo_wine ok(err==MCIERR_UNRECOGNIZED_COMMAND,"mci incorrect cue output returned: %s\n", dbg_mcierr(err)); + todo_wine ok(err==MCIERR_UNRECOGNIZED_COMMAND,"mci incorrect cue output returned %s\n", dbg_mcierr(err)); - err = mciSendString("play mysound from 0 to 0 notify", NULL, 0, hwnd); - ok(!err,"mci play from 0 to 0 returned error: %d\n", err); - todo_wine test_notification1(hwnd,"play from 0 to 0",MCI_NOTIFY_SUCCESSFUL); + /* Test MCI to the bones -- Some todo_wine from Cue and + * from Play from 0 to 0 are not worth fixing. */ + err = mciSendString("cue mysound output notify", NULL, 0, hwnd); + ok(!err,"mci cue output after open file returned %s\n", dbg_mcierr(err)); + /* Notification is delayed as a play thread is started. */ + todo_wine test_notification1(hwnd, "cue immediate", 0); + /* Cue pretends to put the MCI into paused state. */ err = mciSendString("status mysound mode", buf, sizeof(buf), hwnd); - ok(!err,"mci status mode returned error: %d\n", err); - ok(!strcmp(buf,"stopped"), "mci status mode: %s\n", buf); + ok(!err,"mci status mode returned %s\n", dbg_mcierr(err)); + todo_wine ok(!strcmp(buf,"paused"), "mci status mode: %s, expected (pseudo)paused\n", buf); + + /* Strange pause where Pause is rejected, unlike Play; Pause; Pause tested below */ + err = mciSendString("pause mysound", NULL, 0, hwnd); + ok(err==MCIERR_NONAPPLICABLE_FUNCTION,"mci pause after cue returned %s\n", dbg_mcierr(err)); + + /* MCI appears to start the play thread in this border case. + * Guessed that from (flaky) status mode and late notification arrival. */ + err = mciSendString("play mysound from 0 to 0 notify", NULL, 0, hwnd); + ok(!err,"mci play from 0 to 0 returned %s\n", dbg_mcierr(err)); + todo_wine test_notification1(hwnd, "cue aborted by play", MCI_NOTIFY_ABORTED); + /* play's own notification follows below */ err = mciSendString("play mysound from 250 to 0", NULL, 0, NULL); - ok(err==MCIERR_OUTOFRANGE,"mci play from 250 to 0 returned error: %d\n", err); + ok(err==MCIERR_OUTOFRANGE,"mci play from 250 to 0 returned %s\n", dbg_mcierr(err)); - err = mciSendString("play mysound from 250 to 0 notify", NULL, 0, hwnd); - ok(err==MCIERR_OUTOFRANGE,"mci play from 250 to 0 notify returned error: %d\n", err); + Sleep(50); /* Give play from 0 to 0 time to finish. */ + todo_wine test_notification1(hwnd, "play from 0 to 0", MCI_NOTIFY_SUCCESSFUL); + + err = mciSendString("status mysound mode", buf, sizeof(buf), hwnd); + ok(!err,"mci status mode returned %s\n", dbg_mcierr(err)); + ok(!strcmp(buf,"stopped"), "mci status mode: %s after play from 0 to 0\n", buf); + + err = mciSendString("play MYSOUND from 250 to 0 notify", NULL, 0, hwnd); + ok(err==MCIERR_OUTOFRANGE,"mci play from 250 to 0 notify returned %s\n", dbg_mcierr(err)); /* No notification (checked below) sent if error */ - /* A second play caused Wine to hang */ + /* A second play caused Wine<1.1.33 to hang */ err = mciSendString("play mysound from 500 to 1500 wait", NULL, 0, NULL); - ok(!err,"mci play from 500 to 1500 returned error: %d\n", err); + ok(!err,"mci play from 500 to 1500 returned %s\n", dbg_mcierr(err)); memset(buf, 0, sizeof(buf)); err = mciSendString("status mysound position", buf, sizeof(buf), hwnd); - ok(!err,"mci status position returned error: %d\n", err); + ok(!err,"mci status position returned %s\n", dbg_mcierr(err)); if(!err) ok(!strcmp(buf,"1500"), "mci status position: %s\n", buf); /* mci will not play position < current */ err = mciSendString("play mysound to 1000", NULL, 0, NULL); - ok(err==MCIERR_OUTOFRANGE,"mci play to 1000 returned error: %d\n", err); + ok(err==MCIERR_OUTOFRANGE,"mci play to 1000 returned %s\n", dbg_mcierr(err)); /* mci will not play to > end */ - err = mciSendString("play mysound to 3000 notify", NULL, 0, hwnd); - ok(err==MCIERR_OUTOFRANGE,"mci play to 3000 notify returned error: %d\n", err); - /* Again, no notification upon error */ + err = mciSendString("play mysound TO 3000 notify", NULL, 0, hwnd); + ok(err==MCIERR_OUTOFRANGE,"mci play to 3000 notify returned %s\n", dbg_mcierr(err)); err = mciSendString("play mysound to 2000", NULL, 0, NULL); - ok(!err,"mci play to 2000 returned error: %d\n", err); + ok(!err,"mci play to 2000 returned %s\n", dbg_mcierr(err)); /* Rejected while playing */ err = mciSendString("cue mysound output", NULL, 0, NULL); - ok(err==MCIERR_NONAPPLICABLE_FUNCTION,"mci cue output while playing returned error: %d\n", err); + ok(err==MCIERR_NONAPPLICABLE_FUNCTION,"mci cue output while playing returned %s\n", dbg_mcierr(err)); err = mciSendString("play mysound to 3000", NULL, 0, NULL); - ok(err==MCIERR_OUTOFRANGE,"mci play to 3000 returned error: %d\n", err); + ok(err==MCIERR_OUTOFRANGE,"mci play to 3000 returned %s\n", dbg_mcierr(err)); - err = mciSendString("stop mysound wait", NULL, 0, NULL); - ok(!err,"mci stop wait returned error: %d\n", err); - test_notification(hwnd,"play outofrange notify #2",0); + err = mciSendString("stop mysound Wait", NULL, 0, NULL); + ok(!err,"mci stop wait returned %s\n", dbg_mcierr(err)); + test_notification(hwnd, "play/cue/pause/stop", 0); - err = mciSendString("seek mysound to 250 wait notify", NULL, 0, hwnd); - ok(!err,"mci seek to 250 wait notify returned error: %d\n", err); + err = mciSendString("Seek Mysound to 250 wait Notify", NULL, 0, hwnd); + ok(!err,"mci seek to 250 wait notify returned %s\n", dbg_mcierr(err)); test_notification(hwnd,"seek wait notify",MCI_NOTIFY_SUCCESSFUL); memset(buf, 0, sizeof(buf)); err = mciSendString("status mysound position notify", buf, sizeof(buf), hwnd); - ok(!err,"mci status position notify returned error: %d\n", err); + ok(!err,"mci status position notify returned %s\n", dbg_mcierr(err)); if(!err) ok(!strcmp(buf,"250"), "mci status position: %s\n", buf); /* Immediate commands like status also send notifications. */ test_notification(hwnd,"status position",MCI_NOTIFY_SUCCESSFUL); memset(buf, 0, sizeof(buf)); err = mciSendString("status mysound mode", buf, sizeof(buf), hwnd); - ok(!err,"mci status mode returned error: %d\n", err); + ok(!err,"mci status mode returned %s\n", dbg_mcierr(err)); ok(!strcmp(buf,"stopped"), "mci status mode: %s\n", buf); + /* Another play from == to testcase */ err = mciSendString("play mysound to 250 wait notify", NULL, 0, hwnd); - ok(!err,"mci play to 250 returned error: %d\n", err); + ok(!err,"mci play (from 250) to 250 returned %s\n", dbg_mcierr(err)); todo_wine test_notification1(hwnd,"play to 250 wait notify",MCI_NOTIFY_SUCCESSFUL); + err = mciSendString("cue mysound output", NULL, 0, NULL); + ok(!err,"mci cue output after play returned %s\n", dbg_mcierr(err)); + err = mciSendString("close mysound", NULL, 0, NULL); - ok(!err,"mci close returned error: %d\n", err); + ok(!err,"mci close returned %s\n", dbg_mcierr(err)); test_notification(hwnd,"after close",0); } @@ -420,22 +523,23 @@ static void test_asyncWAVE(HWND hwnd) char buf[1024]; memset(buf, 0, sizeof(buf)); - err = mciSendString("open tempfile.wav alias mysound", buf, sizeof(buf), NULL); - ok(!err,"mci open tempfile.wav returned %s\n", dbg_mcierr(err)); + err = mciSendString("open tempfile.wav alias mysound notify", buf, sizeof(buf), hwnd); + ok(err==ok_saved,"mci open tempfile.wav returned %s\n", dbg_mcierr(err)); if(err) { - skip("Cannot open tempfile.wav for playing #2, skipping\n"); + skip("Cannot open tempfile.wav for playing (%s), skipping\n", dbg_mcierr(err)); return; } ok(!strcmp(buf,"1"), "mci open deviceId: %s, expected 1\n", buf); wDeviceID = atoi(buf); ok(wDeviceID,"mci open DeviceID: %d\n", wDeviceID); + test_notification(hwnd,"open alias notify",MCI_NOTIFY_SUCCESSFUL); err = mciSendString("status mysound mode", buf, sizeof(buf), hwnd); - ok(!err,"mci status mode returned error: %d\n", err); + ok(!err,"mci status mode returned %s\n", dbg_mcierr(err)); ok(!strcmp(buf,"stopped"), "mci status mode: %s\n", buf); err = mciSendString("play mysound notify", NULL, 0, hwnd); - ok(!err,"mci play returned error: %d\n", err); + ok(!err,"mci play returned %s\n", dbg_mcierr(err)); /* Give Wine's asynchronous thread time to start up. Furthermore, * it uses 3 buffers per second, so that the positions reported @@ -445,16 +549,16 @@ static void test_asyncWAVE(HWND hwnd) /* Do not query time format as string because result depends on locale! */ parm.status.dwItem = MCI_STATUS_TIME_FORMAT; err = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&parm); - ok(!err,"mciCommand status time format returned error: %d\n",err); + ok(!err,"mciCommand status time format: %s\n", dbg_mcierr(err)); if(!err) ok(parm.status.dwReturn==MCI_FORMAT_MILLISECONDS,"status time format: %ld\n",parm.status.dwReturn); parm.set.dwTimeFormat = MCI_FORMAT_MILLISECONDS; err = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)&parm); - ok(!err,"mciCommand set time format returned error: %d\n",err); + ok(!err,"mciCommand set time format ms: %s\n", dbg_mcierr(err)); buf[0]=0; err = mciSendString("status mysound position", buf, sizeof(buf), hwnd); - ok(!err,"mci status position returned error: %d\n", err); + ok(!err,"mci status position returned %s\n", dbg_mcierr(err)); ok(strcmp(buf,"2000"), "mci status position: %s, expected 2000\n", buf); trace("position after Sleep: %sms\n",buf); p2 = atoi(buf); @@ -463,28 +567,28 @@ static void test_asyncWAVE(HWND hwnd) test_notification(hwnd,"play (nowait)",0); err = mciSendString("pause mysound wait", NULL, 0, hwnd); - ok(!err,"mci pause wait returned error: %s\n", dbg_mcierr(err)); + ok(!err,"mci pause wait returned %s\n", dbg_mcierr(err)); buf[0]=0; err = mciSendString("status mysound mode notify", buf, sizeof(buf), hwnd); - ok(!err,"mci status mode returned error: %d\n", err); + ok(!err,"mci status mode returned %s\n", dbg_mcierr(err)); if(!err) ok(!strcmp(buf,"paused"), "mci status mode: %s\n", buf); test_notification(hwnd,"play",MCI_NOTIFY_SUPERSEDED); test_notification(hwnd,"status",MCI_NOTIFY_SUCCESSFUL); buf[0]=0; err = mciSendString("status mysound position", buf, sizeof(buf), hwnd); - ok(!err,"mci status position returned error: %d\n", err); + ok(!err,"mci status position returned %s\n", dbg_mcierr(err)); trace("position while paused: %sms\n",buf); p1 = atoi(buf); ok(p1>=p2, "position not increasing: %u > %u\n", p2, p1); err = mciSendString("stop mysound wait", NULL, 0, NULL); - ok(!err,"mci stop returned error: %s\n", dbg_mcierr(err)); + ok(!err,"mci stop returned %s\n", dbg_mcierr(err)); buf[0]=0; err = mciSendString("info mysound file notify", buf, sizeof(buf), hwnd); - ok(!err,"mci info file returned error: %d\n", err); + ok(!err,"mci info file returned %s\n", dbg_mcierr(err)); if(!err) { /* fully qualified name */ int len = strlen(buf); todo_wine ok(len>2 && buf[1]==':',"Expected full pathname from info file: %s\n", buf); @@ -494,12 +598,12 @@ static void test_asyncWAVE(HWND hwnd) buf[0]=0; err = mciSendString("status mysound mode", buf, sizeof(buf), hwnd); - ok(!err,"mci status mode returned error: %d\n", err); + ok(!err,"mci status mode returned %s\n", dbg_mcierr(err)); ok(!strcmp(buf,"stopped"), "mci status mode: %s\n", buf); buf[0]=0; err = mciSendString("status mysound position", buf, sizeof(buf), hwnd); - ok(!err,"mci status position returned error: %d\n", err); + ok(!err,"mci status position returned %s\n", dbg_mcierr(err)); trace("position once stopped: %sms\n",buf); p2 = atoi(buf); /* An XP machine let the position increase slightly after pause. */ @@ -507,79 +611,84 @@ static void test_asyncWAVE(HWND hwnd) /* No Resume once stopped (waveaudio, sequencer and cdaudio differ). */ err = mciSendString("resume mysound wait", NULL, 0, NULL); - ok(err==MCIERR_NONAPPLICABLE_FUNCTION,"mci resume wait returned error: %s\n", dbg_mcierr(err)); + ok(err==MCIERR_NONAPPLICABLE_FUNCTION,"mci resume wait returned %s\n", dbg_mcierr(err)); err = mciSendString("play mysound wait", NULL, 0, NULL); - ok(!err,"mci play wait returned error: %d\n", err); + ok(!err,"mci play wait returned %s\n", dbg_mcierr(err)); buf[0]=0; err = mciSendString("status mysound position", buf, sizeof(buf), hwnd); - ok(!err,"mci status position returned error: %d\n", err); + ok(!err,"mci status position returned %s\n", dbg_mcierr(err)); todo_wine ok(!strcmp(buf,"2000"), "mci status position: %s\n", buf); err = mciSendString("seek mysound to start wait", NULL, 0, NULL); - ok(!err,"mci seek to start wait returned error: %d\n", err); + ok(!err,"mci seek to start wait returned %s\n", dbg_mcierr(err)); err = mciSendString("play mysound to 1000 notify", NULL, 0, hwnd); - ok(!err,"mci play returned error: %d\n", err); + ok(!err,"mci play returned %s\n", dbg_mcierr(err)); - Sleep(200); /* Give Wine play thread time to start up, not needed with MS-Windows. */ + /* Sleep(200); not needed with Wine any more. */ err = mciSendString("pause mysound notify", NULL, 0, NULL); /* notify no callback */ - ok(!err,"mci pause notify returned error: %s\n", dbg_mcierr(err)); + ok(!err,"mci pause notify returned %s\n", dbg_mcierr(err)); /* Supersede even though pause cannot notify given no callback */ test_notification(hwnd,"pause aborted play #1 notification",MCI_NOTIFY_SUPERSEDED); test_notification(hwnd,"impossible pause notification",0); err = mciSendString("cue mysound output notify", NULL, 0, hwnd); - ok(err==MCIERR_NONAPPLICABLE_FUNCTION,"mci cue output while paused returned error: %d\n", err); + ok(err==MCIERR_NONAPPLICABLE_FUNCTION,"mci cue output while paused returned %s\n", dbg_mcierr(err)); test_notification(hwnd,"cue output notify #2",0); - /* Seek or even Stop used to hang Wine on MacOS. */ + err = mciSendString("resume mysound notify", NULL, 0, hwnd); + ok(!err,"mci resume notify returned %s\n", dbg_mcierr(err)); + test_notification(hwnd, "resume notify", MCI_NOTIFY_SUCCESSFUL); + + /* Seek or even Stop used to hang Wine<1.1.32 on MacOS. */ err = mciSendString("seek mysound to 0 wait", NULL, 0, NULL); - ok(!err,"mci seek to start returned error: %d\n", err); + ok(!err,"mci seek to start returned %s\n", dbg_mcierr(err)); /* Seek stops. */ err = mciSendString("status mysound mode", buf, sizeof(buf), NULL); - ok(!err,"mci status mode returned error: %d\n", err); + ok(!err,"mci status mode returned %s\n", dbg_mcierr(err)); if(!err) ok(!strcmp(buf,"stopped"), "mci status mode: %s\n", buf); err = mciSendString("seek mysound wait", NULL, 0, NULL); - ok(err==MCIERR_MISSING_PARAMETER,"mci seek to nowhere returned error: %d\n", err); + ok(err==MCIERR_MISSING_PARAMETER,"mci seek to nowhere returned %s\n", dbg_mcierr(err)); /* cdaudio does not detect to start to end as error */ err = mciSendString("seek mysound to start to 0", NULL, 0, NULL); - ok(err==MCIERR_FLAGS_NOT_COMPATIBLE,"mci seek to start to 0 returned error: %d\n", err); + ok(err==MCIERR_FLAGS_NOT_COMPATIBLE,"mci seek to start to 0 returned %s\n", dbg_mcierr(err)); - err = mciSendString("play mysound to 1000 notify", NULL, 0, hwnd); - ok(!err,"mci play returned error: %d\n", err); + err = mciSendString("PLAY mysound to 1000 notify", NULL, 0, hwnd); + ok(!err,"mci play to 1000 notify returned %s\n", dbg_mcierr(err)); - Sleep(200); /* Give Wine more than the 333ms for the first buffer? */ + /* Sleep(200); not needed with Wine any more. */ /* Give it 400ms and resume will appear to complete below. */ err = mciSendString("pause mysound wait", NULL, 0, NULL); - ok(!err,"mci pause wait returned error: %d\n", err); + ok(!err,"mci pause wait returned %s\n", dbg_mcierr(err)); /* Unlike sequencer and cdaudio, waveaudio's pause does not abort. */ test_notification(hwnd,"pause aborted play #2 notification",0); err = mciSendString("resume mysound wait", NULL, 0, NULL); - ok(!err,"mci resume wait returned error: %d\n", err); + ok(!err,"mci resume wait returned %s\n", dbg_mcierr(err)); /* Resume is a short asynchronous call, something else is playing. */ err = mciSendString("status mysound mode", buf, sizeof(buf), NULL); - ok(!err,"mci status mode returned error: %d\n", err); + ok(!err,"mci status mode returned %s\n", dbg_mcierr(err)); if(!err) ok(!strcmp(buf,"playing"), "mci status mode: %s\n", buf); - err = mciSendString("pause mysound wait", NULL, 0, NULL); - ok(!err,"mci pause wait returned error: %d\n", err); + /* Note extra space before alias */ + err = mciSendString("pause mysound wait", NULL, 0, NULL); + todo_wine ok(!err,"mci pause (space) wait returned %s\n", dbg_mcierr(err)); err = mciSendString("pause mysound wait", NULL, 0, NULL); - ok(!err,"mci pause wait returned error: %d\n", err); + ok(!err,"mci pause wait returned %s\n", dbg_mcierr(err)); /* Better ask position only when paused, is it updated while playing? */ buf[0]='\0'; err = mciSendString("status mysound position", buf, sizeof(buf), NULL); - ok(!err,"mci status position returned error: %d\n", err); + ok(!err,"mci status position returned %s\n", dbg_mcierr(err)); /* TODO compare position < 900 */ ok(strcmp(buf,"1000"), "mci resume waited\n"); ok(strcmp(buf,"2000"), "mci resume played to end\n"); @@ -587,7 +696,7 @@ static void test_asyncWAVE(HWND hwnd) test_notification(hwnd,"play (aborted by pause/resume/pause)",0); err = mciSendString("close mysound wait", NULL, 0, NULL); - ok(!err,"mci close wait returned error: %d\n", err); + ok(!err,"mci close wait returned %s\n", dbg_mcierr(err)); test_notification(hwnd,"play (aborted by close)",MCI_NOTIFY_ABORTED); } @@ -596,36 +705,45 @@ static void test_AutoOpenWAVE(HWND hwnd) /* This test used(?) to cause intermittent crashes when Wine exits, after * fixme:winmm:MMDRV_Exit Closing while ll-driver open */ - MCIERROR err; + MCIERROR err, ok_snd; char buf[512], path[300], command[330]; memset(buf, 0, sizeof(buf)); memset(path, 0, sizeof(path)); /* Do not crash on NULL buffer pointer */ err = mciSendString("sysinfo waveaudio quantity open", NULL, 0, NULL); - ok(err==MCIERR_PARAM_OVERFLOW,"mci sysinfo without buffer returned error: %d\n", err); + ok(err==MCIERR_PARAM_OVERFLOW,"mci sysinfo without buffer returned %s\n", dbg_mcierr(err)); err = mciSendString("sysinfo waveaudio quantity open", buf, sizeof(buf), NULL); - ok(!err,"mci sysinfo waveaudio quantity open returned error: %d\n", err); - if(!err) todo_wine ok(!strcmp(buf,"0"), "sysinfo quantity open expected 0, got: %s\n", buf); + ok(!err,"mci sysinfo waveaudio quantity open returned %s\n", dbg_mcierr(err)); + if(!err) todo_wine ok(!strcmp(buf,"0"), "sysinfo quantity open expected 0, got: %s, some more tests will fail.\n", buf); + + ok_snd = waveOutGetNumDevs() ? 0 : MCIERR_HARDWARE; + err = mciSendString("sound NoSuchSoundDefined wait", NULL, 0, NULL); + todo_wine ok(err==ok_snd,"mci sound NoSuchSoundDefined returned %s\n", dbg_mcierr(err)); + + err = mciSendString("sound SystemExclamation notify wait", NULL, 0, hwnd); + todo_wine ok(err==ok_snd,"mci sound SystemExclamation returned %s\n", dbg_mcierr(err)); + test_notification(hwnd, "sound notify", err ? 0 : MCI_NOTIFY_SUCCESSFUL); buf[0]=0; err = mciSendString("sysinfo waveaudio name 1 open", buf, sizeof(buf), NULL); - todo_wine ok(err==MCIERR_OUTOFRANGE,"sysinfo waveaudio name 1 returned error: %d\n", err); + todo_wine ok(err==MCIERR_OUTOFRANGE,"sysinfo waveaudio name 1 returned %s\n", dbg_mcierr(err)); if(!err) trace("sysinfo dangling open alias: %s\n", buf); err = mciSendString("play no-such-file-exists.wav notify", buf, sizeof(buf), NULL); - if(err==MCIERR_FILE_NOT_FOUND) { + if(err==MCIERR_FILE_NOT_FOUND) { /* a Wine detector */ /* Unsupported auto-open leaves the file open, preventing clean-up */ skip("Skipping auto-open tests in Wine\n"); return; } err = mciSendString("play tempfile.wav notify", buf, sizeof(buf), hwnd); - todo_wine ok(err==MCIERR_NOTIFY_ON_AUTO_OPEN,"mci auto-open play notify returned error: %d\n", err); + todo_wine ok(err==MCIERR_NOTIFY_ON_AUTO_OPEN,"mci auto-open play notify returned %s\n", dbg_mcierr(err)); if(err) /* FIXME: don't open twice yet, it confuses Wine. */ err = mciSendString("play tempfile.wav", buf, sizeof(buf), hwnd); - ok(!err,"mci auto-open play returned error: %d\n", err); + ok(err==ok_saved,"mci auto-open play returned %s\n", dbg_mcierr(err)); + if(err==MCIERR_FILE_NOT_FOUND) { skip("Cannot open tempfile.wav for auto-play, skipping\n"); return; @@ -633,34 +751,34 @@ static void test_AutoOpenWAVE(HWND hwnd) buf[0]=0; err = mciSendString("sysinfo waveaudio quantity open", buf, sizeof(buf), NULL); - ok(!err,"mci sysinfo waveaudio quantity after auto-open returned error: %d\n", err); + ok(!err,"mci sysinfo waveaudio quantity after auto-open returned %s\n", dbg_mcierr(err)); if(!err) todo_wine ok(!strcmp(buf,"1"), "sysinfo quantity open expected 1, got: %s\n", buf); buf[0]=0; err = mciSendString("sysinfo waveaudio name 1 open", buf, sizeof(buf), NULL); - todo_wine ok(!err,"mci sysinfo waveaudio name after auto-open returned error: %d\n", err); + todo_wine ok(!err,"mci sysinfo waveaudio name after auto-open returned %s\n", dbg_mcierr(err)); /* This is the alias, not necessarily a file name. */ - if(!err) ok(!strcmp(buf,"tempfile.wav"), "sysinfo name 1 open returned: %s\n", buf); + if(!err) ok(!strcmp(buf,"tempfile.wav"), "sysinfo name 1 open: %s\n", buf); /* Save the full pathname to the file. */ err = mciSendString("info tempfile.wav file", path, sizeof(path), NULL); - ok(!err,"mci info tempfile.wav file returned error: %d\n", err); + ok(!err,"mci info tempfile.wav file returned %s\n", dbg_mcierr(err)); if(err) strcpy(path,"tempfile.wav"); err = mciSendString("status tempfile.wav mode", NULL, 0, hwnd); - ok(!err,"mci status tempfile.wav mode without buffer returned error: %d\n", err); + ok(!err,"mci status tempfile.wav mode without buffer returned %s\n", dbg_mcierr(err)); sprintf(command,"status \"%s\" mode",path); err = mciSendString(command, buf, sizeof(buf), hwnd); - ok(!err,"mci status full-path-to-tempfile.wav mode returned error: %d\n", err); + ok(!err,"mci status \"%s\" mode returned %s\n", path, dbg_mcierr(err)); buf[0]=0; err = mciSendString("status tempfile.wav mode", buf, sizeof(buf), hwnd); - ok(!err,"mci status tempfile.wav mode returned error: %d\n", err); + ok(!err,"mci status tempfile.wav mode returned %s\n", dbg_mcierr(err)); if(!err) ok(!strcmp(buf,"playing"), "mci auto-open status mode, got: %s\n", buf); err = mciSendString("open tempfile.wav", buf, sizeof(buf), NULL); - todo_wine ok(err==MCIERR_DEVICE_OPEN, "mci open from auto-open returned error: %s\n", dbg_mcierr(err)); + todo_wine ok(err==MCIERR_DEVICE_OPEN, "mci open from auto-open returned %s\n", dbg_mcierr(err)); /* w2k/xp and Wine differ. While the device is busy playing, it is * regularly open and accessible via the filename: subsequent @@ -674,10 +792,11 @@ static void test_AutoOpenWAVE(HWND hwnd) * command. */ err = mciSendString("status tempfile.wav mode notify", buf, sizeof(buf), hwnd); - trace("mci auto-open status notify return value: %d\n",err); - todo_wine ok(err==MCIERR_NOTIFY_ON_AUTO_OPEN, "mci auto-open status notify: %s\n", dbg_mcierr(err)); - if(!err) { /* Wine style */ - trace("New style MCI auto-close upon notification behaviour.\n"); + todo_wine ok(err==MCIERR_NOTIFY_ON_AUTO_OPEN, "mci status auto-open notify returned %s\n", dbg_mcierr(err)); + if(!err) { + trace("Wine style MCI auto-close upon notification\n"); + + /* "playing" because auto-close comes after the status call. */ todo_wine ok(!strcmp(buf,"playing"), "mci auto-open status mode notify, got: %s\n", buf); /* fixme:winmm:MMDRV_Exit Closing while ll-driver open * is explained by failure to auto-close a device. */ @@ -686,23 +805,23 @@ static void test_AutoOpenWAVE(HWND hwnd) Sleep(16); test_notification(hwnd,"auto-open",0); } else if(err==MCIERR_NOTIFY_ON_AUTO_OPEN) { /* MS style */ - trace("Old style MCI auto-open forbids notification behaviour.\n"); + trace("MS style MCI auto-open forbids notification\n"); err = mciSendString("pause tempfile.wav", NULL, 0, hwnd); - ok(!err,"mci auto-still-open pause returned error: %d\n", err); + ok(!err,"mci auto-still-open pause returned %s\n", dbg_mcierr(err)); err = mciSendString("status tempfile.wav mode", buf, sizeof(buf), hwnd); - ok(!err,"mci status mode returned error: %d\n", err); + ok(!err,"mci status mode returned %s\n", dbg_mcierr(err)); if(!err) ok(!strcmp(buf,"paused"), "mci auto-open status mode, got: %s\n", buf); /* Auto-close */ err = mciSendString("stop tempfile.wav", NULL, 0, hwnd); - ok(!err,"mci auto-still-open stop returned error: %d\n", err); + ok(!err,"mci auto-still-open stop returned %s\n", dbg_mcierr(err)); Sleep(16); /* makes sysinfo quantity open below succeed */ } err = mciSendString("sysinfo waveaudio quantity open", buf, sizeof(buf), NULL); - ok(!err,"mci sysinfo waveaudio quantity open after close returned error: %d\n", err); + ok(!err,"mci sysinfo waveaudio quantity open after close returned %s\n", dbg_mcierr(err)); if(!err) todo_wine ok(!strcmp(buf,"0"), "sysinfo quantity open expected 0 after auto-close, got: %s\n", buf); /* w95-WinME (not w2k/XP) switch to C:\ after auto-playing once. Prevent @@ -710,17 +829,17 @@ static void test_AutoOpenWAVE(HWND hwnd) */ sprintf(command,"status \"%s\" mode wait",path); err = mciSendString(command, buf, sizeof(buf), hwnd); - ok(!err,"mci re-auto-open status mode returned error: %d\n", err); + ok(!err,"mci re-auto-open status mode returned %s\n", dbg_mcierr(err)); if(!err) ok(!strcmp(buf,"stopped"), "mci re-auto-open status mode, got: %s\n", buf); err = mciSendString("capability waveaudio device type", buf, sizeof(buf), hwnd); - ok(!err,"mci capability device type returned error: %d\n", err); + ok(!err,"mci capability device type returned %s\n", dbg_mcierr(err)); if(!err) ok(!strcmp(buf,"waveaudio"), "mci capability device type response: %s\n", buf); /* waveaudio forbids Pause without Play. */ sprintf(command,"pause \"%s\"",path); err = mciSendString(command, NULL, 0, hwnd); - ok(err==MCIERR_NONAPPLICABLE_FUNCTION,"mci auto-open pause returned error: %d\n", err); + ok(err==MCIERR_NONAPPLICABLE_FUNCTION,"mci auto-open pause returned %s\n", dbg_mcierr(err)); } START_TEST(mci) @@ -737,6 +856,6 @@ START_TEST(mci) /* Win9X hangs when exiting with something still open. */ err = mciSendString("close all", NULL, 0, hwnd); todo_wine ok(!err,"final close all returned %s\n", dbg_mcierr(err)); - ok(DeleteFile("tempfile.wav"),"Delete tempfile.wav (cause auto-open?)\n"); + ok(DeleteFile("tempfile.wav")||ok_saved,"Delete tempfile.wav (cause auto-open?)\n"); DestroyWindow(hwnd); } diff --git a/dlls/winspool.drv/info.c b/dlls/winspool.drv/info.c index 7dac2b66501..6d623d63569 100644 --- a/dlls/winspool.drv/info.c +++ b/dlls/winspool.drv/info.c @@ -3766,8 +3766,6 @@ static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName, dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */ if (!dwType) { FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n"); - *lpdwNeeded = 0; - *lpdwReturned = 0; return TRUE; } diff --git a/dlls/winspool.drv/tests/info.c b/dlls/winspool.drv/tests/info.c index c6c00662eca..2fb09f3ad92 100644 --- a/dlls/winspool.drv/tests/info.c +++ b/dlls/winspool.drv/tests/info.c @@ -70,6 +70,7 @@ static BOOL (WINAPI * pGetDefaultPrinterA)(LPSTR, LPDWORD); static BOOL (WINAPI * pSetDefaultPrinterA)(LPCSTR); static DWORD (WINAPI * pXcvDataW)(HANDLE, LPCWSTR, PBYTE, DWORD, PBYTE, DWORD, PDWORD, PDWORD); static BOOL (WINAPI * pAddPortExA)(LPSTR, DWORD, LPBYTE, LPSTR); +static BOOL (WINAPI * pGetPrinterDriverW)(HANDLE, LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD); /* ################################ */ @@ -2260,6 +2261,15 @@ static void test_GetPrinterDriver(void) continue; } + /* GetPrinterDriverA returns the same number of bytes as GetPrinterDriverW */ + if (! ret && pGetPrinterDriverW) + { + DWORD double_needed; + ret = pGetPrinterDriverW(hprn, NULL, level, NULL, 0, &double_needed); + todo_wine + ok(double_needed == needed, "GetPrinterDriverA returned different size %d than GetPrinterDriverW (%d)\n", needed, double_needed); + } + buf = HeapAlloc(GetProcessHeap(), 0, needed); SetLastError(0xdeadbeef); @@ -2536,6 +2546,7 @@ START_TEST(info) hwinspool = GetModuleHandleA("winspool.drv"); pGetDefaultPrinterA = (void *) GetProcAddress(hwinspool, "GetDefaultPrinterA"); pSetDefaultPrinterA = (void *) GetProcAddress(hwinspool, "SetDefaultPrinterA"); + pGetPrinterDriverW = (void *) GetProcAddress(hwinspool, "GetPrinterDriverW"); pXcvDataW = (void *) GetProcAddress(hwinspool, "XcvDataW"); pAddPortExA = (void *) GetProcAddress(hwinspool, "AddPortExA"); diff --git a/include/Makefile.in b/include/Makefile.in index f2cd3be7f76..0bc1864cd64 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -14,6 +14,8 @@ PUBLIC_IDL_H_SRCS = \ activscp.idl \ amstream.idl \ amvideo.idl \ + audioclient.idl \ + audiopolicy.idl \ austream.idl \ bits.idl \ bits1_5.idl \ @@ -23,6 +25,7 @@ PUBLIC_IDL_H_SRCS = \ ctxtcall.idl \ d3d10.idl \ ddstream.idl \ + devicetopology.idl \ dimm.idl \ dispex.idl \ docobj.idl \ diff --git a/include/audioclient.idl b/include/audioclient.idl new file mode 100644 index 00000000000..cb1880b466e --- /dev/null +++ b/include/audioclient.idl @@ -0,0 +1,326 @@ +/* + * Core Audio audioclient definitions + * + * Copyright 2009 Maarten Lankhorst + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should 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 + * + */ + +cpp_quote("#ifndef __audioclient_h__") +cpp_quote("#define __audioclient_h__") + +import "wtypes.idl"; +import "unknwn.idl"; +import "audiosessiontypes.h"; + +/* Forward declarations */ +interface IAudioClient; +interface IAudioRenderClient; +interface IAudioCaptureClient; +interface IAudioClock; +interface IAudioClock2; +interface IAudioClockAdjustment; +interface ISimpleAudioVolume; +interface IAudioStreamVolume; +interface IChannelAudioVolume; + +cpp_quote("#if 0") +typedef struct WAVEFORMATEX /*[hidden,restricted]*/ +{ + WORD wFormatTag; + WORD nChannels; + DWORD nSamplesPerSec; + DWORD nAvgBytesPerSec; + WORD nBlockAlign; + WORD wBitsPerSample; + WORD cbSize; +} WAVEFORMATEX; +cpp_quote("#else") +cpp_quote("#include ") +cpp_quote("#endif") + +cpp_quote("#if 0") +typedef LONGLONG /*[hidden,restricted]*/ REFERENCE_TIME; +cpp_quote("#else") +cpp_quote("#define _IKsControl_") +cpp_quote("#include ") +cpp_quote("#include ") +cpp_quote("#endif") + +enum _AUDCLNT_BUFFERFLAGS +{ + AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY = 0x1, + AUDCLNT_BUFFERFLAGS_SILENT = 0x2, + AUDCLNT_BUFFERFLAGS_TIMESTAMP_ERROR = 0x4 +}; + +[ + local, + pointer_default(unique), + uuid(1cb9ad4c-dbfa-4c32-b178-c2f568a703b2), + object, +] +interface IAudioClient : IUnknown +{ + HRESULT Initialize( + [in] AUDCLNT_SHAREMODE ShareMode, + [in] DWORD StreamFlags, + [in] REFERENCE_TIME hnsBufferDuration, + [in] REFERENCE_TIME hnsPeriodicity, + [in] const WAVEFORMATEX *pFormat, + [in] LPCGUID AudioSessionGuid + ); + HRESULT GetBufferSize( + [out] UINT32 *pNumBufferFrames + ); + HRESULT GetStreamLatency( + [out] REFERENCE_TIME *phnsLatency + ); + HRESULT GetCurrentPadding( + [out] UINT32 *pNumPaddingFrames + ); + HRESULT IsFormatSupported( + [in] AUDCLNT_SHAREMODE ShareMode, + [in] const WAVEFORMATEX *pFormat, + [out,unique] WAVEFORMATEX **ppClosestMatch + ); + HRESULT GetMixFormat( + [out] WAVEFORMATEX **ppDeviceFormat + ); + HRESULT GetDevicePeriod( + [out] REFERENCE_TIME *phnsDefaultDevicePeriod, + [out] REFERENCE_TIME *phnsMinimumDevicePeriod + ); + HRESULT Start(void); + HRESULT Stop(void); + HRESULT Reset(void); + HRESULT SetEventHandle([in] HANDLE eventHandle); + HRESULT GetService( + [in] REFIID riid, + [iid_is(riid),out] void **ppv + ); +} + +[ + local, + pointer_default(unique), + uuid(f294acfc-3146-4483-a7bf-addca7c260e2), + object, +] +interface IAudioRenderClient : IUnknown +{ + HRESULT GetBuffer( + [in] UINT32 NumFramesRequested, + [out] BYTE **ppData + ); + HRESULT ReleaseBuffer( + [in] UINT32 NumFramesWritten, + [in] DWORD dwFlags + ); +} + +[ + local, + pointer_default(unique), + uuid(c8adbd64-e71e-48a0-a4de-185c395cd317), + object, +] +interface IAudioCaptureClient : IUnknown +{ + HRESULT GetBuffer( + [out] BYTE **ppData, + [out] UINT32 *pNumFramesToRead, + [out] DWORD *pdwFlags, + [unique,out] UINT64 *pu64DevicePosition, + [unique,out] UINT64 *pu64QPCPosition + ); + HRESULT ReleaseBuffer( + [in] UINT32 NumFramesRead + ); + HRESULT GetNextPacketSize( + [out] UINT32 *pNumFramesInNextPacket + ); +} + +cpp_quote("#define AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ 0x00000001") + +[ + local, + pointer_default(unique), + uuid("cd63314f-3fba-4a1b-812c-ef96358728e7"), + object, +] +interface IAudioClock : IUnknown +{ + HRESULT GetFrequency( + [out] UINT64 *pu64Frequency + ); + HRESULT GetPosition( + [out] UINT64 *pu64Position, + [out,unique] UINT64 *pu64QPCPosition + ); + HRESULT GetCharacteristics( + [out] DWORD *pdwCharacteristics + ); +} + +[ + local, + pointer_default(unique), + uuid("6f49ff73-6727-49ac-a008-d98cf5e70048"), + object, +] +interface IAudioClock2 : IUnknown +{ + HRESULT GetPosition( + [out] UINT64 *DevicePosition, + [out,unique] UINT64 *QPCPosition + ); +} + +[ + local, + pointer_default(unique), + uuid("f6e4c0a0-46d9-4fb9-be21-57a3ef2b626c"), + object, +] +interface IAudioClockAdjustment : IUnknown +{ + HRESULT SetSampleRate( + [in] float flSampleRate + ); +} + +[ + local, + pointer_default(unique), + uuid("87ce5498-68d6-44e5-9215-6da47ef883d8"), + object, +] +interface ISimpleAudioVolume : IUnknown +{ + HRESULT SetMasterVolume( + [in] float fLevel, + [unique,in] LPCGUID EventContext + ); + HRESULT GetMasterVolume( + [out] float *pfLevel + ); + HRESULT SetMute( + [in] const BOOL bMute, + [unique,in] LPCGUID EventContext + ); + HRESULT GetMute( + [out] BOOL *pbMute + ); +} + +[ + local, + pointer_default(unique), + uuid("93014887-242d-4068-8a15-cf5e93b90fe3"), + object, +] +interface IAudioStreamVolume : IUnknown +{ + HRESULT GetChannelCount( + [out] UINT32 *pdwCount + ); + HRESULT SetChannelVolume( + [in] UINT32 dwIndex, + [in] const float fLevel + ); + HRESULT GetChannelVolume( + [in] UINT32 dwIndex, + [out] float *pfLevel + ); + HRESULT SetAllVolumes( + [in] UINT32 dwCount, + [size_is(dwCount),in] const float *pfVolumes + ); + HRESULT GetAllVolumes( + [in] UINT32 dwCount, + [size_is(dwCount),out] float *pfVolumes + ); +} + +[ + local, + pointer_default(unique), + uuid("1c158861-b533-4b30-b1cf-e853e51c59b8"), + object, +] +interface IChannelAudioVolume : IUnknown +{ + HRESULT GetChannelCount( + [out] UINT32 *pdwCount + ); + HRESULT SetChannelVolume( + [in] UINT32 dwIndex, + [in] const float fLevel, + [unique,in] LPCGUID EventContext + ); + HRESULT GetChannelVolume( + [in] UINT32 dwIndex, + [out] float *pfLevel + ); + HRESULT SetAllVolumes( + [in] UINT32 dwCount, + [size_is(dwCount),in] const float *pfVolumes, + [unique,in] LPCGUID EventContext + ); + HRESULT GetAllVolumes( + [in] UINT32 dwCount, + [size_is(dwCount),out] float *pfVolumes + ); +} + +cpp_quote("#define FACILIY_AUDCLNT 0x889") +cpp_quote("#define AUDCLNT_ERR(n) MAKE_HRESULT(SEVERITY_ERROR, FACILIY_AUDCLNT, n)") +cpp_quote("#define AUDCLNT_SUCCESS(n) MAKE_SCODE(SEVERITY_SUCCESS, FACILIY_AUDCLNT, n)") +cpp_quote("#define AUDCLNT_E_NOT_INITIALIZED AUDCLNT_ERR(1)") +cpp_quote("#define AUDCLNT_E_ALREADY_INITIALIZED AUDCLNT_ERR(2)") +cpp_quote("#define AUDCLNT_E_WRONG_ENDPOINT_TYPE AUDCLNT_ERR(3)") +cpp_quote("#define AUDCLNT_E_DEVICE_INVALIDATED AUDCLNT_ERR(4)") +cpp_quote("#define AUDCLNT_E_NOT_STOPPED AUDCLNT_ERR(5)") +cpp_quote("#define AUDCLNT_E_BUFFER_TOO_LARGE AUDCLNT_ERR(6)") +cpp_quote("#define AUDCLNT_E_OUT_OF_ORDER AUDCLNT_ERR(7)") +cpp_quote("#define AUDCLNT_E_UNSUPPORTED_FORMAT AUDCLNT_ERR(8)") +cpp_quote("#define AUDCLNT_E_INVALID_SIZE AUDCLNT_ERR(9)") +cpp_quote("#define AUDCLNT_E_DEVICE_IN_USE AUDCLNT_ERR(0x0a)") +cpp_quote("#define AUDCLNT_E_BUFFER_OPERATION_PENDING AUDCLNT_ERR(0x0b)") +cpp_quote("#define AUDCLNT_E_THREAD_NOT_REGISTERED AUDCLNT_ERR(0x0c)") +/* Not defined? cpp_quote("#define AUDCLNT_E_UNKNOWN_XXX1 AUDCLNT_ERR(0x0d)") */ +cpp_quote("#define AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED AUDCLNT_ERR(0x0e)") +cpp_quote("#define AUDCLNT_E_ENDPOINT_CREATE_FAILED AUDCLNT_ERR(0x0f)") +cpp_quote("#define AUDCLNT_E_SERVICE_NOT_RUNNING AUDCLNT_ERR(0x10)") +cpp_quote("#define AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED AUDCLNT_ERR(0x11)") +cpp_quote("#define AUDCLNT_E_EXCLUSIVE_MODE_ONLY AUDCLNT_ERR(0x12)") +cpp_quote("#define AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL AUDCLNT_ERR(0x13)") +cpp_quote("#define AUDCLNT_E_EVENTHANDLE_NOT_SET AUDCLNT_ERR(0x14)") +cpp_quote("#define AUDCLNT_E_INCORRECT_BUFFER_SIZE AUDCLNT_ERR(0x15)") +cpp_quote("#define AUDCLNT_E_BUFFER_SIZE_ERROR AUDCLNT_ERR(0x16)") +cpp_quote("#define AUDCLNT_E_CPUUSAGE_EXCEEDED AUDCLNT_ERR(0x17)") +cpp_quote("#define AUDCLNT_E_BUFFER_ERROR AUDCLNT_ERR(0x18)") +cpp_quote("#define AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED AUDCLNT_ERR(0x19)") +/* Hex fail */ +cpp_quote("#define AUDCLNT_E_INVALID_DEVICE_PERIOD AUDCLNT_ERR(0x20)") + +cpp_quote("#define AUDCLNT_S_BUFFER_EMPTY AUDCLNT_SUCCESS(0x1)") +cpp_quote("#define AUDCLNT_S_THREAD_ALREADY_REGISTERED AUDCLNT_SUCCESS(0x2)") +cpp_quote("#define AUDCLNT_S_POSITION_STALLED AUDCLNT_SUCCESS(0x3)") + +cpp_quote("#endif /*__audioclient_h__*/") diff --git a/include/audiopolicy.idl b/include/audiopolicy.idl new file mode 100644 index 00000000000..2344f91e85a --- /dev/null +++ b/include/audiopolicy.idl @@ -0,0 +1,245 @@ +/* + * Core Audio audio policy definitions + * + * Copyright 2009 Maarten Lankhorst + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should 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 + * + */ + +cpp_quote("#ifndef __audiopolicy_h__") +cpp_quote("#define __audiopolicy_h__") + +import "oaidl.idl"; +import "ocidl.idl"; +import "propidl.idl"; +import "audiosessiontypes.h"; +import "audioclient.idl"; + +interface IAudioSessionEvents; +interface IAudioSessionControl; +interface IAudioSessionControl2; +interface IAudioSessionManager; +interface IAudioVolumeDuckNotification; +interface IAudioSessionNotification; +interface IAudioSessionEnumerator; +interface IAudioSessionManager2; + +typedef enum AudioSessionDisconnectReason /*[local]*/ +{ + DisconnectReasonDeviceRemoval = 0, + DisconnectReasonServerShutdown, + DisconnectReasonFormatChanged, + DisconnectReasonSessionLogoff, + DisconnectReasonSessionDisconnected, + DisconnectReasonExclusiveModeOverride, +} AudioSessionDisconnectReason; + +[ + local, + uuid(24918acc-64b3-37c1-8ca9-74a66e9957a8), + pointer_default(unique), + object +] +interface IAudioSessionEvents : IUnknown +{ + HRESULT OnDisplayNameChanged( + [string,in] LPCWSTR NewDisplayName, + [in] LPCGUID EventContext + ); + HRESULT OnIconPathChanged( + [string,in] LPCWSTR NewIconPath, + [in] LPCGUID EventContext + ); + HRESULT OnSimpleVolumeChanged( + [in] float NewVolume, + [in] BOOL NewMute, + [in] LPCGUID EventContext + ); + HRESULT OnChannelVolumeChanged( + [in] DWORD ChannelCount, + [size_is(ChannelCount),in] float *NewChannelVolumeArray, + [in] DWORD ChangedChannel, + [in] LPCGUID EventContext + ); + HRESULT OnGroupingParamChanged( + [in] LPCGUID NewGroupingParam, + [in] LPCGUID EventContext + ); + HRESULT OnStateChanged( + [in] AudioSessionState NewState + ); + HRESULT OnSessionDisconnected( + [in] AudioSessionDisconnectReason DisconnectReason + ); +} + +[ + local, + uuid(f4b1a599-7266-4319-a8ca-e70acb11e8cd), + pointer_default(unique), + object +] +interface IAudioSessionControl : IUnknown +{ + HRESULT GetState( + [out] AudioSessionState *pRetVal + ); + HRESULT GetDisplayName( + [string,out] LPWSTR *pRetVal + ); + HRESULT SetDisplayName( + [string,in] LPCWSTR DisplayName, + [unique,in] LPCGUID EventContext + ); + HRESULT GetIconPath( + [string,out] LPWSTR *pRetVal + ); + HRESULT SetIconPath( + [string,in] LPCWSTR Value, + [unique,in] LPCGUID EventContext + ); + HRESULT GetGroupingParam( + [out] GUID *pRetVal + ); + HRESULT SetGroupingParam( + [in] GUID *Override, + [unique,in] LPCGUID EventContext + ); + HRESULT RegisterAudioSessionNotification( + [in] IAudioSessionEvents *NewNotifications + ); + HRESULT UnregisterAudioSessionNotification( + [in] IAudioSessionEvents *NewNotifications + ); +} + +[ + local, + uuid(bfb7ff88-7239-4fc9-8fa2-07c950be9c6d), + pointer_default(unique), + object +] +interface IAudioSessionControl2 : IAudioSessionControl +{ + HRESULT GetSessionIdentifier( + [string,out] LPWSTR *pRetVal + ); + HRESULT GetSessionInstanceIdentifier( + [string,out] LPWSTR *pRetVal + ); + HRESULT GetProcessId( + [out] DWORD *pRetVal + ); + HRESULT IsSystemSoundsSession(void); + HRESULT SetDuckingPreferences( + [in] BOOL optOut + ); +}; + +[ + local, + uuid(bfa971f1-4d5e-40bb-935e-967039bfbee4), + pointer_default(unique), + object +] +interface IAudioSessionManager : IUnknown +{ + HRESULT GetAudioSessionControl( + [in] LPCGUID AudioSessionGuid, + [in] DWORD StreamFlags, + [out] IAudioSessionControl **SessionControl + ); + HRESULT GetSimpleAudioVolume( + [in] LPCGUID AudioSessionGuid, + [in] DWORD StreamFlags, + [out] ISimpleAudioVolume **AudioVolume + ); +}; + +[ + local, + uuid(c3b284d4-6d39-4359-b3cf-b56ddb3bb39c), + pointer_default(unique), + object +] +interface IAudioVolumeDuckNotification : IUnknown +{ + HRESULT OnVolumeDuckNotification( + [in] LPCWSTR sessionID, + [in] UINT32 countCommunicationSessions + ); + HRESULT OnVolumeUndockNotification( + [in] LPCWSTR sessionID + ); +}; + +[ + local, + uuid(641dd20b-4d41-49cc-aba3-174b9477bb08), + pointer_default(unique), + object +] +interface IAudioSessionNotification : IUnknown +{ + HRESULT OnSessionCreated( + [in] IAudioSessionControl *NewSession + ); +}; + +[ + local, + uuid(e2f5bb11-0570-40ca-acdd-3aa01277dee8), + pointer_default(unique), + object +] +interface IAudioSessionEnumerator : IUnknown +{ + HRESULT GetCount( + [out] INT *SessionCount + ); + HRESULT GetSession( + [in] INT SessionCount, + [out] IAudioSessionControl **Session + ); +}; + +[ + local, + uuid(77aa99a0-1bd6-484f-8bc7-2c654c9a9b6f), + pointer_default(unique), + object +] +interface IAudiosessionManager2 : IAudioSessionManager +{ + HRESULT GetSessionEnumerator( + [retval,out] IAudioSessionEnumerator **SessionEnum + ); + HRESULT RegisterSessionNotification( + [in] IAudioSessionNotification *SessionNotification + ); + HRESULT UnregisterSessionNotification( + [in] IAudioSessionNotification *SessionNotification + ); + HRESULT RegisterDuckNotification( + [string,in] LPCWSTR sessionID, + [in] IAudioVolumeDuckNotification *duckNotification + ); + HRESULT UnregisterDuckNotification( + [in] IAudioVolumeDuckNotification *duckNotification + ); +}; + +cpp_quote("#endif /*__audiopolicy_h__*/") diff --git a/include/commctrl.h b/include/commctrl.h index 23a296b30c0..b88d694826d 100644 --- a/include/commctrl.h +++ b/include/commctrl.h @@ -3015,6 +3015,7 @@ static const WCHAR WC_LISTVIEWW[] = { 'S','y','s', #define LVSIL_NORMAL 0 #define LVSIL_SMALL 1 #define LVSIL_STATE 2 +#define LVSIL_GROUPHEADER 3 /* following 2 flags only for LVS_OWNERDATA listviews */ /* and only in report or list mode */ @@ -3022,11 +3023,12 @@ static const WCHAR WC_LISTVIEWW[] = { 'S','y','s', #define LVSICF_NOSCROLL 0x0002 -#define LVFI_PARAM 0X0001 -#define LVFI_STRING 0X0002 -#define LVFI_PARTIAL 0X0008 -#define LVFI_WRAP 0X0020 -#define LVFI_NEARESTXY 0X0040 +#define LVFI_PARAM 0x0001 +#define LVFI_STRING 0x0002 +#define LVFI_SUBSTRING 0x0004 +#define LVFI_PARTIAL 0x0008 +#define LVFI_WRAP 0x0020 +#define LVFI_NEARESTXY 0x0040 #define LVIF_TEXT 0x0001 #define LVIF_IMAGE 0x0002 diff --git a/include/config.h.in b/include/config.h.in index 16b2e90bc70..7a77d1f85be 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -591,6 +591,12 @@ /* Define to 1 if you have the `popen' function. */ #undef HAVE_POPEN +/* Define to 1 if you have the `port_create' function. */ +#undef HAVE_PORT_CREATE + +/* Define to 1 if you have the header file. */ +#undef HAVE_PORT_H + /* Define if we can use ppdev.h for parallel port access */ #undef HAVE_PPDEV diff --git a/include/dbghelp.h b/include/dbghelp.h index 98695b23634..34805f4e78a 100644 --- a/include/dbghelp.h +++ b/include/dbghelp.h @@ -1461,6 +1461,7 @@ BOOL WINAPI SymGetSymPrevW(HANDLE, PIMAGEHLP_SYMBOLW); DWORD WINAPI SymLoadModule(HANDLE, HANDLE, PCSTR, PCSTR, DWORD, DWORD); BOOL WINAPI SymRegisterCallback(HANDLE, PSYMBOL_REGISTERED_CALLBACK, PVOID); BOOL WINAPI SymRegisterFunctionEntryCallback(HANDLE, PSYMBOL_FUNCENTRY_CALLBACK, PVOID); +BOOL WINAPI SymRefreshModuleList(HANDLE); BOOL WINAPI SymUnDName(PIMAGEHLP_SYMBOL, PSTR, DWORD); BOOL WINAPI SymUnloadModule(HANDLE, DWORD); diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h index ccdeca3f9a3..df0ad5dd488 100644 --- a/include/ddk/wdm.h +++ b/include/ddk/wdm.h @@ -1059,7 +1059,9 @@ void WINAPI KeQuerySystemTime(LARGE_INTEGER*); void WINAPI KeQueryTickCount(LARGE_INTEGER*); ULONG WINAPI KeQueryTimeIncrement(void); +PVOID WINAPI MmAllocateContiguousMemory(SIZE_T,PHYSICAL_ADDRESS); PVOID WINAPI MmAllocateNonCachedMemory(SIZE_T); +PMDL WINAPI MmAllocatePagesForMdl(PHYSICAL_ADDRESS,PHYSICAL_ADDRESS,PHYSICAL_ADDRESS,SIZE_T); void WINAPI MmFreeNonCachedMemory(PVOID,SIZE_T); MM_SYSTEMSIZE WINAPI MmQuerySystemSize(void); diff --git a/include/devicetopology.idl b/include/devicetopology.idl new file mode 100644 index 00000000000..d373b2a96a5 --- /dev/null +++ b/include/devicetopology.idl @@ -0,0 +1,738 @@ +/* + * Core Audio device topology definitions + * + * Copyright 2009 Maarten Lankhorst + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should 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 + * + */ + +cpp_quote("#ifndef __devicetopology_h__") +cpp_quote("#define __devicetopology_h__") + +interface IPart; +interface IControlInterface; +interface IDeviceTopology; +interface IControlChangeNotify; + +import "oaidl.idl"; +import "ocidl.idl"; +import "propidl.idl"; + +cpp_quote("#define E_NOTFOUND HRESULT_FROM_WIN32(ERROR_NOT_FOUND)") +cpp_quote("#define DEVTOPO_HARDWARE_INITIATED_EVENTCONTEXT 'draH'") +cpp_quote("DEFINE_GUID(EVENTCONTEXT_VOLUMESLIDER, 0xe2c2e9de, 0x09b1, 0x4b04,0x84,0xe5, 0x07, 0x93, 0x12, 0x25, 0xee, 0x04);") + +cpp_quote("#define _IKsControl_") +cpp_quote("#include ") +cpp_quote("#include ") +cpp_quote("#ifndef _KS_") + +typedef struct { + ULONG FormatSize; + ULONG Flags; + ULONG SampleSize; + ULONG Reserved; + GUID MajorFormat; + GUID SubFormat; + GUID Specifier; +} KSDATAFORMAT; + +typedef KSDATAFORMAT *PKSDATAFORMAT; + +typedef struct +{ + union + { + struct { + GUID Set; + ULONG Id; + ULONG Flags; + } DUMMYSTRUCTNAME; + LONGLONG Alignment; + } DUMMYUNIONNAME; +} KSIDENTIFIER; + +typedef KSIDENTIFIER KSPROPERTY, *PKSPROPERTY; +typedef KSIDENTIFIER KSMETHOD, *PKSMETHOD; +typedef KSIDENTIFIER KSEVENT, *PKSEVENT; + +typedef enum +{ + eConnTypeUnknown = 0, + eConnType3Point5mm, + eConnTypeQuarter, + eConnTypeAtapiInternal, + eConnTypeRCA, + eConnTypeOptical, + eConnTypeOtherDigital, + eConnTypeOtherAnalog, + eConnTypeMultichannelAnalogDIN, + eConnTypeXlrProfessional, + eConnTypeRj11Modem, + eConnTypeCombination +} EPcxConnectionType; + +typedef enum +{ + eGeoLocRear = 1, + eGeoLocFront, + eGeoLocLeft, + eGeoLocRight, + eGeoLocTop, + eGeoLocBottom, + eGeoLocRearPanel, + eGeoLocRiser, + eGeoLocInsideMobileLid, + eGeoLocDrivebay, + eGeoLocHDMI, + eGeoLocOutsideMobileLid, + eGeoLocATAPI, + eGeoLocReserved5, + eGeoLocReserved6 +} EPcxGeoLocation; + +typedef enum +{ + eGenLocPrimaryBox = 0, + eGenLocInternal, + eGenLocSeparate, + eGenLocOther +} EPcxGenLocation; + +typedef enum +{ + ePortConnJack = 0, + ePortConnIntegratedDevice, + ePortConnBothIntegratedAndJack, + ePortConnUnknown +} EPxcPortConnection; + +typedef struct +{ + DWORD ChannelMapping; + COLORREF Color; + EPcxConnectionType ConnectionType; + EPcxGeoLocation GeoLocation; + EPcxGenLocation GenLocation; + EPxcPortConnection PortConnection; + BOOL IsConnected; +} KSJACK_DESCRIPTION; + +typedef KSJACK_DESCRIPTION *PKSJACK_DESCRIPTION; + +typedef struct _LUID +{ + DWORD LowPart; + LONG HighPart; +} LUID; + +typedef struct _LUID *PLUID; + +typedef enum +{ + KSJACK_SINK_CONNECTIONTYPE_HDMI = 0, + KSJACK_SINK_CONNECTIONTYPE_DISPLAYPORT +} KSJACK_SINK_CONNECTIONTYPE; + +typedef struct _tagKSJACK_SINK_INFORMATION +{ + KSJACK_SINK_CONNECTIONTYPE ConnType; + WORD ManufacturerId; + WORD ProductId; + WORD AudioLatency; + BOOL HDCPCapable; + BOOL AICapable; + UCHAR SinkDescriptionLength; + WCHAR SinkDescription[32]; + LUID PortId; +} KSJACK_SINK_INFORMATION; + +typedef struct _tagKSJACK_DESCRIPTION2 +{ + DWORD DeviceStateInfo; + DWORD JackCapabilities; +} KSJACK_DESCRIPTION2; + +typedef struct _tagKSJACK_DESCRIPTION2 *PKSJACK_DESCRIPTION2; + +cpp_quote("#endif") + +typedef enum +{ + In = 0, + Out +} DataFlow; + +typedef enum +{ + Connector = 0, + Subunit +} PartType; + +typedef enum +{ + Unknown_Connector = 0, + Physical_Internal, + Physical_External, + Software_IO, + Software_Fixed, + Network +} ConnectorType; + +[ + pointer_default(unique), + nonextensible, + uuid(28f54685-06fd-11d2-b27a-00a0c9223196), + local, + object +] +interface IKsControl : IUnknown +{ + HRESULT KsProperty( + [in] PKSPROPERTY Property, + [in] ULONG PropertyLength, + [in,out] void *PropertyData, + [in] ULONG DataLength, + [out] ULONG *BytesReturned + ); + HRESULT KsMethod( + [in] PKSMETHOD Method, + [in] ULONG MethodLength, + [in,out] void *MethodData, + [in] ULONG DataLength, + [out] ULONG *BytesReturned + ); + HRESULT KsEvent( + [in] PKSEVENT Event, + [in] ULONG EventLength, + [in,out] void *EventData, + [in] ULONG DataLength, + [out] ULONG *BytesReturned + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(c2f8e001-f205-4bc9-99bc-c13b1e048ccb), + local, + object +] +interface IPerChannelDbLevel : IUnknown +{ + HRESULT GetChannelCount( + [out] UINT *pcChannels + ); + HRESULT GetLevelRange( + [in] UINT nChannel, + [out] float *pfMinLevelDB, + [out] float *pfMaxLevelDB, + [out] float *pfStepping + ); + HRESULT GetLevel( + [in] UINT nChannel, + [out] float *pfLevelDB + ); + HRESULT SetLevel( + [in] UINT nChannel, + [in] float fLevelDB, + [in,unique] LPCGUID pguidEventContext + ); + HRESULT SetLevelUniform( + [in] float fLevelDB, + [in,unique] LPCGUID pguidEventContext + ); + HRESULT SetLevelAllChannels( + [size_is(cChannels),in] float *aLevelsDB, + [in] ULONG cChannels, + [in] LPCGUID pguidEventContext + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(7fb7b48f-531d-44a2-bcb3-5ad5a134b3dc), + local, + object +] +interface IAudioVolumeLevel : IPerChannelDbLevel +{ + /* Empty */ +} + +[ + pointer_default(unique), + nonextensible, + uuid(bb11c46f-ec28-493c-b88a-5db88062ce98), + local, + object +] +interface IAudioChannelConfig : IUnknown +{ + HRESULT SetChannelConfig( + [in] DWORD dwConfig, + [in] LPCGUID pguidEventContext + ); + HRESULT GetChannelConfig( + [in] DWORD dwConfig, + [retval,out] DWORD *pdwConfig + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(7d8b1437-dd53-4350-9c1b-1ee2890bf938), + local, + object +] +interface IAudioLoudness : IUnknown +{ + HRESULT GetEnabled( + [out] BOOL *pbEnabled + ); + HRESULT SetEnabled( + [in] BOOL bEnabled, + [in] LPCGUID pguidEventContext + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(4f03dc02-5e6e-4653-8f72-a030c123d598), + local, + object +] +interface IAudioInputSelector : IUnknown +{ + HRESULT GetSelection( + [out] UINT *pnIdSelected + ); + HRESULT SetSelection( + [in] UINT nIdSelect, + [unique,in] LPCGUID pguidEventContext + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(bb515f69-94a7-429e-8b9c-271b3f11a3ab), + local, + object +] +interface IAudioOutputSelector : IUnknown +{ + HRESULT GetSelection( + [out] UINT *pnIdSelected + ); + HRESULT SetSelection( + [in] UINT nIdSelect, + [unique,in] LPCGUID pguidEventContext + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(bb515f69-94a7-429e-8b9c-271b3f11a3ab), + local, + object +] +interface IAudioMute : IUnknown +{ + HRESULT SetMute( + [in] BOOL bMute, + [unique,in] LPCGUID pguidEventContext + ); + HRESULT GetMute( + [out] BOOL *pbMute + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(a2b1a1d9-4db3-425d-a2b2-bd335cb3e2e5), + local, + object +] +interface IAudioBass : IPerChannelDbLevel +{ + /* Empty */ +} + +[ + pointer_default(unique), + nonextensible, + uuid(5e54b6d7-b44b-40d9-9a9e-e691d9ce6edf), + local, + object +] +interface IAudioMidRange : IPerChannelDbLevel +{ + /* Empty */ +} + +[ + pointer_default(unique), + nonextensible, + uuid(0a717812-694e-4907-b74b-bafa5cfdca7b), + local, + object +] +interface IAudioTreble : IPerChannelDbLevel +{ + /* Empty */ +} + +[ + pointer_default(unique), + nonextensible, + uuid(bb515f69-94a7-429e-8b9c-271b3f11a3ab), + local, + object +] +interface IAudioAutoGainControl : IUnknown +{ + HRESULT GetEnabled( + [in] BOOL bEnabled, + [unique,in] LPCGUID pguidEventContext + ); + HRESULT GetMute( + [out] BOOL *pbEnabled + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(dd79923c-0599-45e0-b8b6-c8df7db6e796), + local, + object +] +interface IAudioPeakMeter : IUnknown +{ + HRESULT GetChannelCount( + [out] UINT *pcChannels + ); + HRESULT GetLevel( + [in] UINT nChannel, + [out] float *pfLevel + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(3b22bcbf-2586-4af0-8583-205d391b807c), + local, + object +] +interface IDeviceSpecificProperty : IUnknown +{ + HRESULT GetType( + [out] VARTYPE *pVType + ); + HRESULT GetValue( + [out] VARTYPE *pvType, + [out,in] DWORD *pcbValue + ); + HRESULT SetValue( + [in] void *pvValue, + [in] DWORD cbValue, + [in] LPCGUID pguidEventContext + ); + HRESULT Get4BRange( + [out] LONG *plMin, + [out] LONG *plMax, + [out] LONG *plStepping + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(3cb4a69d-bb6f-4d2b-95b7-452d2c155db5), + local, + object +] +interface IKsFormatSupport : IUnknown +{ + HRESULT IsFormatSupported( + [size_is(cbFormat),in] PKSDATAFORMAT pKsFormat, + [in] DWORD cbFormat, + [out] BOOL *pbSupported + ); + HRESULT GetDevicePreferredFormat( + [out] PKSDATAFORMAT *ppKsFormat + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(4509f757-2d46-4637-8e62-ce7db944f57b), + local, + object +] +interface IKsJackDescription : IUnknown +{ + HRESULT GetJackCount( + [out] UINT *pcJacks + ); + HRESULT GetJackDescription( + [in] UINT nJack, + [out] KSJACK_DESCRIPTION *pDescription + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(478f3a9b-e0c9-4827-9228-6f5505ffe76a), + local, + object +] +interface IKsJackDescription2 : IUnknown +{ + HRESULT GetJackCount( + [out] UINT *pcJacks + ); + HRESULT GetJackDescription2( + [in] UINT nJack, + [out] KSJACK_DESCRIPTION2 *pDescription2 + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(d9bd72ed-290f-4581-9ff3-61027a8fe532), + local, + object +] +interface IKsJackSinkInformation : IUnknown +{ + HRESULT GetJackSinkInformation( + [out] KSJACK_SINK_INFORMATION *pJackSinkInformation + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(6daa848c-5eb0-45cc-aea5-998a2cda1ffb), + local, + object +] +interface IPartsList : IUnknown +{ + HRESULT GetCount( + [out] UINT *pCount + ); + HRESULT GetPart( + [in] UINT nIndex, + [out] IPart **ppPart + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(ae2de0e4-5bca-4f2d-aa46-5d13f8fdb3a9), + local, + object +] +interface IPart : IUnknown +{ + HRESULT GetName( + [out] LPWSTR *ppwstrName + ); + HRESULT GetLocalId( + [out] UINT *pnId + ); + HRESULT GetGlobalId( + [out] LPWSTR *ppwstrGlobalId + ); + HRESULT GetPartType( + [out] PartType *pPartType + ); + HRESULT GetSubType( + [out] GUID *pSubType + ); + HRESULT GetControlInterfaceCount( + [out] UINT *pCount + ); + HRESULT GetControlInterface( + [in] UINT nIndex, + [out] IControlInterface **ppInterfaceDesc + ); + HRESULT EnumPartsIncoming( + [out] IPartsList **ppParts + ); + HRESULT EnumPartsOutgoing( + [out] IPartsList **ppParts + ); + HRESULT GetTopologyObjects( + [out] IDeviceTopology **ppTopology + ); + HRESULT Activate( + [in] DWORD dwClsContext, + [in] REFIID refiid, + [iid_is(refiid),out] void **ppvObject + ); + HRESULT RegisterControlChangeCallback( + [in] REFGUID riid, + [in] IControlChangeNotify *pNotify + ); + HRESULT UnregisterControlChangeCallback( + [in] IControlChangeNotify *pNotify + ); +}; + +[ + pointer_default(unique), + nonextensible, + uuid(9c2c4058-23f5-41de-877a-df3af236a09e), + local, + object +] +interface IConnector : IUnknown +{ + HRESULT GetType( + [out] ConnectorType *pType + ); + HRESULT GetDataFlow( + [out] DataFlow *pFlow + ); + HRESULT ConnectTo( + [in] IConnector *pConnectTo + ); + HRESULT Disconnect(void); + HRESULT IsConnected( + [out] BOOL *pbConnected + ); + HRESULT GetConnectedTo( + [out] IConnector **ppConTo + ); + HRESULT GetConnectorIdConnectedTo( + [out] LPWSTR *ppwstrConnectorId + ); + HRESULT GetDeviceIdConnectedTo( + [out] LPWSTR *ppwstrDeviceId + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(82149a85-dba6-4487-86bb-ea8f7fefcc71), + local, + object +] +interface ISubUnit: IUnknown +{ + /* Empty IUnknown interface.. */ +} + +[ + pointer_default(unique), + nonextensible, + uuid(45d37c3f-5140-444a-ae24-400789f3cbf3), + local, + object +] +interface IControlInterface : IUnknown +{ + HRESULT GetName( + [out] LPWSTR *ppwstrName + ); + HRESULT GetIID( + [out] GUID *pIID + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(a09513ed-c709-4d21-bd7b-5f34c47f3947), + local, + object +] +interface IControlChangeNotify : IUnknown +{ + HRESULT OnNotify( + [in] DWORD dwSenderProcessId, + [in] LPCGUID ppguidEventContext + ); +} + +[ + pointer_default(unique), + nonextensible, + uuid(2a07407e-6497-4a18-9787-32f79bd0d98f), + local, + object +] +interface IDeviceTopology : IUnknown +{ + HRESULT GetConnectorCount( + [out] UINT *pCount + ); + HRESULT GetConnector( + [in] UINT nIndex, + [out] IConnector **ppConnector + ); + HRESULT GetSubunitCount( + [out] UINT *pCount + ); + HRESULT GetSubunit( + [in] UINT nIndex, + [out] ISubUnit **ppConnector + ); + HRESULT GetPartById( + [in] UINT nId, + [out] IPart **ppPart + ); + HRESULT GetDeviceId( + [out] LPWSTR *ppwstrDeviceId + ); + HRESULT GetSignalPath( + [in] IPart *pIPartFrom, + [in] IPart *pIPartTo, + [in] BOOL bRejectMixedPaths, + [out] IPartsList **ppParts + ); +} + +[ + version(1.0) +] +library DevTopologyLib +{ + [ + uuid(1df639d0-5ec1-47aa-9379-828dc1aa8c59), + ] + coclass DeviceTopology + { + interface IDeviceTopology; + } +} + +cpp_quote("#endif /*__devicetopology_h__*/") diff --git a/include/dsound.h b/include/dsound.h index e1bd6680fc5..0923561ceec 100644 --- a/include/dsound.h +++ b/include/dsound.h @@ -1074,7 +1074,7 @@ DECLARE_INTERFACE_(IDirectSound3DBuffer,IUnknown) #define IDirectSound3DBuffer_GetPosition(p,a) (p)->lpVtbl->GetPosition(p,a) #define IDirectSound3DBuffer_GetVelocity(p,a) (p)->lpVtbl->GetVelocity(p,a) #define IDirectSound3DBuffer_SetAllParameters(p,a,b) (p)->lpVtbl->SetAllParameters(p,a,b) -#define IDirectSound3DBuffer_SetConeAngles(p,a,b) (p)->lpVtbl->SetConeAngles(p,a,b) +#define IDirectSound3DBuffer_SetConeAngles(p,a,b,c) (p)->lpVtbl->SetConeAngles(p,a,b,c) #define IDirectSound3DBuffer_SetConeOrientation(p,a,b,c,d) (p)->lpVtbl->SetConeOrientation(p,a,b,c,d) #define IDirectSound3DBuffer_SetConeOutsideVolume(p,a,b) (p)->lpVtbl->SetConeOutsideVolume(p,a,b) #define IDirectSound3DBuffer_SetMaxDistance(p,a,b) (p)->lpVtbl->SetMaxDistance(p,a,b) diff --git a/include/gdiplusflat.h b/include/gdiplusflat.h index bce1e2103bf..563ee96a101 100644 --- a/include/gdiplusflat.h +++ b/include/gdiplusflat.h @@ -74,12 +74,15 @@ GpStatus WINGDIPAPI GdipCreateCustomLineCap(GpPath*,GpPath*,GpLineCap,REAL, GpCustomLineCap**); GpStatus WINGDIPAPI GdipDeleteCustomLineCap(GpCustomLineCap*); GpStatus WINGDIPAPI GdipGetCustomLineCapBaseCap(GpCustomLineCap*,GpLineCap*); +GpStatus WINGDIPAPI GdipSetCustomLineCapBaseCap(GpCustomLineCap*,GpLineCap); GpStatus WINGDIPAPI GdipGetCustomLineCapBaseInset(GpCustomLineCap*,REAL*); +GpStatus WINGDIPAPI GdipSetCustomLineCapBaseInset(GpCustomLineCap*,REAL); GpStatus WINGDIPAPI GdipSetCustomLineCapStrokeCaps(GpCustomLineCap*,GpLineCap, GpLineCap); GpStatus WINGDIPAPI GdipGetCustomLineCapStrokeJoin(GpCustomLineCap*,GpLineJoin*); GpStatus WINGDIPAPI GdipSetCustomLineCapStrokeJoin(GpCustomLineCap*,GpLineJoin); GpStatus WINGDIPAPI GdipGetCustomLineCapWidthScale(GpCustomLineCap*,REAL*); +GpStatus WINGDIPAPI GdipSetCustomLineCapBaseInset(GpCustomLineCap*,REAL); /* Font */ GpStatus WINGDIPAPI GdipCloneFont(GpFont*,GpFont**); @@ -104,6 +107,8 @@ GpStatus WINGDIPAPI GdipNewInstalledFontCollection(GpFontCollection**); GpStatus WINGDIPAPI GdipNewPrivateFontCollection(GpFontCollection**); GpStatus WINGDIPAPI GdipDeletePrivateFontCollection(GpFontCollection**); GpStatus WINGDIPAPI GdipPrivateAddFontFile(GpFontCollection*, GDIPCONST WCHAR*); +GpStatus WINGDIPAPI GdipPrivateAddMemoryFont(GpFontCollection*, + GDIPCONST void*,INT); GpStatus WINGDIPAPI GdipGetFontCollectionFamilyCount(GpFontCollection*, INT*); GpStatus WINGDIPAPI GdipGetFontCollectionFamilyList(GpFontCollection*, INT, GpFontFamily*[], INT*); @@ -134,6 +139,7 @@ GpStatus WINGDIPAPI GdipCreateFromHDC(HDC,GpGraphics**); GpStatus WINGDIPAPI GdipCreateFromHDC2(HDC,HANDLE,GpGraphics**); GpStatus WINGDIPAPI GdipCreateFromHWND(HWND,GpGraphics**); GpStatus WINGDIPAPI GdipCreateFromHWNDICM(HWND,GpGraphics**); +HPALETTE WINGDIPAPI GdipCreateHalftonePalette(void); GpStatus WINGDIPAPI GdipDeleteGraphics(GpGraphics *); GpStatus WINGDIPAPI GdipDrawArc(GpGraphics*,GpPen*,REAL,REAL,REAL,REAL,REAL,REAL); GpStatus WINGDIPAPI GdipDrawArcI(GpGraphics*,GpPen*,INT,INT,INT,INT,REAL,REAL); @@ -151,6 +157,8 @@ GpStatus WINGDIPAPI GdipDrawCurve2(GpGraphics*,GpPen*,GDIPCONST GpPointF*,INT,RE GpStatus WINGDIPAPI GdipDrawCurve2I(GpGraphics*,GpPen*,GDIPCONST GpPoint*,INT,REAL); GpStatus WINGDIPAPI GdipDrawCurve3(GpGraphics*,GpPen*,GDIPCONST GpPointF*,INT,INT,INT,REAL); GpStatus WINGDIPAPI GdipDrawCurve3I(GpGraphics*,GpPen*,GDIPCONST GpPoint*,INT,INT,INT,REAL); +GpStatus WINGDIPAPI GdipDrawDriverString(GpGraphics*,GDIPCONST UINT16*,INT, + GDIPCONST GpFont*,GDIPCONST GpBrush*,GDIPCONST PointF*,INT,GDIPCONST GpMatrix*); GpStatus WINGDIPAPI GdipDrawEllipse(GpGraphics*,GpPen*,REAL,REAL,REAL,REAL); GpStatus WINGDIPAPI GdipDrawEllipseI(GpGraphics*,GpPen*,INT,INT,INT,INT); GpStatus WINGDIPAPI GdipDrawImage(GpGraphics*,GpImage*,REAL,REAL); @@ -238,9 +246,13 @@ GpStatus WINGDIPAPI GdipIsVisibleRectI(GpGraphics*,INT,INT,INT,INT,BOOL*); GpStatus WINGDIPAPI GdipMeasureCharacterRanges(GpGraphics*, GDIPCONST WCHAR*, INT, GDIPCONST GpFont*, GDIPCONST RectF*, GDIPCONST GpStringFormat*, INT, GpRegion**); +GpStatus WINGDIPAPI GdipMeasureDriverString(GpGraphics*,GDIPCONST UINT16*,INT, + GDIPCONST GpFont*,GDIPCONST PointF*,INT,GDIPCONST GpMatrix*,RectF*); GpStatus WINGDIPAPI GdipMeasureString(GpGraphics*,GDIPCONST WCHAR*,INT, GDIPCONST GpFont*,GDIPCONST RectF*,GDIPCONST GpStringFormat*,RectF*,INT*,INT*); GpStatus WINGDIPAPI GdipMultiplyWorldTransform(GpGraphics*,GDIPCONST GpMatrix*,GpMatrixOrder); +GpStatus WINGDIPAPI GdipRecordMetafileI(HDC,EmfType,GDIPCONST GpRect*, + MetafileFrameUnit,GDIPCONST WCHAR*,GpMetafile**); GpStatus WINGDIPAPI GdipReleaseDC(GpGraphics*,HDC); GpStatus WINGDIPAPI GdipResetClip(GpGraphics*); GpStatus WINGDIPAPI GdipResetWorldTransform(GpGraphics*); @@ -249,6 +261,7 @@ GpStatus WINGDIPAPI GdipRotateWorldTransform(GpGraphics*,REAL,GpMatrixOrder); GpStatus WINGDIPAPI GdipSaveGraphics(GpGraphics*,GraphicsState*); GpStatus WINGDIPAPI GdipScaleWorldTransform(GpGraphics*,REAL,REAL,GpMatrixOrder); GpStatus WINGDIPAPI GdipSetClipHrgn(GpGraphics*,HRGN,CombineMode); +GpStatus WINGDIPAPI GdipSetClipGraphics(GpGraphics*,GpGraphics*,CombineMode); GpStatus WINGDIPAPI GdipSetClipPath(GpGraphics*,GpPath*,CombineMode); GpStatus WINGDIPAPI GdipSetClipRect(GpGraphics*,REAL,REAL,REAL,REAL,CombineMode); GpStatus WINGDIPAPI GdipSetClipRectI(GpGraphics*,INT,INT,INT,INT,CombineMode); @@ -259,6 +272,7 @@ GpStatus WINGDIPAPI GdipSetInterpolationMode(GpGraphics*,InterpolationMode); GpStatus WINGDIPAPI GdipSetPageScale(GpGraphics*,REAL); GpStatus WINGDIPAPI GdipSetPageUnit(GpGraphics*,GpUnit); GpStatus WINGDIPAPI GdipSetPixelOffsetMode(GpGraphics*,PixelOffsetMode); +GpStatus WINGDIPAPI GdipSetRenderingOrigin(GpGraphics*,INT,INT); GpStatus WINGDIPAPI GdipSetSmoothingMode(GpGraphics*,SmoothingMode); GpStatus WINGDIPAPI GdipSetTextContrast(GpGraphics*,UINT); GpStatus WINGDIPAPI GdipSetTextRenderingHint(GpGraphics*,TextRenderingHint); @@ -336,11 +350,15 @@ GpStatus WINGDIPAPI GdipSetPathFillMode(GpPath*,GpFillMode); GpStatus WINGDIPAPI GdipSetPathMarker(GpPath*); GpStatus WINGDIPAPI GdipStartPathFigure(GpPath*); GpStatus WINGDIPAPI GdipTransformPath(GpPath*,GpMatrix*); +GpStatus WINGDIPAPI GdipWarpPath(GpPath*,GpMatrix*,GDIPCONST GpPointF*,INT,REAL, + REAL,REAL,REAL,WarpMode,REAL); +GpStatus WINGDIPAPI GdipWidenPath(GpPath*,GpPen*,GpMatrix*,REAL); /* HatchBrush */ GpStatus WINGDIPAPI GdipCreateHatchBrush(HatchStyle,ARGB,ARGB,GpHatch**); GpStatus WINGDIPAPI GdipGetHatchBackgroundColor(GpHatch*,ARGB*); GpStatus WINGDIPAPI GdipGetHatchForegroundColor(GpHatch*,ARGB*); +GpStatus WINGDIPAPI GdipGetHatchStyle(GpHatch*,HatchStyle*); /* Image */ GpStatus WINGDIPAPI GdipCloneImage(GpImage*, GpImage**); @@ -421,11 +439,18 @@ GpStatus WINGDIPAPI GdipSetLinePresetBlend(GpLineGradient*,GDIPCONST ARGB*, GDIPCONST REAL*,INT); GpStatus WINGDIPAPI GdipGetLinePresetBlend(GpLineGradient*,ARGB*,REAL*,INT); GpStatus WINGDIPAPI GdipGetLinePresetBlendCount(GpLineGradient*,INT*); +GpStatus WINGDIPAPI GdipResetLineTransform(GpLineGradient*); +GpStatus WINGDIPAPI GdipRotateLineTransform(GpLineGradient*,REAL,GpMatrixOrder); +GpStatus WINGDIPAPI GdipScaleLineTransform(GpLineGradient*,REAL,REAL, + GpMatrixOrder); GpStatus WINGDIPAPI GdipSetLineColors(GpLineGradient*,ARGB,ARGB); GpStatus WINGDIPAPI GdipSetLineGammaCorrection(GpLineGradient*,BOOL); GpStatus WINGDIPAPI GdipSetLineSigmaBlend(GpLineGradient*,REAL,REAL); +GpStatus WINGDIPAPI GdipSetLineTransform(GpLineGradient*,GDIPCONST GpMatrix*); GpStatus WINGDIPAPI GdipSetLineLinearBlend(GpLineGradient*,REAL,REAL); GpStatus WINGDIPAPI GdipSetLineWrapMode(GpLineGradient*,GpWrapMode); +GpStatus WINGDIPAPI GdipTranslateLineTransform(GpLineGradient*,REAL,REAL, + GpMatrixOrder); /* Matrix */ GpStatus WINGDIPAPI GdipCloneMatrix(GpMatrix*,GpMatrix**); @@ -484,6 +509,8 @@ GpStatus WINGDIPAPI GdipGetPathGradientCenterPointI(GpPathGradient*,GpPoint*); GpStatus WINGDIPAPI GdipGetPathGradientFocusScales(GpPathGradient*,REAL*,REAL*); GpStatus WINGDIPAPI GdipGetPathGradientGammaCorrection(GpPathGradient*,BOOL*); GpStatus WINGDIPAPI GdipGetPathGradientPointCount(GpPathGradient*,INT*); +GpStatus WINGDIPAPI GdipSetPathGradientPresetBlend(GpPathGradient*, + GDIPCONST ARGB*,GDIPCONST REAL*,INT); GpStatus WINGDIPAPI GdipGetPathGradientRect(GpPathGradient*,GpRectF*); GpStatus WINGDIPAPI GdipGetPathGradientRectI(GpPathGradient*,GpRect*); GpStatus WINGDIPAPI GdipGetPathGradientSurroundColorsWithCount(GpPathGradient*, @@ -629,9 +656,15 @@ GpStatus WINGDIPAPI GdipCreateTextureIAI(GpImage*,GDIPCONST GpImageAttributes*, INT,INT,INT,INT,GpTexture**); GpStatus WINGDIPAPI GdipGetTextureTransform(GpTexture*,GpMatrix*); GpStatus WINGDIPAPI GdipGetTextureWrapMode(GpTexture*, GpWrapMode*); +GpStatus WINGDIPAPI GdipMultiplyTextureTransform(GpTexture*, + GDIPCONST GpMatrix*,GpMatrixOrder); GpStatus WINGDIPAPI GdipResetTextureTransform(GpTexture*); +GpStatus WINGDIPAPI GdipRotateTextureTransform(GpTexture*,REAL,GpMatrixOrder); +GpStatus WINGDIPAPI GdipScaleTextureTransform(GpTexture*,REAL,REAL,GpMatrixOrder); GpStatus WINGDIPAPI GdipSetTextureTransform(GpTexture *,GDIPCONST GpMatrix*); GpStatus WINGDIPAPI GdipSetTextureWrapMode(GpTexture*, GpWrapMode); +GpStatus WINGDIPAPI GdipTranslateTextureTransform(GpTexture*,REAL,REAL, + GpMatrixOrder); /* Without wrapper methods */ GpStatus WINGDIPAPI GdipCreateStreamOnFile(GDIPCONST WCHAR*,UINT,IStream**); diff --git a/include/ksmedia.h b/include/ksmedia.h index 4f36ccc8b1e..4dfe058d606 100644 --- a/include/ksmedia.h +++ b/include/ksmedia.h @@ -34,4 +34,102 @@ DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0 #define KSAUDIO_SPEAKER_5POINT1 (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOWFREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT) #define KSAUDIO_SPEAKER_7POINT1 (KSAUDIO_SPEAKER_5POINT1 | SPEAKER_FRONT_LEFT_OF_CENTER | SPEAKER_FRONT_RIGHT_OF_CENTER) +typedef LONGLONG REFERENCE_TIME; + +typedef enum +{ + eConnTypeUnknown = 0, + eConnType3Point5mm, + eConnTypeQuarter, + eConnTypeAtapiInternal, + eConnTypeRCA, + eConnTypeOptical, + eConnTypeOtherDigital, + eConnTypeOtherAnalog, + eConnTypeMultichannelAnalogDIN, + eConnTypeXlrProfessional, + eConnTypeRj11Modem, + eConnTypeCombination +} EPcxConnectionType; + +typedef enum +{ + eGeoLocRear = 1, + eGeoLocFront, + eGeoLocLeft, + eGeoLocRight, + eGeoLocTop, + eGeoLocBottom, + eGeoLocRearPanel, + eGeoLocRiser, + eGeoLocInsideMobileLid, + eGeoLocDrivebay, + eGeoLocHDMI, + eGeoLocOutsideMobileLid, + eGeoLocATAPI, + eGeoLocReserved5, + eGeoLocReserved6 +} EPcxGeoLocation; + +typedef enum +{ + eGenLocPrimaryBox = 0, + eGenLocInternal, + eGenLocSeparate, + eGenLocOther +} EPcxGenLocation; + +typedef enum +{ + ePortConnJack = 0, + ePortConnIntegratedDevice, + ePortConnBothIntegratedAndJack, + ePortConnUnknown +} EPxcPortConnection; + +typedef struct +{ + DWORD ChannelMapping; + COLORREF Color; + EPcxConnectionType ConnectionType; + EPcxGeoLocation GeoLocation; + EPcxGenLocation GenLocation; + EPxcPortConnection PortConnection; + BOOL IsConnected; +} KSJACK_DESCRIPTION; + +typedef KSJACK_DESCRIPTION *PKSJACK_DESCRIPTION; + +typedef enum +{ + KSJACK_SINK_CONNECTIONTYPE_HDMI = 0, + KSJACK_SINK_CONNECTIONTYPE_DISPLAYPORT +} KSJACK_SINK_CONNECTIONTYPE; + +#define MAX_SINK_DESCRIPTION_NAME_LENGTH 32 + +typedef struct _tagKSJACK_SINK_INFORMATION +{ + KSJACK_SINK_CONNECTIONTYPE ConnType; + WORD ManufacturerId; + WORD ProductId; + WORD AudioLatency; + BOOL HDCPCapable; + BOOL AICapable; + UCHAR SinkDescriptionLength; + WCHAR SinkDescription[MAX_SINK_DESCRIPTION_NAME_LENGTH]; + LUID PortId; +} KSJACK_SINK_INFORMATION; + +#define JACKDESC2_PRESENCE_DETECT_CAPABILITY 0x1 +#define JACKDESC2_DYNAMIC_FORMAT_CHANGE_CAPABILITY 0x2 + +typedef struct _tagKSJACK_DESCRIPTION2 +{ + DWORD DeviceStateInfo; + DWORD JackCapabilities; +} KSJACK_DESCRIPTION2; + +typedef struct _tagKSJACK_DESCRIPTION2 *PKSJACK_DESCRIPTION2; + #endif /* _KSMEDIA_ */ diff --git a/include/mmsystem.h b/include/mmsystem.h index 39f70a18401..dd9723af2cb 100644 --- a/include/mmsystem.h +++ b/include/mmsystem.h @@ -1809,7 +1809,7 @@ YIELDPROC WINAPI mciGetYieldProc(MCIDEVICEID,DWORD*); #define MCI_USER_MESSAGES (0x400 + DRV_MCI_FIRST) -#define MCI_ALL_DEVICE_ID 0xFFFF +#define MCI_ALL_DEVICE_ID 0xFFFFFFFF #define MCI_DEVTYPE_VCR (MCI_STRING_OFFSET + 1) #define MCI_DEVTYPE_VIDEODISC (MCI_STRING_OFFSET + 2) diff --git a/include/msvcrt/crtdefs.h b/include/msvcrt/crtdefs.h index 2a101a92b2b..61116e99665 100644 --- a/include/msvcrt/crtdefs.h +++ b/include/msvcrt/crtdefs.h @@ -80,6 +80,16 @@ # endif #endif +#ifndef DECLSPEC_ALIGN +# if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(MIDL_PASS) +# define DECLSPEC_ALIGN(x) __declspec(align(x)) +# elif defined(__GNUC__) +# define DECLSPEC_ALIGN(x) __attribute__((aligned(x))) +# else +# define DECLSPEC_ALIGN(x) +# endif +#endif + #ifndef _MSVCRT_LONG_DEFINED #define _MSVCRT_LONG_DEFINED /* we need 32-bit longs even on 64-bit */ @@ -129,7 +139,7 @@ typedef __msvcrt_long __time32_t; #endif #ifndef _TIME64_T_DEFINED -typedef __int64 __time64_t; +typedef __int64 DECLSPEC_ALIGN(8) __time64_t; #define _TIME64_T_DEFINED #endif diff --git a/include/msvcrt/io.h b/include/msvcrt/io.h index e15dff1ac8d..c7ba9ab47b0 100644 --- a/include/msvcrt/io.h +++ b/include/msvcrt/io.h @@ -44,7 +44,7 @@ struct _finddatai64_t time_t time_create; time_t time_access; time_t time_write; - __int64 size; + __int64 DECLSPEC_ALIGN(8) size; char name[260]; }; #endif /* _FINDDATA_T_DEFINED */ @@ -65,7 +65,7 @@ struct _wfinddatai64_t { time_t time_create; time_t time_access; time_t time_write; - __int64 size; + __int64 DECLSPEC_ALIGN(8) size; wchar_t name[260]; }; #endif /* _WFINDDATA_T_DEFINED */ diff --git a/include/msvcrt/stdio.h b/include/msvcrt/stdio.h index 1b3872cc372..b309ebbd463 100644 --- a/include/msvcrt/stdio.h +++ b/include/msvcrt/stdio.h @@ -72,7 +72,7 @@ typedef struct _iobuf #endif /* _FILE_DEFINED */ #ifndef _FPOS_T_DEFINED -typedef __int64 fpos_t; +typedef __int64 DECLSPEC_ALIGN(8) fpos_t; #define _FPOS_T_DEFINED #endif diff --git a/include/msvcrt/wchar.h b/include/msvcrt/wchar.h index fe761667bad..66d3a8103ed 100644 --- a/include/msvcrt/wchar.h +++ b/include/msvcrt/wchar.h @@ -111,7 +111,7 @@ struct _wfinddatai64_t { time_t time_create; time_t time_access; time_t time_write; - __int64 size; + __int64 DECLSPEC_ALIGN(8) size; wchar_t name[260]; }; diff --git a/include/propkeydef.h b/include/propkeydef.h index 8507ddbabc3..2a459841858 100644 --- a/include/propkeydef.h +++ b/include/propkeydef.h @@ -33,18 +33,18 @@ #ifdef INITGUID #ifdef __cplusplus #define DEFINE_PROPERTYKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) \ - EXTERN_C const PROPERTYKEY name DECLSPEC_HIDDEN DECLSPEC_ANY; \ + EXTERN_C const PROPERTYKEY name DECLSPEC_HIDDEN DECLSPEC_SELECTANY; \ EXTERN_C const PROPERTYKEY name = \ { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }, pid } #else #define DEFINE_PROPERTYKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) \ - const PROPERTYKEY name DECLSPEC_HIDDEN DECLSPEC_ANY; \ + const PROPERTYKEY name DECLSPEC_HIDDEN DECLSPEC_SELECTANY; \ const PROPERTYKEY name = \ { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }, pid } #endif #else #define DEFINE_PROPERTYKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) \ - EXTERN_C const PROPERTYKEY name DECLSPEC_HIDDEN DECLSPEC_ANY + EXTERN_C const PROPERTYKEY name DECLSPEC_HIDDEN DECLSPEC_SELECTANY #endif #ifndef IsEqualPropertyKey diff --git a/include/prsht.h b/include/prsht.h index 27e43c8c6da..0830757a9af 100644 --- a/include/prsht.h +++ b/include/prsht.h @@ -266,7 +266,7 @@ DECL_WINELIB_TYPE_AW(LPFNPSPCALLBACK) #define PSH_WIZARD97_NEW 0x01000000 /* for IE >= 5 */ #define PSH_NOCONTEXTHELP 0x02000000 #ifndef __WINESRC__ -# if _WIN32_IE < 0x0500 +# if defined(_WIN32_IE) && (_WIN32_IE < 0x0500) # define PSH_WIZARD97 PSH_WIZARD97_OLD # else # define PSH_WIZARD97 PSH_WIZARD97_NEW diff --git a/include/rpcndr.h b/include/rpcndr.h index 81baa870758..5ab0685bb4c 100644 --- a/include/rpcndr.h +++ b/include/rpcndr.h @@ -97,8 +97,8 @@ extern "C" { #define small char typedef unsigned char byte; -#define hyper __int64 -#define MIDL_uhyper unsigned __int64 +typedef INT64 hyper; +typedef UINT64 MIDL_uhyper; typedef unsigned char boolean; #define __RPC_CALLEE WINAPI diff --git a/include/winbase.h b/include/winbase.h index 0b4ee170d11..8298cbd4cbb 100644 --- a/include/winbase.h +++ b/include/winbase.h @@ -501,6 +501,10 @@ typedef struct tagMEMORYSTATUSEX { } MEMORYSTATUSEX, *LPMEMORYSTATUSEX; #include +typedef enum _MEMORY_RESOURCE_NOTIFICATION_TYPE { + LowMemoryResourceNotification, + HighMemoryResourceNotification +} MEMORY_RESOURCE_NOTIFICATION_TYPE; #ifndef _SYSTEMTIME_ #define _SYSTEMTIME_ @@ -1391,6 +1395,7 @@ WINBASEAPI HANDLE WINAPI CreateJobObjectW(LPSECURITY_ATTRIBUTES,LPCWSTR); WINBASEAPI HANDLE WINAPI CreateMailslotA(LPCSTR,DWORD,DWORD,LPSECURITY_ATTRIBUTES); WINBASEAPI HANDLE WINAPI CreateMailslotW(LPCWSTR,DWORD,DWORD,LPSECURITY_ATTRIBUTES); #define CreateMailslot WINELIB_NAME_AW(CreateMailslot) +WINBASEAPI HANDLE WINAPI CreateMemoryResourceNotification(MEMORY_RESOURCE_NOTIFICATION_TYPE); WINBASEAPI HANDLE WINAPI CreateMutexA(LPSECURITY_ATTRIBUTES,BOOL,LPCSTR); WINBASEAPI HANDLE WINAPI CreateMutexW(LPSECURITY_ATTRIBUTES,BOOL,LPCWSTR); #define CreateMutex WINELIB_NAME_AW(CreateMutex) diff --git a/include/wine/rpcfc.h b/include/wine/rpcfc.h index ee7ba7fb1ff..53dd1633087 100644 --- a/include/wine/rpcfc.h +++ b/include/wine/rpcfc.h @@ -167,6 +167,7 @@ #define RPC_FC_PROC_OIF_OBJECT 0x04 #define RPC_FC_PROC_OIF_RPCFLAGS 0x08 #define RPC_FC_PROC_OIF_OBJ_V2 0x20 +#define RPC_FC_PROC_OIF_HAS_COMM_OR_FAULT 0x20 #define RPC_FC_PROC_OIF_NEWINIT 0x40 #define RPC_FC_PROC_PF_MUSTSIZE 0x0001 diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index fd52bfbf15d..6a860dfc53a 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -4123,16 +4123,17 @@ struct access_check_reply char __pad_20[4]; }; -struct get_token_user_request +struct get_token_sid_request { struct request_header __header; obj_handle_t handle; + unsigned int which_sid; }; -struct get_token_user_reply +struct get_token_sid_reply { struct reply_header __header; - data_size_t user_len; - /* VARARG(user,SID); */ + data_size_t sid_len; + /* VARARG(sid,SID); */ char __pad_12[4]; }; @@ -4862,7 +4863,7 @@ enum request REQ_check_token_privileges, REQ_duplicate_token, REQ_access_check, - REQ_get_token_user, + REQ_get_token_sid, REQ_get_token_groups, REQ_get_token_default_dacl, REQ_set_token_default_dacl, @@ -5110,7 +5111,7 @@ union generic_request struct check_token_privileges_request check_token_privileges_request; struct duplicate_token_request duplicate_token_request; struct access_check_request access_check_request; - struct get_token_user_request get_token_user_request; + struct get_token_sid_request get_token_sid_request; struct get_token_groups_request get_token_groups_request; struct get_token_default_dacl_request get_token_default_dacl_request; struct set_token_default_dacl_request set_token_default_dacl_request; @@ -5356,7 +5357,7 @@ union generic_reply struct check_token_privileges_reply check_token_privileges_reply; struct duplicate_token_reply duplicate_token_reply; struct access_check_reply access_check_reply; - struct get_token_user_reply get_token_user_reply; + struct get_token_sid_reply get_token_sid_reply; struct get_token_groups_reply get_token_groups_reply; struct get_token_default_dacl_reply get_token_default_dacl_reply; struct set_token_default_dacl_reply set_token_default_dacl_reply; @@ -5393,6 +5394,6 @@ union generic_reply struct free_user_handle_reply free_user_handle_reply; }; -#define SERVER_PROTOCOL_VERSION 393 +#define SERVER_PROTOCOL_VERSION 394 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/include/wine/wgl.h b/include/wine/wgl.h index a1021094e09..7a99de27598 100644 --- a/include/wine/wgl.h +++ b/include/wine/wgl.h @@ -200,7 +200,11 @@ #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 #define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 #define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 #define ERROR_INVALID_VERSION_ARB 0x2095 +#define ERROR_INVALID_PROFILE_ARB 0x2096 #ifndef GLX_ARB_create_context #define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001 #define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 @@ -208,6 +212,11 @@ #define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 #define GLX_CONTEXT_FLAGS_ARB 0x2094 #endif +#ifndef GLX_ARB_create_context_profile +#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#endif /** * WGL_ATI_pixel_format_float / WGL_ARB_color_buffer_float diff --git a/include/wine/wined3d.idl b/include/wine/wined3d.idl index 2534fbbc06b..176e602bf71 100644 --- a/include/wine/wined3d.idl +++ b/include/wine/wined3d.idl @@ -3076,8 +3076,6 @@ interface IWineD3DDevice : IWineD3DBase BOOL ShowCursor( [in] BOOL show ); - HRESULT TestCooperativeLevel( - ); HRESULT SetClipPlane( [in] DWORD plane_idx, [in] const float *plane diff --git a/include/winnt.h b/include/winnt.h index a77a60768f4..222af220c34 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -296,7 +296,7 @@ extern "C" { #endif /* Eliminate Microsoft C/C++ compiler warning 4715 */ -#if (_MSC_VER > 1200) +#if defined(_MSC_VER) && (_MSC_VER > 1200) # define DEFAULT_UNREACHABLE default: __assume(0) #else # define DEFAULT_UNREACHABLE diff --git a/include/winternl.h b/include/winternl.h index 633239f17e3..6f21ad0c36b 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -407,6 +407,20 @@ typedef enum _FILE_INFORMATION_CLASS { FileNetworkOpenInformation, FileAttributeTagInformation, FileTrackingInformation, + FileIdBothDirectoryInformation, + FileIdFullDirectoryInformation, + FileValidDataLengthInformation, + FileShortNameInformation = 40, + /* 41, 42, 43 undocumented */ + FileSfioReserveInformation = 44, + FileSfioVolumeInformation = 45, + FileHardLinkInformation = 46, + /* 47 undocumented */ + FileNormalizedNameInformation = 48, + /* 49 undocumented */ + FileIdGlobalTxDirectoryInformation = 50, + /* 51, 52, 53 undocumented */ + FileStandardLinkInformation = 54, FileMaximumInformation } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; @@ -440,6 +454,22 @@ typedef struct _FILE_FULL_DIRECTORY_INFORMATION { } FILE_FULL_DIRECTORY_INFORMATION, *PFILE_FULL_DIRECTORY_INFORMATION, FILE_FULL_DIR_INFORMATION, *PFILE_FULL_DIR_INFORMATION; +typedef struct _FILE_ID_FULL_DIRECTORY_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + LARGE_INTEGER FileId; + WCHAR FileName[ANYSIZE_ARRAY]; +} FILE_ID_FULL_DIRECTORY_INFORMATION, *PFILE_ID_FULL_DIRECTORY_INFORMATION; + typedef struct _FILE_BOTH_DIRECTORY_INFORMATION { ULONG NextEntryOffset; ULONG FileIndex; @@ -458,6 +488,24 @@ typedef struct _FILE_BOTH_DIRECTORY_INFORMATION { } FILE_BOTH_DIRECTORY_INFORMATION, *PFILE_BOTH_DIRECTORY_INFORMATION, FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION; +typedef struct _FILE_ID_BOTH_DIRECTORY_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + CHAR ShortNameLength; + WCHAR ShortName[12]; + LARGE_INTEGER FileId; + WCHAR FileName[ANYSIZE_ARRAY]; +} FILE_ID_BOTH_DIRECTORY_INFORMATION, *PFILE_ID_BOTH_DIRECTORY_INFORMATION; + typedef struct _FILE_BASIC_INFORMATION { LARGE_INTEGER CreationTime; LARGE_INTEGER LastAccessTime; @@ -1622,9 +1670,7 @@ typedef struct _RTL_HANDLE_TABLE #define FILE_PIPE_SERVER_END 0x00000001 #define FILE_PIPE_CLIENT_END 0x00000000 -#if (_WIN32_WINNT >= 0x0501) #define INTERNAL_TS_ACTIVE_CONSOLE_ID ( *((volatile ULONG*)(0x7ffe02d8)) ) -#endif /* (_WIN32_WINNT >= 0x0501) */ #define LOGONID_CURRENT ((ULONG)-1) @@ -1734,7 +1780,7 @@ typedef struct _KEY_MULTIPLE_VALUE_INFORMATION typedef VOID (CALLBACK *PRTL_OVERLAPPED_COMPLETION_ROUTINE)(DWORD,DWORD,LPVOID); -typedef VOID (*PTIMER_APC_ROUTINE) ( PVOID, ULONG, LONG ); +typedef VOID (CALLBACK *PTIMER_APC_ROUTINE) ( PVOID, ULONG, LONG ); typedef enum _EVENT_TYPE { NotificationEvent, diff --git a/include/ws2def.h b/include/ws2def.h index f2f72232be9..585647b02cd 100644 --- a/include/ws2def.h +++ b/include/ws2def.h @@ -58,7 +58,7 @@ typedef struct _CSADDR_INFO { typedef struct WS(sockaddr_storage) { short ss_family; char __ss_pad1[WS(_SS_PAD1SIZE)]; - __int64 __ss_align; + __int64 DECLSPEC_ALIGN(8) __ss_align; char __ss_pad2[WS(_SS_PAD2SIZE)]; } SOCKADDR_STORAGE, *PSOCKADDR_STORAGE, *LPSOCKADDR_STORAGE; diff --git a/programs/cmd/It.rc b/programs/cmd/It.rc index d334ed1a90e..8eb2a3389e5 100644 --- a/programs/cmd/It.rc +++ b/programs/cmd/It.rc @@ -75,7 +75,7 @@ esiste nel cmd di wine.\n" file batch.\n\ \n\ L'etichetta che è l'obiettivo di un GOTO può essere lunga fino a 255 caratteri\n\ -ma non può includere spazi (questo è differente da altri sistemi \n\ +ma non può includere spazi (questo è differente da altri sistemi\n\ operativi). Se esistono due o più etichette identiche esistono in un file batch, la\n\ prima sarà sempre eseguita. Tentare un GOTO verso un'etichetta\n\ inesistente termina l'esecuzione del file batch.\n\ diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c index 7bcdd44991b..e14fe813ddc 100644 --- a/programs/winemenubuilder/winemenubuilder.c +++ b/programs/winemenubuilder/winemenubuilder.c @@ -991,8 +991,12 @@ static BOOL write_menu_file(const char *unix_link, const char *filename) struct stat st; name[i] = 0; fprintf(tempfile, " \n"); - fprintf(tempfile, " %s%s\n", count ? "" : "wine-", name); - fprintf(tempfile, " %s%s.directory\n", count ? "" : "wine-", name); + fprintf(tempfile, " %s", count ? "" : "wine-"); + write_xml_text(tempfile, name); + fprintf(tempfile, "\n"); + fprintf(tempfile, " %s", count ? "" : "wine-"); + write_xml_text(tempfile, name); + fprintf(tempfile, ".directory\n"); dir_file_name = heap_printf("%s/desktop-directories/%s%s.directory", xdg_data_dir, count ? "" : "wine-", name); if (dir_file_name) @@ -1009,7 +1013,9 @@ static BOOL write_menu_file(const char *unix_link, const char *filename) name[i] = 0; fprintf(tempfile, " \n"); - fprintf(tempfile, " %s\n", name); + fprintf(tempfile, " "); + write_xml_text(tempfile, name); + fprintf(tempfile, "\n"); fprintf(tempfile, " \n"); for (i = 0; i < count; i++) fprintf(tempfile, " \n"); diff --git a/programs/winetest/main.c b/programs/winetest/main.c index ee092e5405f..21dbaef54d3 100644 --- a/programs/winetest/main.c +++ b/programs/winetest/main.c @@ -209,6 +209,7 @@ static void print_version (void) const char *(CDECL *wine_get_build_id)(void); void (CDECL *wine_get_host_version)( const char **sysname, const char **release ); BOOL (WINAPI *pIsWow64Process)(HANDLE hProcess, PBOOL Wow64Process); + BOOL (WINAPI *pGetProductInfo)(DWORD, DWORD, DWORD, DWORD, DWORD *); ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); if (!(ext = GetVersionEx ((OSVERSIONINFO *) &ver))) @@ -247,6 +248,15 @@ static void print_version (void) " wSuiteMask=%d\n wProductType=%d\n wReserved=%d\n", ver.wServicePackMajor, ver.wServicePackMinor, ver.wSuiteMask, ver.wProductType, ver.wReserved); + + pGetProductInfo = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"),"GetProductInfo"); + if (pGetProductInfo && !running_under_wine()) + { + DWORD prodtype = 0; + + pGetProductInfo(ver.dwMajorVersion, ver.dwMinorVersion, ver.wServicePackMajor, ver.wServicePackMinor, &prodtype); + xprintf(" dwProductInfo=%u\n", prodtype); + } } static inline int is_dot_dir(const char* x) diff --git a/programs/wordpad/wordpad.c b/programs/wordpad/wordpad.c index e4e9ae03ad8..e983c5d74b7 100644 --- a/programs/wordpad/wordpad.c +++ b/programs/wordpad/wordpad.c @@ -1281,6 +1281,13 @@ static void dialog_find(LPFINDREPLACEW fr, BOOL replace) { static WCHAR findBuffer[MAX_STRING_LEN]; + /* Allow only one search/replace dialog to open */ + if(hFindWnd != NULL) + { + SetActiveWindow(hFindWnd); + return; + } + ZeroMemory(fr, sizeof(FINDREPLACEW)); fr->lStructSize = sizeof(FINDREPLACEW); fr->hwndOwner = hMainWnd; diff --git a/server/fd.c b/server/fd.c index f57ed97d3b1..9d8a06f7a5a 100644 --- a/server/fd.c +++ b/server/fd.c @@ -162,6 +162,10 @@ static inline int epoll_wait( int epfd, struct epoll_event *events, int maxevent #endif /* linux && __i386__ && HAVE_STDINT_H */ +#if defined(HAVE_PORT_H) && defined(HAVE_PORT_CREATE) +# include +# define USE_EVENT_PORTS +#endif /* HAVE_PORT_H && HAVE_PORT_CREATE */ /* Because of the stupid Posix locking semantics, we need to keep * track of all file descriptors referencing a given file, and not @@ -676,6 +680,107 @@ static inline void main_loop_epoll(void) } } +#elif defined(USE_EVENT_PORTS) + +static int port_fd = -1; + +static inline void init_epoll(void) +{ + port_fd = port_create(); +} + +static inline void set_fd_epoll_events( struct fd *fd, int user, int events ) +{ + int ret; + + if (port_fd == -1) return; + + if (events == -1) /* stop waiting on this fd completely */ + { + if (pollfd[user].fd == -1) return; /* already removed */ + port_dissociate( port_fd, PORT_SOURCE_FD, fd->unix_fd ); + } + else if (pollfd[user].fd == -1) + { + if (pollfd[user].events) return; /* stopped waiting on it, don't restart */ + ret = port_associate( port_fd, PORT_SOURCE_FD, fd->unix_fd, events, (void *)user ); + } + else + { + if (pollfd[user].events == events) return; /* nothing to do */ + ret = port_associate( port_fd, PORT_SOURCE_FD, fd->unix_fd, events, (void *)user ); + } + + if (ret == -1) + { + if (errno == ENOMEM) /* not enough memory, give up on port_associate */ + { + close( port_fd ); + port_fd = -1; + } + else perror( "port_associate" ); /* should not happen */ + } +} + +static inline void remove_epoll_user( struct fd *fd, int user ) +{ + if (port_fd == -1) return; + + if (pollfd[user].fd != -1) + { + port_dissociate( port_fd, PORT_SOURCE_FD, fd->unix_fd ); + } +} + +static inline void main_loop_epoll(void) +{ + int i, nget, ret, timeout; + port_event_t events[128]; + + if (port_fd == -1) return; + + while (active_users) + { + timeout = get_next_timeout(); + nget = 1; + + if (!active_users) break; /* last user removed by a timeout */ + if (port_fd == -1) break; /* an error occurred with event completion */ + + if (timeout != -1) + { + struct timespec ts; + + ts.tv_sec = timeout / 1000; + ts.tv_nsec = (timeout % 1000) * 1000000; + ret = port_getn( port_fd, events, sizeof(events)/sizeof(events[0]), &nget, &ts ); + } + else ret = port_getn( port_fd, events, sizeof(events)/sizeof(events[0]), &nget, NULL ); + + if (ret == -1) break; /* an error occurred with event completion */ + + set_current_time(); + + /* put the events into the pollfd array first, like poll does */ + for (i = 0; i < nget; i++) + { + long user = (long)events[i].portev_user; + pollfd[user].revents = events[i].portev_events; + } + + /* read events from the pollfd array, as set_fd_events may modify them */ + for (i = 0; i < nget; i++) + { + long user = (long)events[i].portev_user; + if (pollfd[user].revents) fd_poll_event( poll_users[user], pollfd[user].revents ); + /* if we are still interested, reassociate the fd */ + if (pollfd[user].fd != -1) { + port_associate( port_fd, PORT_SOURCE_FD, pollfd[user].fd, pollfd[user].events, (void *)user ); + } + } + } +} + #else /* HAVE_KQUEUE */ static inline void init_epoll(void) { } @@ -1488,6 +1593,59 @@ struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *use return fd; } +/* duplicate an fd object for a different user */ +struct fd *dup_fd_object( struct fd *orig, unsigned int access, unsigned int sharing, unsigned int options ) +{ + struct fd *fd = alloc_object( &fd_ops ); + + if (!fd) return NULL; + + fd->fd_ops = NULL; + fd->user = NULL; + fd->inode = NULL; + fd->closed = NULL; + fd->access = access; + fd->options = options; + fd->sharing = sharing; + fd->unix_fd = -1; + fd->signaled = 0; + fd->fs_locks = 0; + fd->poll_index = -1; + fd->read_q = NULL; + fd->write_q = NULL; + fd->wait_q = NULL; + fd->completion = NULL; + list_init( &fd->inode_entry ); + list_init( &fd->locks ); + + if (!(fd->unix_name = mem_alloc( strlen(orig->unix_name) + 1 ))) goto failed; + strcpy( fd->unix_name, orig->unix_name ); + if ((fd->poll_index = add_poll_user( fd )) == -1) goto failed; + + if (orig->inode) + { + struct closed_fd *closed = mem_alloc( sizeof(*closed) ); + if (!closed) goto failed; + if ((fd->unix_fd = dup( orig->unix_fd )) == -1) + { + free( closed ); + goto failed; + } + closed->unix_fd = fd->unix_fd; + closed->unlink[0] = 0; + fd->closed = closed; + fd->inode = (struct inode *)grab_object( orig->inode ); + list_add_head( &fd->inode->open, &fd->inode_entry ); + } + else if ((fd->unix_fd = dup( orig->unix_fd )) == -1) goto failed; + + return fd; + +failed: + release_object( fd ); + return NULL; +} + /* set the status to return when the fd has no associated unix fd */ void set_no_fd_status( struct fd *fd, unsigned int status ) { @@ -1496,14 +1654,13 @@ void set_no_fd_status( struct fd *fd, unsigned int status ) /* check if the desired access is possible without violating */ /* the sharing mode of other opens of the same file */ -static int check_sharing( struct fd *fd, unsigned int access, unsigned int sharing ) +static unsigned int check_sharing( struct fd *fd, unsigned int access, unsigned int sharing, + unsigned int open_flags, unsigned int options ) { unsigned int existing_sharing = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; unsigned int existing_access = 0; struct list *ptr; - /* if access mode is 0, sharing mode is ignored */ - if (!access) sharing = existing_sharing; fd->access = access; fd->sharing = sharing; @@ -1512,18 +1669,29 @@ static int check_sharing( struct fd *fd, unsigned int access, unsigned int shari struct fd *fd_ptr = LIST_ENTRY( ptr, struct fd, inode_entry ); if (fd_ptr != fd) { - existing_sharing &= fd_ptr->sharing; + /* if access mode is 0, sharing mode is ignored */ + if (fd_ptr->access) existing_sharing &= fd_ptr->sharing; existing_access |= fd_ptr->access; } } - if ((access & FILE_UNIX_READ_ACCESS) && !(existing_sharing & FILE_SHARE_READ)) return 0; - if ((access & FILE_UNIX_WRITE_ACCESS) && !(existing_sharing & FILE_SHARE_WRITE)) return 0; - if ((access & DELETE) && !(existing_sharing & FILE_SHARE_DELETE)) return 0; - if ((existing_access & FILE_UNIX_READ_ACCESS) && !(sharing & FILE_SHARE_READ)) return 0; - if ((existing_access & FILE_UNIX_WRITE_ACCESS) && !(sharing & FILE_SHARE_WRITE)) return 0; - if ((existing_access & DELETE) && !(sharing & FILE_SHARE_DELETE)) return 0; - return 1; + if (((access & FILE_UNIX_READ_ACCESS) && !(existing_sharing & FILE_SHARE_READ)) || + ((access & FILE_UNIX_WRITE_ACCESS) && !(existing_sharing & FILE_SHARE_WRITE)) || + ((access & DELETE) && !(existing_sharing & FILE_SHARE_DELETE))) + return STATUS_SHARING_VIOLATION; + if (((existing_access & FILE_MAPPING_WRITE) && !(sharing & FILE_SHARE_WRITE)) || + ((existing_access & FILE_MAPPING_IMAGE) && (access & FILE_SHARE_WRITE))) + return STATUS_SHARING_VIOLATION; + if ((existing_access & FILE_MAPPING_IMAGE) && (options & FILE_DELETE_ON_CLOSE)) + return STATUS_CANNOT_DELETE; + if ((existing_access & FILE_MAPPING_ACCESS) && (open_flags & O_TRUNC)) + return STATUS_USER_MAPPED_FILE; + if (!access) return 0; /* if access mode is 0, sharing mode is ignored (except for mappings) */ + if (((existing_access & FILE_UNIX_READ_ACCESS) && !(sharing & FILE_SHARE_READ)) || + ((existing_access & FILE_UNIX_WRITE_ACCESS) && !(sharing & FILE_SHARE_WRITE)) || + ((existing_access & DELETE) && !(sharing & FILE_SHARE_DELETE))) + return STATUS_SHARING_VIOLATION; + return 0; } /* sets the user of an fd that previously had no user */ @@ -1604,6 +1772,7 @@ struct fd *open_fd( const char *name, int flags, mode_t *mode, unsigned int acce /* only bother with an inode for normal files and directories */ if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) { + unsigned int err; struct inode *inode = get_inode( st.st_dev, st.st_ino, fd->unix_fd ); if (!inode) @@ -1630,10 +1799,10 @@ struct fd *open_fd( const char *name, int flags, mode_t *mode, unsigned int acce set_error( STATUS_FILE_IS_A_DIRECTORY ); return NULL; } - if (!check_sharing( fd, access, sharing )) + if ((err = check_sharing( fd, access, sharing, flags, options ))) { release_object( fd ); - set_error( STATUS_SHARING_VIOLATION ); + set_error( err ); return NULL; } strcpy( closed_fd->unlink, unlink_name ); @@ -1839,6 +2008,11 @@ void fd_reselect_async( struct fd *fd, struct async_queue *queue ) fd->fd_ops->reselect_async( fd, queue ); } +void no_fd_queue_async( struct fd *fd, const async_data_t *data, int type, int count ) +{ + set_error( STATUS_OBJECT_TYPE_MISMATCH ); +} + void default_fd_queue_async( struct fd *fd, const async_data_t *data, int type, int count ) { struct async *async; @@ -1927,6 +2101,13 @@ static void unmount_device( struct fd *device_fd ) release_object( device ); } +obj_handle_t no_fd_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async, + int blocking, const void *data, data_size_t size ) +{ + set_error( STATUS_OBJECT_TYPE_MISMATCH ); + return 0; +} + /* default ioctl() routine */ obj_handle_t default_fd_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async, int blocking, const void *data, data_size_t size ) diff --git a/server/file.c b/server/file.c index a74de140f87..c09ddc5ca99 100644 --- a/server/file.c +++ b/server/file.c @@ -115,7 +115,7 @@ static inline int is_overlapped( const struct file *file ) /* create a file from a file descriptor */ /* if the function fails the fd is closed */ -static struct file *create_file_for_fd( int fd, unsigned int access, unsigned int sharing ) +struct file *create_file_for_fd( int fd, unsigned int access, unsigned int sharing ) { struct file *file; struct stat st; @@ -226,23 +226,6 @@ int is_same_file( struct file *file1, struct file *file2 ) return is_same_file_fd( file1->fd, file2->fd ); } -/* create a temp file for anonymous mappings */ -struct file *create_temp_file( int access ) -{ - char tmpfn[16]; - int fd; - - sprintf( tmpfn, "anonmap.XXXXXX" ); /* create it in the server directory */ - fd = mkstemps( tmpfn, 0 ); - if (fd == -1) - { - file_set_error(); - return NULL; - } - unlink( tmpfn ); - return create_file_for_fd( fd, access, 0 ); -} - static void file_dump( struct object *obj, int verbose ) { struct file *file = (struct file *)obj; @@ -641,48 +624,6 @@ struct file *grab_file_unless_removable( struct file *file ) return (struct file *)grab_object( file ); } -/* extend a file beyond the current end of file */ -static int extend_file( struct file *file, file_pos_t new_size ) -{ - static const char zero; - int unix_fd = get_file_unix_fd( file ); - off_t size = new_size; - - if (unix_fd == -1) return 0; - - if (sizeof(new_size) > sizeof(size) && size != new_size) - { - set_error( STATUS_INVALID_PARAMETER ); - return 0; - } - /* extend the file one byte beyond the requested size and then truncate it */ - /* this should work around ftruncate implementations that can't extend files */ - if (pwrite( unix_fd, &zero, 1, size ) != -1) - { - ftruncate( unix_fd, size ); - return 1; - } - file_set_error(); - return 0; -} - -/* try to grow the file to the specified size */ -int grow_file( struct file *file, file_pos_t size ) -{ - struct stat st; - int unix_fd = get_file_unix_fd( file ); - - if (unix_fd == -1) return 0; - - if (fstat( unix_fd, &st ) == -1) - { - file_set_error(); - return 0; - } - if (st.st_size >= size) return 1; /* already large enough */ - return extend_file( file, size ); -} - /* create a file */ DECL_HANDLER(create_file) { diff --git a/server/file.h b/server/file.h index f59ec9e4175..a49fc4dca2d 100644 --- a/server/file.h +++ b/server/file.h @@ -58,6 +58,8 @@ extern struct fd *open_fd( const char *name, int flags, mode_t *mode, unsigned i unsigned int sharing, unsigned int options ); extern struct fd *create_anonymous_fd( const struct fd_ops *fd_user_ops, int unix_fd, struct object *user, unsigned int options ); +extern struct fd *dup_fd_object( struct fd *orig, unsigned int access, unsigned int sharing, + unsigned int options ); extern void *get_fd_user( struct fd *fd ); extern void set_fd_user( struct fd *fd, const struct fd_ops *ops, struct object *user ); extern unsigned int get_fd_options( struct fd *fd ); @@ -79,8 +81,11 @@ extern void default_poll_event( struct fd *fd, int event ); extern struct async *fd_queue_async( struct fd *fd, const async_data_t *data, int type ); extern void fd_async_wake_up( struct fd *fd, int type, unsigned int status ); extern void fd_reselect_async( struct fd *fd, struct async_queue *queue ); +extern obj_handle_t no_fd_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async, + int blocking, const void *data, data_size_t size ); extern obj_handle_t default_fd_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async, int blocking, const void *data, data_size_t size ); +extern void no_fd_queue_async( struct fd *fd, const async_data_t *data, int type, int count ); extern void default_fd_queue_async( struct fd *fd, const async_data_t *data, int type, int count ); extern void default_fd_reselect_async( struct fd *fd, struct async_queue *queue ); extern void default_fd_cancel_async( struct fd *fd, struct process *process, struct thread *thread, client_ptr_t iosb ); @@ -109,9 +114,8 @@ extern struct file *get_file_obj( struct process *process, obj_handle_t handle, unsigned int access ); extern int get_file_unix_fd( struct file *file ); extern int is_same_file( struct file *file1, struct file *file2 ); +extern struct file *create_file_for_fd( int fd, unsigned int access, unsigned int sharing ); extern struct file *grab_file_unless_removable( struct file *file ); -extern int grow_file( struct file *file, file_pos_t size ); -extern struct file *create_temp_file( int access ); extern void file_set_error(void); extern struct security_descriptor *mode_to_sd( mode_t mode, const SID *user, const SID *group ); extern mode_t sd_to_mode( const struct security_descriptor *sd, const SID *owner ); @@ -155,4 +159,9 @@ extern void fd_copy_completion( struct fd *src, struct fd *dst ); /* access rights that require Unix write permission */ #define FILE_UNIX_WRITE_ACCESS (FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES|FILE_WRITE_EA) +/* magic file access rights for mappings */ +#define FILE_MAPPING_IMAGE 0x80000000 /* set for SEC_IMAGE mappings */ +#define FILE_MAPPING_WRITE 0x40000000 /* set for writable shared mappings */ +#define FILE_MAPPING_ACCESS 0x20000000 /* set for all mappings */ + #endif /* __WINE_SERVER_FILE_H */ diff --git a/server/mapping.c b/server/mapping.c index a3031118bad..1cf53b9fe99 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -56,7 +56,7 @@ struct mapping struct object obj; /* object header */ mem_size_t size; /* mapping size */ int protect; /* protection flags */ - struct file *file; /* file mapped */ + struct fd *fd; /* fd for mapped file */ int header_size; /* size of headers (for PE image mapping) */ client_ptr_t base; /* default base addr (for PE image mapping) */ struct ranges *committed; /* list of committed ranges in this mapping */ @@ -69,6 +69,7 @@ static struct object_type *mapping_get_type( struct object *obj ); static struct fd *mapping_get_fd( struct object *obj ); static unsigned int mapping_map_access( struct object *obj, unsigned int access ); static void mapping_destroy( struct object *obj ); +static enum server_fd_type mapping_get_fd_type( struct fd *fd ); static const struct object_ops mapping_ops = { @@ -90,6 +91,18 @@ static const struct object_ops mapping_ops = mapping_destroy /* destroy */ }; +static const struct fd_ops mapping_fd_ops = +{ + default_fd_get_poll_events, /* get_poll_events */ + default_poll_event, /* poll_event */ + no_flush, /* flush */ + mapping_get_fd_type, /* get_fd_type */ + no_fd_ioctl, /* ioctl */ + no_fd_queue_async, /* queue_async */ + default_fd_reselect_async, /* reselect_async */ + default_fd_cancel_async /* cancel_async */ +}; + static struct list shared_list = LIST_INIT(shared_list); #ifdef __i386__ @@ -126,13 +139,56 @@ static void init_page_size(void) #define ROUND_SIZE(size) (((size) + page_mask) & ~page_mask) +/* extend a file beyond the current end of file */ +static int grow_file( int unix_fd, file_pos_t new_size ) +{ + static const char zero; + off_t size = new_size; + + if (sizeof(new_size) > sizeof(size) && size != new_size) + { + set_error( STATUS_INVALID_PARAMETER ); + return 0; + } + /* extend the file one byte beyond the requested size and then truncate it */ + /* this should work around ftruncate implementations that can't extend files */ + if (pwrite( unix_fd, &zero, 1, size ) != -1) + { + ftruncate( unix_fd, size ); + return 1; + } + file_set_error(); + return 0; +} + +/* create a temp file for anonymous mappings */ +static int create_temp_file( file_pos_t size ) +{ + char tmpfn[16]; + int fd; + + sprintf( tmpfn, "anonmap.XXXXXX" ); /* create it in the server directory */ + fd = mkstemps( tmpfn, 0 ); + if (fd != -1) + { + if (!grow_file( fd, size )) + { + close( fd ); + fd = -1; + } + unlink( tmpfn ); + } + else file_set_error(); + return fd; +} + /* find the shared PE mapping for a given mapping */ static struct file *get_shared_file( struct mapping *mapping ) { struct mapping *ptr; LIST_FOR_EACH_ENTRY( ptr, &shared_list, struct mapping, shared_entry ) - if (is_same_file( ptr->file, mapping->file )) + if (is_same_file_fd( ptr->fd, mapping->fd )) return (struct file *)grab_object( ptr->shared_file ); return NULL; } @@ -257,9 +313,9 @@ static int build_shared_mapping( struct mapping *mapping, int fd, /* create a temp file for the mapping */ - if (!(mapping->shared_file = create_temp_file( FILE_GENERIC_READ|FILE_GENERIC_WRITE ))) return 0; - if (!grow_file( mapping->shared_file, total_size )) goto error; - if ((shared_fd = get_file_unix_fd( mapping->shared_file )) == -1) goto error; + if ((shared_fd = create_temp_file( total_size )) == -1) return 0; + if (!(mapping->shared_file = create_file_for_fd( shared_fd, FILE_GENERIC_READ|FILE_GENERIC_WRITE, 0 ))) + return 0; if (!(buffer = malloc( max_size ))) goto error; @@ -300,7 +356,7 @@ static int build_shared_mapping( struct mapping *mapping, int fd, } /* retrieve the mapping parameters for an executable (PE) image */ -static int get_image_params( struct mapping *mapping ) +static int get_image_params( struct mapping *mapping, int unix_fd ) { IMAGE_DOS_HEADER dos; IMAGE_SECTION_HEADER *sec = NULL; @@ -314,14 +370,11 @@ static int get_image_params( struct mapping *mapping ) IMAGE_OPTIONAL_HEADER64 hdr64; } opt; } nt; - struct fd *fd; off_t pos; - int unix_fd, size; + int size; /* load the headers */ - if (!(fd = mapping_get_fd( &mapping->obj ))) return 0; - if ((unix_fd = get_unix_fd( fd )) == -1) goto error; if (pread( unix_fd, &dos, sizeof(dos), 0 ) != sizeof(dos)) goto error; if (dos.e_magic != IMAGE_DOS_SIGNATURE) goto error; pos = dos.e_lfanew; @@ -363,33 +416,24 @@ static int get_image_params( struct mapping *mapping ) mapping->protect = VPROT_IMAGE; free( sec ); - release_object( fd ); return 1; error: free( sec ); - release_object( fd ); set_error( STATUS_INVALID_FILE_FOR_SECTION ); return 0; } -/* get the size of the unix file associated with the mapping */ -static inline int get_file_size( struct file *file, mem_size_t *size ) -{ - struct stat st; - int unix_fd = get_file_unix_fd( file ); - - if (unix_fd == -1 || fstat( unix_fd, &st ) == -1) return 0; - *size = st.st_size; - return 1; -} - static struct object *create_mapping( struct directory *root, const struct unicode_str *name, unsigned int attr, mem_size_t size, int protect, obj_handle_t handle, const struct security_descriptor *sd ) { struct mapping *mapping; + struct file *file; + struct fd *fd; int access = 0; + int unix_fd; + struct stat st; if (!page_mask) init_page_size(); @@ -404,7 +448,7 @@ static struct object *create_mapping( struct directory *root, const struct unico SACL_SECURITY_INFORMATION ); mapping->header_size = 0; mapping->base = 0; - mapping->file = NULL; + mapping->fd = NULL; mapping->shared_file = NULL; mapping->committed = NULL; @@ -413,30 +457,47 @@ static struct object *create_mapping( struct directory *root, const struct unico if (handle) { + unsigned int mapping_access = FILE_MAPPING_ACCESS; + if (!(protect & VPROT_COMMITTED)) { set_error( STATUS_INVALID_PARAMETER ); goto error; } - if (!(mapping->file = get_file_obj( current->process, handle, access ))) goto error; + if (!(file = get_file_obj( current->process, handle, access ))) goto error; + fd = get_obj_fd( (struct object *)file ); + + /* file sharing rules for mappings are different so we use magic the access rights */ + if (protect & VPROT_IMAGE) mapping_access |= FILE_MAPPING_IMAGE; + else if (protect & VPROT_WRITE) mapping_access |= FILE_MAPPING_WRITE; + mapping->fd = dup_fd_object( fd, mapping_access, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_SYNCHRONOUS_IO_NONALERT ); + release_object( file ); + release_object( fd ); + if (!mapping->fd) goto error; + + set_fd_user( mapping->fd, &mapping_fd_ops, &mapping->obj ); + if ((unix_fd = get_unix_fd( mapping->fd )) == -1) goto error; if (protect & VPROT_IMAGE) { - if (!get_image_params( mapping )) goto error; + if (!get_image_params( mapping, unix_fd )) goto error; return &mapping->obj; } + if (fstat( unix_fd, &st ) == -1) + { + file_set_error(); + goto error; + } if (!size) { - if (!get_file_size( mapping->file, &size )) goto error; - if (!size) + if (!(size = st.st_size)) { set_error( STATUS_MAPPED_FILE_SIZE_ZERO ); goto error; } } - else - { - if (!grow_file( mapping->file, size )) goto error; - } + else if (st.st_size < size && !grow_file( unix_fd, size )) goto error; } else /* Anonymous mapping (no associated file) */ { @@ -451,8 +512,9 @@ static struct object *create_mapping( struct directory *root, const struct unico mapping->committed->count = 0; mapping->committed->max = 8; } - if (!(mapping->file = create_temp_file( access ))) goto error; - if (!grow_file( mapping->file, size )) goto error; + if ((unix_fd = create_temp_file( size )) == -1) goto error; + if (!(mapping->fd = create_anonymous_fd( &mapping_fd_ops, unix_fd, &mapping->obj, + FILE_SYNCHRONOUS_IO_NONALERT ))) goto error; } mapping->size = (size + page_mask) & ~((mem_size_t)page_mask); mapping->protect = protect; @@ -467,10 +529,10 @@ static void mapping_dump( struct object *obj, int verbose ) { struct mapping *mapping = (struct mapping *)obj; assert( obj->ops == &mapping_ops ); - fprintf( stderr, "Mapping size=%08x%08x prot=%08x file=%p header_size=%08x base=%08lx " + fprintf( stderr, "Mapping size=%08x%08x prot=%08x fd=%p header_size=%08x base=%08lx " "shared_file=%p ", (unsigned int)(mapping->size >> 32), (unsigned int)mapping->size, - mapping->protect, mapping->file, mapping->header_size, + mapping->protect, mapping->fd, mapping->header_size, (unsigned long)mapping->base, mapping->shared_file ); dump_object_name( &mapping->obj ); fputc( '\n', stderr ); @@ -486,7 +548,7 @@ static struct object_type *mapping_get_type( struct object *obj ) static struct fd *mapping_get_fd( struct object *obj ) { struct mapping *mapping = (struct mapping *)obj; - return get_obj_fd( (struct object *)mapping->file ); + return (struct fd *)grab_object( mapping->fd ); } static unsigned int mapping_map_access( struct object *obj, unsigned int access ) @@ -502,7 +564,7 @@ static void mapping_destroy( struct object *obj ) { struct mapping *mapping = (struct mapping *)obj; assert( obj->ops == &mapping_ops ); - if (mapping->file) release_object( mapping->file ); + if (mapping->fd) release_object( mapping->fd ); if (mapping->shared_file) { release_object( mapping->shared_file ); @@ -511,6 +573,11 @@ static void mapping_destroy( struct object *obj ) free( mapping->committed ); } +static enum server_fd_type mapping_get_fd_type( struct fd *fd ) +{ + return FD_TYPE_FILE; +} + int get_page_size(void) { if (!page_mask) init_page_size(); diff --git a/server/protocol.def b/server/protocol.def index ca44e380a6a..bba6788da3d 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2924,18 +2924,19 @@ enum message_type VARARG(privileges,LUID_AND_ATTRIBUTES); /* privileges used during access check */ @END -@REQ(get_token_user) +@REQ(get_token_sid) obj_handle_t handle; /* handle to the token */ + unsigned int which_sid; /* which SID to retrieve from the token */ @REPLY - data_size_t user_len; /* length needed to store user */ - VARARG(user,SID); /* sid of the user the token represents */ + data_size_t sid_len; /* length needed to store sid */ + VARARG(sid,SID); /* the sid specified by which_sid from the token */ @END @REQ(get_token_groups) obj_handle_t handle; /* handle to the token */ @REPLY data_size_t user_len; /* length needed to store user */ - VARARG(user,token_groups); /* groups the token's user belongs to */ + VARARG(user,token_groups); /* groups the token's user belongs to */ @END @REQ(get_token_default_dacl) diff --git a/server/registry.c b/server/registry.c index d83486b8d1b..afdffed04f4 100644 --- a/server/registry.c +++ b/server/registry.c @@ -612,11 +612,6 @@ static struct key *create_key( struct key *key, const struct unicode_str *name, set_error( STATUS_KEY_DELETED ); return NULL; } - if (!(flags & KEY_VOLATILE) && (key->flags & KEY_VOLATILE)) - { - set_error( STATUS_CHILD_MUST_BE_VOLATILE ); - return NULL; - } token.str = NULL; if (!get_path_token( name, &token )) return NULL; @@ -632,6 +627,11 @@ static struct key *create_key( struct key *key, const struct unicode_str *name, /* create the remaining part */ if (!token.len) goto done; + if (!(flags & KEY_VOLATILE) && (key->flags & KEY_VOLATILE)) + { + set_error( STATUS_CHILD_MUST_BE_VOLATILE ); + return NULL; + } *created = 1; if (flags & KEY_DIRTY) make_dirty( key ); if (!(key = alloc_subkey( key, &token, index, modif ))) return NULL; @@ -1257,7 +1257,6 @@ static int load_value( struct key *key, const char *buffer, struct file_load_inf value->data = newptr; value->len = len; value->type = type; - make_dirty( key ); return 1; error: @@ -1266,7 +1265,6 @@ static int load_value( struct key *key, const char *buffer, struct file_load_inf value->data = NULL; value->len = 0; value->type = REG_NONE; - make_dirty( key ); return 0; } @@ -1304,7 +1302,6 @@ static void load_keys( struct key *key, const char *filename, FILE *f, int prefi struct key *subkey = NULL; struct file_load_info info; char *p; - int flags = (key->flags & KEY_VOLATILE) ? KEY_VOLATILE : KEY_DIRTY; info.filename = filename; info.file = f; @@ -1334,7 +1331,7 @@ static void load_keys( struct key *key, const char *filename, FILE *f, int prefi case '[': /* new key */ if (subkey) release_object( subkey ); if (prefix_len == -1) prefix_len = get_prefix_len( key, p + 1, &info ); - if (!(subkey = load_key( key, p + 1, flags, prefix_len, &info ))) + if (!(subkey = load_key( key, p + 1, key->flags, prefix_len, &info ))) file_read_error( "Error creating key", &info ); break; case '@': /* default value */ diff --git a/server/request.h b/server/request.h index 8aa8a9d246a..ca5fc88ed30 100644 --- a/server/request.h +++ b/server/request.h @@ -317,7 +317,7 @@ DECL_HANDLER(get_token_privileges); DECL_HANDLER(check_token_privileges); DECL_HANDLER(duplicate_token); DECL_HANDLER(access_check); -DECL_HANDLER(get_token_user); +DECL_HANDLER(get_token_sid); DECL_HANDLER(get_token_groups); DECL_HANDLER(get_token_default_dacl); DECL_HANDLER(set_token_default_dacl); @@ -564,7 +564,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_check_token_privileges, (req_handler)req_duplicate_token, (req_handler)req_access_check, - (req_handler)req_get_token_user, + (req_handler)req_get_token_sid, (req_handler)req_get_token_groups, (req_handler)req_get_token_default_dacl, (req_handler)req_set_token_default_dacl, @@ -1755,9 +1755,10 @@ C_ASSERT( FIELD_OFFSET(struct access_check_reply, access_granted) == 8 ); C_ASSERT( FIELD_OFFSET(struct access_check_reply, access_status) == 12 ); C_ASSERT( FIELD_OFFSET(struct access_check_reply, privileges_len) == 16 ); C_ASSERT( sizeof(struct access_check_reply) == 24 ); -C_ASSERT( FIELD_OFFSET(struct get_token_user_request, handle) == 12 ); -C_ASSERT( FIELD_OFFSET(struct get_token_user_reply, user_len) == 8 ); -C_ASSERT( sizeof(struct get_token_user_reply) == 16 ); +C_ASSERT( FIELD_OFFSET(struct get_token_sid_request, handle) == 12 ); +C_ASSERT( FIELD_OFFSET(struct get_token_sid_request, which_sid) == 16 ); +C_ASSERT( FIELD_OFFSET(struct get_token_sid_reply, sid_len) == 8 ); +C_ASSERT( sizeof(struct get_token_sid_reply) == 16 ); C_ASSERT( FIELD_OFFSET(struct get_token_groups_request, handle) == 12 ); C_ASSERT( FIELD_OFFSET(struct get_token_groups_reply, user_len) == 8 ); C_ASSERT( sizeof(struct get_token_groups_reply) == 16 ); diff --git a/server/thread.c b/server/thread.c index f45be2436b1..b50193addb2 100644 --- a/server/thread.c +++ b/server/thread.c @@ -415,7 +415,7 @@ void set_thread_affinity( struct thread *thread, affinity_t affinity ) return; } #ifdef HAVE_SCHED_SETAFFINITY - if (thread->unix_pid != -1) + if (thread->unix_tid != -1) { cpu_set_t set; int i; @@ -425,7 +425,7 @@ void set_thread_affinity( struct thread *thread, affinity_t affinity ) for (i = 0, mask = 1; mask; i++, mask <<= 1) if (affinity & mask) CPU_SET( i, &set ); - if (!sched_setaffinity( thread->unix_pid, sizeof(set), &set )) + if (!sched_setaffinity( thread->unix_tid, sizeof(set), &set )) thread->affinity = affinity; else file_set_error(); diff --git a/server/token.c b/server/token.c index ce896ac17dc..4c45d50ac77 100644 --- a/server/token.c +++ b/server/token.c @@ -1225,27 +1225,51 @@ DECL_HANDLER(access_check) } /* retrieves the SID of the user that the token represents */ -DECL_HANDLER(get_token_user) +DECL_HANDLER(get_token_sid) { struct token *token; - reply->user_len = 0; + reply->sid_len = 0; if ((token = (struct token *)get_handle_obj( current->process, req->handle, TOKEN_QUERY, &token_ops ))) { - const SID *user = token->user; + const SID *sid = NULL; - reply->user_len = FIELD_OFFSET(SID, SubAuthority[user->SubAuthorityCount]); - if (reply->user_len <= get_reply_max_size()) + switch (req->which_sid) + { + case TokenUser: + assert(token->user); + sid = token->user; + break; + case TokenPrimaryGroup: + sid = token->primary_group; + break; + case TokenOwner: { - SID *user_reply = set_reply_data_size( reply->user_len ); - if (user_reply) - memcpy( user_reply, user, reply->user_len ); + struct group *group; + LIST_FOR_EACH_ENTRY( group, &token->groups, struct group, entry ) + { + if (group->owner) + { + sid = &group->sid; + break; + } + } + break; + } + default: + set_error( STATUS_INVALID_PARAMETER ); + break; } - else set_error( STATUS_BUFFER_TOO_SMALL ); + if (sid) + { + reply->sid_len = FIELD_OFFSET(SID, SubAuthority[sid->SubAuthorityCount]); + if (reply->sid_len <= get_reply_max_size()) set_reply_data( sid, reply->sid_len ); + else set_error( STATUS_BUFFER_TOO_SMALL ); + } release_object( token ); } } diff --git a/server/trace.c b/server/trace.c index a529e5bf9f7..6cb4cc950c4 100644 --- a/server/trace.c +++ b/server/trace.c @@ -3426,15 +3426,16 @@ static void dump_access_check_reply( const struct access_check_reply *req ) dump_varargs_LUID_AND_ATTRIBUTES( ", privileges=", cur_size ); } -static void dump_get_token_user_request( const struct get_token_user_request *req ) +static void dump_get_token_sid_request( const struct get_token_sid_request *req ) { fprintf( stderr, " handle=%04x", req->handle ); + fprintf( stderr, ", which_sid=%08x", req->which_sid ); } -static void dump_get_token_user_reply( const struct get_token_user_reply *req ) +static void dump_get_token_sid_reply( const struct get_token_sid_reply *req ) { - fprintf( stderr, " user_len=%u", req->user_len ); - dump_varargs_SID( ", user=", cur_size ); + fprintf( stderr, " sid_len=%u", req->sid_len ); + dump_varargs_SID( ", sid=", cur_size ); } static void dump_get_token_groups_request( const struct get_token_groups_request *req ) @@ -4012,7 +4013,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_check_token_privileges_request, (dump_func)dump_duplicate_token_request, (dump_func)dump_access_check_request, - (dump_func)dump_get_token_user_request, + (dump_func)dump_get_token_sid_request, (dump_func)dump_get_token_groups_request, (dump_func)dump_get_token_default_dacl_request, (dump_func)dump_set_token_default_dacl_request, @@ -4256,7 +4257,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_check_token_privileges_reply, (dump_func)dump_duplicate_token_reply, (dump_func)dump_access_check_reply, - (dump_func)dump_get_token_user_reply, + (dump_func)dump_get_token_sid_reply, (dump_func)dump_get_token_groups_reply, (dump_func)dump_get_token_default_dacl_reply, NULL, @@ -4500,7 +4501,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "check_token_privileges", "duplicate_token", "access_check", - "get_token_user", + "get_token_sid", "get_token_groups", "get_token_default_dacl", "set_token_default_dacl", @@ -4554,6 +4555,7 @@ static const struct { "BUFFER_OVERFLOW", STATUS_BUFFER_OVERFLOW }, { "BUFFER_TOO_SMALL", STATUS_BUFFER_TOO_SMALL }, { "CANCELLED", STATUS_CANCELLED }, + { "CANNOT_DELETE", STATUS_CANNOT_DELETE }, { "CANT_OPEN_ANONYMOUS", STATUS_CANT_OPEN_ANONYMOUS }, { "CHILD_MUST_BE_VOLATILE", STATUS_CHILD_MUST_BE_VOLATILE }, { "DEBUGGER_INACTIVE", STATUS_DEBUGGER_INACTIVE }, @@ -4628,6 +4630,7 @@ static const struct { "TOO_MANY_OPENED_FILES", STATUS_TOO_MANY_OPENED_FILES }, { "UNSUCCESSFUL", STATUS_UNSUCCESSFUL }, { "USER_APC", STATUS_USER_APC }, + { "USER_MAPPED_FILE", STATUS_USER_MAPPED_FILE }, { "VOLUME_DISMOUNTED", STATUS_VOLUME_DISMOUNTED }, { "WAS_LOCKED", STATUS_WAS_LOCKED }, { NULL, 0 } diff --git a/tools/widl/header.c b/tools/widl/header.c index e87a44e9077..c8b9613028a 100644 --- a/tools/widl/header.c +++ b/tools/widl/header.c @@ -254,6 +254,7 @@ void write_type_left(FILE *h, type_t *t, int declonly) break; case TYPE_BASIC: if (type_basic_get_type(t) != TYPE_BASIC_INT32 && + type_basic_get_type(t) != TYPE_BASIC_INT64 && type_basic_get_type(t) != TYPE_BASIC_HYPER) { if (type_basic_get_sign(t) < 0) fprintf(h, "signed "); @@ -264,7 +265,6 @@ void write_type_left(FILE *h, type_t *t, int declonly) case TYPE_BASIC_INT8: fprintf(h, "small"); break; case TYPE_BASIC_INT16: fprintf(h, "short"); break; case TYPE_BASIC_INT: fprintf(h, "int"); break; - case TYPE_BASIC_INT64: fprintf(h, "__int64"); break; case TYPE_BASIC_INT3264: fprintf(h, "__int3264"); break; case TYPE_BASIC_BYTE: fprintf(h, "byte"); break; case TYPE_BASIC_CHAR: fprintf(h, "char"); break; @@ -279,6 +279,12 @@ void write_type_left(FILE *h, type_t *t, int declonly) else fprintf(h, "LONG"); break; + case TYPE_BASIC_INT64: + if (type_basic_get_sign(t) > 0) + fprintf(h, "UINT64"); + else + fprintf(h, "INT64"); + break; case TYPE_BASIC_HYPER: if (type_basic_get_sign(t) > 0) fprintf(h, "MIDL_uhyper"); diff --git a/tools/widl/parser.y b/tools/widl/parser.y index de44ab5626f..73b48a20a15 100644 --- a/tools/widl/parser.y +++ b/tools/widl/parser.y @@ -1033,7 +1033,7 @@ m_bitfield: { $$ = NULL; } struct_declarator: any_declarator m_bitfield { $$ = $1; $$->bits = $2; if (!$$->bits && !$$->var->name) - error_loc("unnamed fields are not allowed"); + error_loc("unnamed fields are not allowed\n"); } ; diff --git a/tools/widl/typegen.c b/tools/widl/typegen.c index fdb2379a070..68e9da1ebc7 100644 --- a/tools/widl/typegen.c +++ b/tools/widl/typegen.c @@ -3298,7 +3298,7 @@ void print_phase_basetype(FILE *file, int indent, const char *local_var_prefix, size = 0; } - if (phase == PHASE_MARSHAL) + if (phase == PHASE_MARSHAL && alignment > 1) print_file(file, indent, "MIDL_memset(__frame->_StubMsg.Buffer, 0, (0x%x - (ULONG_PTR)__frame->_StubMsg.Buffer) & 0x%x);\n", alignment, alignment - 1); print_file(file, indent, "__frame->_StubMsg.Buffer = (unsigned char *)(((ULONG_PTR)__frame->_StubMsg.Buffer + %u) & ~0x%x);\n", alignment - 1, alignment - 1); diff --git a/tools/wine.inf.in b/tools/wine.inf.in index 6022e8828e4..f676898f3af 100644 --- a/tools/wine.inf.in +++ b/tools/wine.inf.in @@ -456,7 +456,7 @@ HKLM,Software\Microsoft\DirectPlay\Service Providers\Serial Connection For Direc HKLM,System\CurrentControlSet\Control\Session Manager\Environment,"APPDATA",,"%16410%" HKLM,System\CurrentControlSet\Control\Session Manager\Environment,"ComSpec",0x00020000,"%11%\cmd.exe" HKLM,System\CurrentControlSet\Control\Session Manager\Environment,"LOCALAPPDATA",,"%16412%" -HKLM,System\CurrentControlSet\Control\Session Manager\Environment,"PATH",0x00020002,"%11%;%10%" +HKLM,System\CurrentControlSet\Control\Session Manager\Environment,"PATH",0x00020002,"%11%;%10%;%11%\wbem" HKLM,System\CurrentControlSet\Control\Session Manager\Environment,"ProgramFiles",,"%16422%" HKLM,System\CurrentControlSet\Control\Session Manager\Environment,"SystemDrive",2,"c:" HKLM,System\CurrentControlSet\Control\Session Manager\Environment,"SYSTEMROOT",,"%10%" @@ -540,8 +540,6 @@ HKLM,System\CurrentControlSet\Control\Session Manager,,,"" HKLM,System\CurrentControlSet\Control\VMM32Files,,,"" HKCU,AppEvents\Schemes\Apps\Explorer\Navigating\.Current,,,"" HKCU,Software\Microsoft\Protected Storage System Provider,,,"" -HKLM,HARDWARE\DEVICEMAP\PARALLEL PORTS,,,"" -HKLM,HARDWARE\DEVICEMAP\SERIALCOMM,,,"" ; Some apps requires at least four subkeys of Active Setup\Installed Components HKLM,SOFTWARE\Microsoft\Active Setup\Installed Components\{44BBA855-CC51-11CF-AAFA-00AA00B6015F},,2,"DirectDrawEx" HKLM,SOFTWARE\Microsoft\Active Setup\Installed Components\{44BBA855-CC51-11CF-AAFA-00AA00B6015F},"ComponentID",2,"DirectDrawEx" @@ -2423,6 +2421,7 @@ HKLM,%CurrentVersion%\Telephony\Country List\998,"SameAreaRule",,"G" 11,mui, 11,spool\drivers\color, 11,spool\printers, +11,wbem, 10,,explorer.exe 10,,hh.exe 10,,notepad.exe diff --git a/tools/winebuild/build.h b/tools/winebuild/build.h index b942934aedf..e47278acc4c 100644 --- a/tools/winebuild/build.h +++ b/tools/winebuild/build.h @@ -119,7 +119,7 @@ typedef struct enum target_cpu { - CPU_x86, CPU_x86_64, CPU_SPARC, CPU_ALPHA, CPU_POWERPC + CPU_x86, CPU_x86_64, CPU_SPARC, CPU_ALPHA, CPU_POWERPC, CPU_ARM, CPU_LAST = CPU_ARM }; enum target_platform @@ -148,7 +148,7 @@ extern enum target_platform target_platform; #define FLAG_EXT_LINK 0x200 /* function links to an external symbol */ #define FLAG_CPU(cpu) (0x01000 << (cpu)) -#define FLAG_CPU_MASK 0x1f000 +#define FLAG_CPU_MASK (FLAG_CPU(CPU_LAST + 1) - FLAG_CPU(0)) #define FLAG_CPU_WIN64 (FLAG_CPU(CPU_x86_64)) #define FLAG_CPU_WIN32 (FLAG_CPU_MASK & ~FLAG_CPU_WIN64) diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c index bb9d6d1d27c..d41a754ac41 100644 --- a/tools/winebuild/import.c +++ b/tools/winebuild/import.c @@ -699,6 +699,10 @@ static void output_import_thunk( const char *name, const char *table, int pos ) output( "\tlda $0,%d($0)\n", pos ); output( "\tjmp $31,($0)\n" ); break; + case CPU_ARM: + output( "\tmov r4, #%s\n", table ); + output( "\tldr r15, [r4, #%d]\n", pos ); + break; case CPU_POWERPC: output( "\tmr %s, %s\n", ppc_reg(0), ppc_reg(31) ); if (target_platform == PLATFORM_APPLE) @@ -1005,6 +1009,11 @@ static void output_delayed_import_thunks( const DLLSPEC *spec ) output( "\tjsr $26,%s\n", asm_name("__wine_spec_delay_load") ); output( "\tjmp $31,($0)\n" ); break; + case CPU_ARM: + output( "\tstmfd sp!, {r4, r5, r6, r7, r8, r9, r10, lr}\n" ); + output( "\tblx %s\n", asm_name("__wine_spec_delay_load") ); + output( "\tldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, pc}\n" ); + break; case CPU_POWERPC: if (target_platform == PLATFORM_APPLE) extra_stack_storage = 56; @@ -1088,6 +1097,9 @@ static void output_delayed_import_thunks( const DLLSPEC *spec ) output( "\tldah $0,%d($0)\n", idx); output( "\tjmp $31,%s\n", asm_name("__wine_delay_load_asm") ); break; + case CPU_ARM: + output( "\tb %s\n", asm_name("__wine_delay_load_asm") ); + break; case CPU_POWERPC: switch(target_platform) { diff --git a/tools/winebuild/main.c b/tools/winebuild/main.c index 4dfa63f08a5..14c168994b2 100644 --- a/tools/winebuild/main.c +++ b/tools/winebuild/main.c @@ -58,6 +58,8 @@ enum target_cpu target_cpu = CPU_SPARC; enum target_cpu target_cpu = CPU_ALPHA; #elif defined(__powerpc__) enum target_cpu target_cpu = CPU_POWERPC; +#elif defined(__arm__) +enum target_cpu target_cpu = CPU_ARM; #else #error Unsupported CPU #endif diff --git a/tools/winebuild/spec32.c b/tools/winebuild/spec32.c index 09e69f575a1..c2b11af8474 100644 --- a/tools/winebuild/spec32.c +++ b/tools/winebuild/spec32.c @@ -37,6 +37,7 @@ #define IMAGE_FILE_MACHINE_ALPHA 0x0184 #define IMAGE_FILE_MACHINE_POWERPC 0x01f0 #define IMAGE_FILE_MACHINE_AMD64 0x8664 +#define IMAGE_FILE_MACHINE_ARM 0x01C0 #define IMAGE_SIZEOF_NT_OPTIONAL32_HEADER 224 #define IMAGE_SIZEOF_NT_OPTIONAL64_HEADER 240 @@ -369,6 +370,9 @@ static void output_asm_constructor( const char *constructor ) case CPU_ALPHA: output( "\tjsr $26,%s\n", asm_name(constructor) ); break; + case CPU_ARM: + output( "\tblx %s\n", asm_name(constructor) ); + break; case CPU_POWERPC: output( "\tbl %s\n", asm_name(constructor) ); break; @@ -412,6 +416,7 @@ void output_module( DLLSPEC *spec ) case CPU_SPARC: output( "\tjmp 1f\n" ); break; + case CPU_ARM: case CPU_POWERPC: output( "\tb 1f\n" ); break; @@ -434,6 +439,7 @@ void output_module( DLLSPEC *spec ) { case CPU_x86: machine = IMAGE_FILE_MACHINE_I386; break; case CPU_x86_64: machine = IMAGE_FILE_MACHINE_AMD64; break; + case CPU_ARM: machine = IMAGE_FILE_MACHINE_ARM; break; case CPU_POWERPC: machine = IMAGE_FILE_MACHINE_POWERPC; break; case CPU_ALPHA: machine = IMAGE_FILE_MACHINE_ALPHA; break; case CPU_SPARC: machine = IMAGE_FILE_MACHINE_UNKNOWN; break; @@ -623,6 +629,7 @@ void output_fake_module( DLLSPEC *spec ) case CPU_POWERPC: put_word( IMAGE_FILE_MACHINE_POWERPC ); break; case CPU_ALPHA: put_word( IMAGE_FILE_MACHINE_ALPHA ); break; case CPU_SPARC: put_word( IMAGE_FILE_MACHINE_UNKNOWN ); break; + case CPU_ARM: put_word( IMAGE_FILE_MACHINE_ARM ); break; } put_word( nb_sections ); /* NumberOfSections */ put_dword( 0 ); /* TimeDateStamp */ diff --git a/tools/winebuild/utils.c b/tools/winebuild/utils.c index bbf23f4dd95..c0b93710e6c 100644 --- a/tools/winebuild/utils.c +++ b/tools/winebuild/utils.c @@ -57,7 +57,8 @@ static const struct { "x86_64", CPU_x86_64 }, { "sparc", CPU_SPARC }, { "alpha", CPU_ALPHA }, - { "powerpc", CPU_POWERPC } + { "powerpc", CPU_POWERPC }, + { "arm", CPU_ARM } }; /* atexit handler to clean tmp files */ @@ -795,6 +796,7 @@ unsigned int get_alignment(unsigned int align) case CPU_x86: case CPU_x86_64: case CPU_SPARC: + case CPU_ARM: if (target_platform != PLATFORM_APPLE) return align; /* fall through */ case CPU_POWERPC: @@ -816,6 +818,7 @@ unsigned int get_page_size(void) case CPU_x86: return 4096; case CPU_x86_64: return 4096; case CPU_POWERPC: return 4096; + case CPU_ARM: return 4096; case CPU_SPARC: return 8192; case CPU_ALPHA: return 8192; } @@ -833,6 +836,7 @@ unsigned int get_ptr_size(void) case CPU_POWERPC: case CPU_SPARC: case CPU_ALPHA: + case CPU_ARM: return 4; case CPU_x86_64: return 8; @@ -873,7 +877,15 @@ const char *func_declaration( const char *func ) sprintf( buffer, ".def _%s; .scl 2; .type 32; .endef", func ); break; default: - sprintf( buffer, ".type %s,@function", func ); + switch(target_cpu) + { + case CPU_ARM: + sprintf( buffer, ".type %s,%%function", func ); + break; + default: + sprintf( buffer, ".type %s,@function", func ); + break; + } break; } return buffer; @@ -902,7 +914,15 @@ void output_gnu_stack_note(void) case PLATFORM_APPLE: break; default: - output( "\t.section .note.GNU-stack,\"\",@progbits\n" ); + switch(target_cpu) + { + case CPU_ARM: + output( "\t.section .note.GNU-stack,\"\",%%progbits\n" ); + break; + default: + output( "\t.section .note.GNU-stack,\"\",@progbits\n" ); + break; + } break; } } diff --git a/tools/winedump/minidump.c b/tools/winedump/minidump.c index 76aaa582cd6..2ea4c544523 100644 --- a/tools/winedump/minidump.c +++ b/tools/winedump/minidump.c @@ -284,6 +284,9 @@ void mdmp_dump(void) case PROCESSOR_ARCHITECTURE_PPC: str = "PowerPC"; break; + case PROCESSOR_ARCHITECTURE_ARM: + str = "ARM"; + break; default: str = "???"; break; diff --git a/tools/winedump/pe.c b/tools/winedump/pe.c index 077109d28f0..9761215e951 100644 --- a/tools/winedump/pe.c +++ b/tools/winedump/pe.c @@ -61,6 +61,7 @@ const char *get_machine_str(int mach) case IMAGE_FILE_MACHINE_POWERPC: return "PowerPC"; case IMAGE_FILE_MACHINE_AMD64: return "AMD64"; case IMAGE_FILE_MACHINE_IA64: return "IA64"; + case IMAGE_FILE_MACHINE_ARM: return "ARM"; } return "???"; } diff --git a/tools/winemaker b/tools/winemaker index e077db282e0..4cd46ff3ac4 100755 --- a/tools/winemaker +++ b/tools/winemaker @@ -582,6 +582,7 @@ sub source_scan_project_file($$$) if (/^\# Microsoft Developer Studio Project File - Name=\"([^\"]+)/) { $prj_name="$1"; + $prj_name=~s/\s+/_/g; #print $prj_name; next; } elsif (/^# TARGTYPE/) { @@ -852,6 +853,7 @@ sub source_scan_project_file($$$) foreach my $vc_project_attr ($vc_project->attributes) { if ($vc_project_attr->getName eq "Name") { $prj_name=$vc_project_attr->getValue; + $prj_name=~s/\s+/_/g; last; } } -- 2.11.4.GIT