From bab15316a23f12aa0550b72b128885fd83be269d Mon Sep 17 00:00:00 2001 From: Jan Zerebecki Date: Mon, 21 May 2007 02:07:43 +0200 Subject: [PATCH] push 3f945e9775023a88a9fe5158a41ae6d84ee66613 --- .gitignore | 3 + Makefile.in | 2 + configure | 3 + configure.ac | 1 + dlls/advapi32/service.c | 47 ++- dlls/comctl32/imagelist.c | 9 +- dlls/dbghelp/elf_module.c | 4 +- dlls/kernel32/instr.c | 6 +- dlls/kernel32/kernel32.spec | 1 + dlls/kernel32/kernel_private.h | 2 +- dlls/kernel32/module.c | 40 ++- dlls/kernel32/tests/codepage.c | 43 +-- dlls/kernel32/tests/loader.c | 4 +- dlls/kernel32/wowthunk.c | 4 +- dlls/msi/automation.c | 588 +++++++++++++++++++++++++----------- dlls/msi/msi.c | 6 +- dlls/msi/msiserver.idl | 10 +- dlls/msi/msiserver_dispids.h | 6 +- dlls/msi/script.c | 114 +++---- dlls/msi/tests/automation.c | 374 ++++++++++++++--------- dlls/msi/tests/msi.c | 62 ++++ dlls/msxml3/Makefile.in | 1 + dlls/msxml3/domdoc.c | 15 +- dlls/msxml3/element.c | 20 +- dlls/msxml3/msxml_private.h | 5 +- dlls/msxml3/node.c | 33 +- dlls/msxml3/nodelist.c | 227 ++------------ dlls/msxml3/queryresult.c | 293 ++++++++++++++++++ dlls/msxml3/tests/Makefile.in | 2 +- dlls/msxml3/tests/domdoc.c | 308 ++++++++++++++++++- dlls/ntdll/loader.c | 127 ++++---- dlls/ntdll/ntdll.spec | 4 +- dlls/ntdll/ntdll_misc.h | 2 +- dlls/ntdll/thread.c | 16 +- dlls/ntdll/version.c | 8 + dlls/ntoskrnl.exe/ntoskrnl.c | 312 +++++++++++++++++++ dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 38 ++- dlls/ole32/compobj.c | 220 ++++++++++---- dlls/ole32/compobj_private.h | 2 + dlls/ole32/hglobalstream.c | 13 + dlls/ole32/tests/hglobalstream.c | 45 +++ dlls/ole32/tests/marshal.c | 1 - dlls/oleaut32/tests/tmarshal.idl | 109 +++++++ dlls/oleaut32/tests/typelib.c | 256 +++++++++++++++- dlls/oleaut32/tmarshal.c | 265 ++++++++++------ dlls/oleaut32/typelib.c | 258 ++++++++-------- dlls/oleaut32/ungif.c | 9 +- dlls/qcap/capturegraph.c | 1 - dlls/qcap/vfwcapture.c | 1 - dlls/qcap/yuv.c | 1 - dlls/quartz/acmwrapper.c | 2 - dlls/quartz/avidec.c | 4 - dlls/quartz/avisplit.c | 1 - dlls/quartz/dsoundrender.c | 2 - dlls/quartz/mpegsplit.c | 1 - dlls/quartz/parser.c | 5 - dlls/quartz/systemclock.c | 1 - dlls/quartz/transform.c | 6 - dlls/quartz/videorenderer.c | 2 - dlls/quartz/waveparser.c | 1 - dlls/riched20/editor.c | 2 - dlls/riched20/txtsrv.c | 1 - dlls/rpcrt4/ndr_clientserver.c | 1 - dlls/rpcrt4/ndr_marshall.c | 1 - dlls/rpcrt4/ndr_ole.c | 1 - dlls/rpcrt4/ndr_stubless.c | 1 - dlls/rpcrt4/rpc_binding.c | 1 - dlls/rpcrt4/rpc_epmap.c | 1 - dlls/rpcrt4/rpc_message.c | 1 - dlls/rpcrt4/rpc_server.c | 1 - dlls/rpcrt4/rpc_transport.c | 1 - dlls/rsaenh/rsaenh.c | 1 - dlls/setupapi/query.c | 2 +- dlls/setupapi/queue.c | 96 +++++- dlls/setupapi/setupapi.spec | 4 +- dlls/shell32/shlexec.c | 2 + dlls/user32/msg16.c | 2 +- include/Makefile.in | 2 + include/ddk/wdm.h | 7 + include/icftypes.idl | 69 +++++ include/netfw.idl | 470 ++++++++++++++++++++++++++++ include/setupapi.h | 7 + include/winternl.h | 3 +- programs/Makefile.in | 2 + programs/winedevice/Makefile.in | 14 + programs/winedevice/device.c | 237 +++++++++++++++ server/token.c | 9 +- 87 files changed, 3805 insertions(+), 1080 deletions(-) create mode 100644 dlls/msxml3/queryresult.c create mode 100644 include/icftypes.idl create mode 100644 include/netfw.idl create mode 100644 programs/winedevice/Makefile.in create mode 100644 programs/winedevice/device.c diff --git a/.gitignore b/.gitignore index 62efdbaa819..af69a26d2be 100644 --- a/.gitignore +++ b/.gitignore @@ -693,6 +693,7 @@ include/exdisp.h include/hlink.h include/htiframe.h include/iads.h +include/icftypes.h include/indexsrv.h include/mediaobj.h include/mimeinfo.h @@ -702,6 +703,7 @@ include/mshtmhst.h include/mshtml.h include/msxml.h include/msxml2.h +include/netfw.h include/oaidl.h include/objidl.h include/objsafe.h @@ -807,6 +809,7 @@ programs/winedbg/dbg.tab.h programs/winedbg/debug.yy.c programs/winedbg/winedbg programs/winedbg/winedbg.man +programs/winedevice/winedevice programs/winefile/drivebar.bmp programs/winefile/images.bmp programs/winefile/rsrc.res diff --git a/Makefile.in b/Makefile.in index e7942ec61d0..3b16428c2b5 100644 --- a/Makefile.in +++ b/Makefile.in @@ -469,6 +469,7 @@ ALL_MAKEFILES = \ programs/winecfg/Makefile \ programs/wineconsole/Makefile \ programs/winedbg/Makefile \ + programs/winedevice/Makefile \ programs/winefile/Makefile \ programs/winemenubuilder/Makefile \ programs/winemine/Makefile \ @@ -817,6 +818,7 @@ programs/winebrowser/Makefile: programs/winebrowser/Makefile.in programs/Makepro programs/winecfg/Makefile: programs/winecfg/Makefile.in programs/Makeprog.rules programs/wineconsole/Makefile: programs/wineconsole/Makefile.in programs/Makeprog.rules programs/winedbg/Makefile: programs/winedbg/Makefile.in programs/Makeprog.rules +programs/winedevice/Makefile: programs/winedevice/Makefile.in programs/Makeprog.rules programs/winefile/Makefile: programs/winefile/Makefile.in programs/Makeprog.rules programs/winemenubuilder/Makefile: programs/winemenubuilder/Makefile.in programs/Makeprog.rules programs/winemine/Makefile: programs/winemine/Makefile.in programs/Makeprog.rules diff --git a/configure b/configure index 8795df4d513..203055ee167 100755 --- a/configure +++ b/configure @@ -21028,6 +21028,8 @@ ac_config_files="$ac_config_files programs/wineconsole/Makefile" ac_config_files="$ac_config_files programs/winedbg/Makefile" +ac_config_files="$ac_config_files programs/winedevice/Makefile" + ac_config_files="$ac_config_files programs/winefile/Makefile" ac_config_files="$ac_config_files programs/winemenubuilder/Makefile" @@ -21949,6 +21951,7 @@ do "programs/winecfg/Makefile") CONFIG_FILES="$CONFIG_FILES programs/winecfg/Makefile" ;; "programs/wineconsole/Makefile") CONFIG_FILES="$CONFIG_FILES programs/wineconsole/Makefile" ;; "programs/winedbg/Makefile") CONFIG_FILES="$CONFIG_FILES programs/winedbg/Makefile" ;; + "programs/winedevice/Makefile") CONFIG_FILES="$CONFIG_FILES programs/winedevice/Makefile" ;; "programs/winefile/Makefile") CONFIG_FILES="$CONFIG_FILES programs/winefile/Makefile" ;; "programs/winemenubuilder/Makefile") CONFIG_FILES="$CONFIG_FILES programs/winemenubuilder/Makefile" ;; "programs/winemine/Makefile") CONFIG_FILES="$CONFIG_FILES programs/winemine/Makefile" ;; diff --git a/configure.ac b/configure.ac index e29fc779c1d..d8a01ac1025 100644 --- a/configure.ac +++ b/configure.ac @@ -1810,6 +1810,7 @@ AC_CONFIG_FILES([programs/winebrowser/Makefile]) AC_CONFIG_FILES([programs/winecfg/Makefile]) AC_CONFIG_FILES([programs/wineconsole/Makefile]) AC_CONFIG_FILES([programs/winedbg/Makefile]) +AC_CONFIG_FILES([programs/winedevice/Makefile]) AC_CONFIG_FILES([programs/winefile/Makefile]) AC_CONFIG_FILES([programs/winemenubuilder/Makefile]) AC_CONFIG_FILES([programs/winemine/Makefile]) diff --git a/dlls/advapi32/service.c b/dlls/advapi32/service.c index e1d10655427..e9a116088c4 100644 --- a/dlls/advapi32/service.c +++ b/dlls/advapi32/service.c @@ -1486,26 +1486,43 @@ static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid) PROCESS_INFORMATION pi; STARTUPINFOW si; LPWSTR path = NULL, str; - DWORD type, size, ret; + DWORD type, size, ret, svc_type; HANDLE handles[2]; BOOL r; - /* read the executable path from memory */ - size = 0; - ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size); - if (ret!=ERROR_SUCCESS) - return FALSE; - str = HeapAlloc(GetProcessHeap(),0,size); - ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size); - if (ret==ERROR_SUCCESS) + size = sizeof(svc_type); + if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD) + svc_type = 0; + + if (svc_type == SERVICE_KERNEL_DRIVER) { - size = ExpandEnvironmentStringsW(str,NULL,0); - path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR)); - ExpandEnvironmentStringsW(str,path,size); + static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0}; + DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name); + + if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE; + GetSystemDirectoryW( path, len ); + lstrcatW( path, winedeviceW ); + lstrcatW( path, hsvc->name ); + } + else + { + /* read the executable path from the registry */ + size = 0; + ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size); + if (ret!=ERROR_SUCCESS) + return FALSE; + str = HeapAlloc(GetProcessHeap(),0,size); + ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size); + if (ret==ERROR_SUCCESS) + { + size = ExpandEnvironmentStringsW(str,NULL,0); + path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR)); + ExpandEnvironmentStringsW(str,path,size); + } + HeapFree(GetProcessHeap(),0,str); + if (!path) + return FALSE; } - HeapFree(GetProcessHeap(),0,str); - if (!path) - return FALSE; /* wait for the process to start and set an event or terminate */ handles[0] = service_get_event_handle( hsvc->name ); diff --git a/dlls/comctl32/imagelist.c b/dlls/comctl32/imagelist.c index 0c23d19d0a7..3c9e89b2994 100644 --- a/dlls/comctl32/imagelist.c +++ b/dlls/comctl32/imagelist.c @@ -1192,8 +1192,13 @@ ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp) hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour)); PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY ); - BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND ); - BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, pt.x, pt.y, SRCPAINT ); + if (himl->hbmMask) + { + BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND ); + BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, pt.x, pt.y, SRCPAINT ); + } + else + BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, pt.x, pt.y, SRCCOPY); DeleteObject (SelectObject (hImageDC, hOldBrush)); } diff --git a/dlls/dbghelp/elf_module.c b/dlls/dbghelp/elf_module.c index b844e59c8d5..30b7a3c0102 100644 --- a/dlls/dbghelp/elf_module.c +++ b/dlls/dbghelp/elf_module.c @@ -961,7 +961,7 @@ static BOOL elf_debuglink_parse(struct elf_file_map* fmap, struct module* module * 2/ padding on 4 byte boundary * 3/ CRC of the linked ELF file */ - const char* dbg_link = (char*)debuglink; + const char* dbg_link = (const char*)debuglink; DWORD crc; crc = *(const DWORD*)(dbg_link + ((DWORD_PTR)(strlen(dbg_link) + 4) & ~3)); @@ -1090,7 +1090,7 @@ static BOOL elf_load_debug_info_from_map(struct module* module, dw2_debug_loclist, elf_get_map_size(&debug_loclist_sect)); if (!lret) - WARN("Couldn't correctly read stabs\n"); + WARN("Couldn't correctly read dwarf2\n"); ret = ret || lret; } elf_unmap_section(&debug_sect); diff --git a/dlls/kernel32/instr.c b/dlls/kernel32/instr.c index 8a37a47b864..f9b99c8a9c1 100644 --- a/dlls/kernel32/instr.c +++ b/dlls/kernel32/instr.c @@ -428,12 +428,12 @@ static void INSTR_outport( WORD port, int size, DWORD val, CONTEXT86 *context ) /*********************************************************************** - * INSTR_EmulateInstruction + * __wine_emulate_instruction * * Emulate a privileged instruction. * Returns exception continuation status. */ -DWORD INSTR_EmulateInstruction( EXCEPTION_RECORD *rec, CONTEXT86 *context ) +DWORD __wine_emulate_instruction( EXCEPTION_RECORD *rec, CONTEXT86 *context ) { int prefix, segprefix, prefixlen, len, repX, long_op, long_addr; BYTE *instr; @@ -886,7 +886,7 @@ LONG CALLBACK INSTR_vectored_handler( EXCEPTION_POINTERS *ptrs ) (record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION || record->ExceptionCode == EXCEPTION_PRIV_INSTRUCTION)) { - if (INSTR_EmulateInstruction( record, context ) == ExceptionContinueExecution) + if (__wine_emulate_instruction( record, context ) == ExceptionContinueExecution) return EXCEPTION_CONTINUE_EXECUTION; } return EXCEPTION_CONTINUE_SEARCH; diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index d6bb2bf71e5..32bf8e3f030 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -1234,6 +1234,7 @@ @ cdecl __wine_dll_register_16(ptr str) @ cdecl __wine_dll_unregister_16(ptr) @ varargs -private __wine_call_from_16_regs() +@ cdecl __wine_emulate_instruction(ptr ptr) # Unix files @ cdecl wine_get_unix_file_name(wstr) diff --git a/dlls/kernel32/kernel_private.h b/dlls/kernel32/kernel_private.h index 4796e62ce07..dd7c91608fc 100644 --- a/dlls/kernel32/kernel_private.h +++ b/dlls/kernel32/kernel_private.h @@ -79,7 +79,7 @@ extern void FILE_SetDosError(void); extern WCHAR *FILE_name_AtoW( LPCSTR name, BOOL alloc ); extern DWORD FILE_name_WtoA( LPCWSTR src, INT srclen, LPSTR dest, INT destlen ); -extern DWORD INSTR_EmulateInstruction( EXCEPTION_RECORD *rec, CONTEXT86 *context ); +extern DWORD __wine_emulate_instruction( EXCEPTION_RECORD *rec, CONTEXT86 *context ); extern LONG CALLBACK INSTR_vectored_handler( EXCEPTION_POINTERS *ptrs ); extern void INSTR_CallBuiltinHandler( CONTEXT86 *context, BYTE intnum ); diff --git a/dlls/kernel32/module.c b/dlls/kernel32/module.c index daf27144899..996abf358af 100644 --- a/dlls/kernel32/module.c +++ b/dlls/kernel32/module.c @@ -501,6 +501,12 @@ BOOL WINAPI GetModuleHandleExW( DWORD flags, LPCWSTR name, HMODULE *module ) { NTSTATUS status = STATUS_SUCCESS; HMODULE ret; + ULONG magic; + + /* if we are messing with the refcount, grab the loader lock */ + if ((flags & GET_MODULE_HANDLE_EX_FLAG_PIN) || + !(flags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT)) + LdrLockLoaderLock( 0, NULL, &magic ); if (!name) { @@ -515,21 +521,24 @@ BOOL WINAPI GetModuleHandleExW( DWORD flags, LPCWSTR name, HMODULE *module ) { UNICODE_STRING wstr; RtlInitUnicodeString( &wstr, name ); - status = LdrGetDllHandle( 0, 0, &wstr, &ret ); + status = LdrGetDllHandle( NULL, 0, &wstr, &ret ); } - if (status != STATUS_SUCCESS) + if (status == STATUS_SUCCESS) { - SetLastError( RtlNtStatusToDosError( status ) ); - return FALSE; + if (flags & GET_MODULE_HANDLE_EX_FLAG_PIN) + FIXME( "should pin refcount for %p\n", ret ); + else if (!(flags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT)) + LdrAddRefDll( 0, ret ); } + else SetLastError( RtlNtStatusToDosError( status ) ); if ((flags & GET_MODULE_HANDLE_EX_FLAG_PIN) || !(flags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT)) - FIXME( "should update refcount, flags %x\n", flags ); + LdrUnlockLoaderLock( 0, magic ); if (module) *module = ret; - return TRUE; + return (status == STATUS_SUCCESS); } /*********************************************************************** @@ -835,24 +844,37 @@ static HMODULE load_library( const UNICODE_STRING *libname, DWORD flags ) HMODULE hModule; WCHAR *load_path; + load_path = MODULE_get_dll_load_path( flags & LOAD_WITH_ALTERED_SEARCH_PATH ? libname->Buffer : NULL ); + if (flags & LOAD_LIBRARY_AS_DATAFILE) { + ULONG magic; + + LdrLockLoaderLock( 0, NULL, &magic ); + if (!(nts = LdrGetDllHandle( load_path, flags, libname, &hModule ))) + { + LdrAddRefDll( 0, hModule ); + LdrUnlockLoaderLock( 0, magic ); + goto done; + } + LdrUnlockLoaderLock( 0, magic ); + /* The method in load_library_as_datafile allows searching for the * 'native' libraries only */ - if (load_library_as_datafile( libname->Buffer, &hModule )) return hModule; + if (load_library_as_datafile( libname->Buffer, &hModule )) goto done; flags |= DONT_RESOLVE_DLL_REFERENCES; /* Just in case */ /* Fallback to normal behaviour */ } - load_path = MODULE_get_dll_load_path( flags & LOAD_WITH_ALTERED_SEARCH_PATH ? libname->Buffer : NULL ); nts = LdrLoadDll( load_path, flags, libname, &hModule ); - HeapFree( GetProcessHeap(), 0, load_path ); if (nts != STATUS_SUCCESS) { hModule = 0; SetLastError( RtlNtStatusToDosError( nts ) ); } +done: + HeapFree( GetProcessHeap(), 0, load_path ); return hModule; } diff --git a/dlls/kernel32/tests/codepage.c b/dlls/kernel32/tests/codepage.c index 2cd0557b4f6..bde9f825510 100644 --- a/dlls/kernel32/tests/codepage.c +++ b/dlls/kernel32/tests/codepage.c @@ -36,8 +36,8 @@ static void test_destination_buffer(void) SetLastError(0xdeadbeef); needed = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, NULL, 0, NULL, NULL); - ok( (needed > 0), "returned %d with 0x%x/%d (expected '> 0')\n", - needed, GetLastError(), GetLastError()); + ok( (needed > 0), "returned %d with %u (expected '> 0')\n", + needed, GetLastError()); maxsize = needed*2; buffer = HeapAlloc(GetProcessHeap(), 0, maxsize); @@ -48,45 +48,44 @@ static void test_destination_buffer(void) buffer[maxsize] = '\0'; SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, buffer, needed+1, NULL, NULL); - ok( (len > 0), "returned %d with 0x%x/%d and '%s' (expected '> 0')\n", - len, GetLastError(), GetLastError(), buffer); + ok( (len > 0), "returned %d with %u and '%s' (expected '> 0')\n", + len, GetLastError(), buffer); memset(buffer, 'x', maxsize); buffer[maxsize] = '\0'; SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, buffer, needed, NULL, NULL); - ok( (len > 0), "returned %d with 0x%x/%d and '%s' (expected '> 0')\n", - len, GetLastError(), GetLastError(), buffer); + ok( (len > 0), "returned %d with %u and '%s' (expected '> 0')\n", + len, GetLastError(), buffer); memset(buffer, 'x', maxsize); buffer[maxsize] = '\0'; SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, buffer, needed-1, NULL, NULL); ok( !len && (GetLastError() == ERROR_INSUFFICIENT_BUFFER), - "returned %d with 0x%x/%d and '%s' (expected '0' with " - "ERROR_INSUFFICIENT_BUFFER)\n", len, GetLastError(), GetLastError(), buffer); + "returned %d with %u and '%s' (expected '0' with " + "ERROR_INSUFFICIENT_BUFFER)\n", len, GetLastError(), buffer); memset(buffer, 'x', maxsize); buffer[maxsize] = '\0'; SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, buffer, 1, NULL, NULL); ok( !len && (GetLastError() == ERROR_INSUFFICIENT_BUFFER), - "returned %d with 0x%x/%d and '%s' (expected '0' with " - "ERROR_INSUFFICIENT_BUFFER)\n", len, GetLastError(), GetLastError(), buffer); + "returned %d with %u and '%s' (expected '0' with " + "ERROR_INSUFFICIENT_BUFFER)\n", len, GetLastError(), buffer); SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, buffer, 0, NULL, NULL); - ok( (len > 0), "returned %d with 0x%x/%d (expected '> 0')\n", - len, GetLastError(), GetLastError()); + ok( (len > 0), "returned %d with %u (expected '> 0')\n", + len, GetLastError()); SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, NULL, needed, NULL, NULL); ok( !len && (GetLastError() == ERROR_INVALID_PARAMETER), - "returned %d with 0x%x/%d (expected '0' with " - "ERROR_INVALID_PARAMETER)\n", len, GetLastError(), GetLastError()); + "returned %d with %u (expected '0' with " + "ERROR_INVALID_PARAMETER)\n", len, GetLastError()); HeapFree(GetProcessHeap(), 0, buffer); - } @@ -99,14 +98,14 @@ static void test_null_source(void) len = WideCharToMultiByte(CP_ACP, 0, NULL, 0, NULL, 0, NULL, NULL); GLE = GetLastError(); ok(!len && GLE == ERROR_INVALID_PARAMETER, - "WideCharToMultiByte returned %d with GLE=%d (expected 0 with ERROR_INVALID_PARAMETER)\n", + "WideCharToMultiByte returned %d with GLE=%u (expected 0 with ERROR_INVALID_PARAMETER)\n", len, GLE); SetLastError(0); len = WideCharToMultiByte(CP_ACP, 0, NULL, -1, NULL, 0, NULL, NULL); GLE = GetLastError(); ok(!len && GLE == ERROR_INVALID_PARAMETER, - "WideCharToMultiByte returned %d with GLE=%d (expected 0 with ERROR_INVALID_PARAMETER)\n", + "WideCharToMultiByte returned %d with GLE=%u (expected 0 with ERROR_INVALID_PARAMETER)\n", len, GLE); } @@ -131,13 +130,19 @@ static void test_negative_source_length(void) memset(buf,'x',sizeof(buf)); len = WideCharToMultiByte(CP_ACP, 0, foobarW, -2002, buf, 10, NULL, NULL); ok(len == 7 && !lstrcmpA(buf, "foobar") && GetLastError() == 0xdeadbeef, - "WideCharToMultiByte(-2002): len=%d error=%d\n",len,GetLastError()); + "WideCharToMultiByte(-2002): len=%d error=%u\n", len, GetLastError()); SetLastError( 0xdeadbeef ); memset(bufW,'x',sizeof(bufW)); len = MultiByteToWideChar(CP_ACP, 0, "foobar", -2002, bufW, 10); ok(len == 7 && !mylstrcmpW(bufW, foobarW) && GetLastError() == 0xdeadbeef, - "MultiByteToWideChar(-2002): len=%d error=%d\n",len,GetLastError()); + "MultiByteToWideChar(-2002): len=%d error=%u\n", len, GetLastError()); + + SetLastError(0xdeadbeef); + memset(bufW, 'x', sizeof(bufW)); + len = MultiByteToWideChar(CP_ACP, 0, "foobar", -1, bufW, 6); + ok(len == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "MultiByteToWideChar(-1): len=%d error=%u\n", len, GetLastError()); } static void test_overlapped_buffers(void) diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c index b67b81d08c9..7b297a2306d 100644 --- a/dlls/kernel32/tests/loader.c +++ b/dlls/kernel32/tests/loader.c @@ -424,14 +424,14 @@ START_TEST(loader) SetLastError(0xdeadbeef); hlib_as_data_file = LoadLibraryEx(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE); ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError()); -todo_wine ok(hlib_as_data_file == hlib, "hlib_as_file and hlib are different\n"); + ok(hlib_as_data_file == hlib, "hlib_as_file and hlib are different\n"); SetLastError(0xdeadbeef); ok(FreeLibrary(hlib), "FreeLibrary error %d\n", GetLastError()); SetLastError(0xdeadbeef); hlib = GetModuleHandle(dll_name); -todo_wine ok(hlib != 0, "GetModuleHandle error %u\n", GetLastError()); + ok(hlib != 0, "GetModuleHandle error %u\n", GetLastError()); SetLastError(0xdeadbeef); ok(FreeLibrary(hlib_as_data_file), "FreeLibrary error %d\n", GetLastError()); diff --git a/dlls/kernel32/wowthunk.c b/dlls/kernel32/wowthunk.c index 9e27f85646e..4f714ab6317 100644 --- a/dlls/kernel32/wowthunk.c +++ b/dlls/kernel32/wowthunk.c @@ -256,7 +256,7 @@ static DWORD call16_handler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION_RE else { SEGPTR gpHandler; - DWORD ret = INSTR_EmulateInstruction( record, context ); + DWORD ret = __wine_emulate_instruction( record, context ); /* * Insert check for pending DPMI events. Note that this @@ -310,7 +310,7 @@ static DWORD vm86_handler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION_RECO if (record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION || record->ExceptionCode == EXCEPTION_PRIV_INSTRUCTION) { - return INSTR_EmulateInstruction( record, context ); + return __wine_emulate_instruction( record, context ); } return ExceptionContinueSearch; diff --git a/dlls/msi/automation.c b/dlls/msi/automation.c index 762f20ca093..63fea99c1a3 100644 --- a/dlls/msi/automation.c +++ b/dlls/msi/automation.c @@ -80,13 +80,31 @@ interface AutomationObject { }; /* + * ListEnumerator - IEnumVARIANT implementation for MSI automation lists. + */ + +typedef interface ListEnumerator ListEnumerator; + +interface ListEnumerator { + /* VTables */ + const IEnumVARIANTVtbl *lpVtbl; + + /* Object reference count */ + LONG ref; + + /* Current position and pointer to AutomationObject that stores actual data */ + ULONG ulPos; + AutomationObject *pObj; +}; + +/* * Structures for additional data required by specific automation objects */ typedef struct { - int iCount; - LPWSTR *pszStrings; -} StringListData; + ULONG ulCount; + VARIANT *pVars; +} ListData; typedef struct { /* The parent Installer object */ @@ -96,6 +114,7 @@ typedef struct { /* VTables */ static const struct IDispatchVtbl AutomationObject_Vtbl; static const struct IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl; +static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl; /* Load type info so we don't have to process GetIDsOfNames */ HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid) @@ -110,19 +129,19 @@ HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID /* Load registered type library */ hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, lcid, &pLib); if (FAILED(hr)) { - hr = LoadTypeLib(szMsiServer, &pLib); - if (FAILED(hr)) { - ERR("Could not load msiserver.tlb\n"); - return hr; - } + hr = LoadTypeLib(szMsiServer, &pLib); + if (FAILED(hr)) { + ERR("Could not load msiserver.tlb\n"); + return hr; + } } /* Get type information for object */ hr = ITypeLib_GetTypeInfoOfGuid(pLib, clsid, &pInfo); ITypeLib_Release(pLib); if (FAILED(hr)) { - ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid)); - return hr; + ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid)); + return hr; } *pptinfo = pInfo; return S_OK; @@ -131,8 +150,8 @@ HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID /* Create the automation object, placing the result in the pointer ppObj. The automation object is created * with the appropriate clsid and invocation function. */ HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, LPVOID *ppObj, REFIID clsid, - HRESULT (STDMETHODCALLTYPE *funcInvoke)(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*, - VARIANT*,EXCEPINFO*,UINT*), + HRESULT (STDMETHODCALLTYPE *funcInvoke)(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*, + VARIANT*,EXCEPINFO*,UINT*), void (STDMETHODCALLTYPE *funcFree)(AutomationObject*), SIZE_T sizetPrivateData) { @@ -142,7 +161,7 @@ HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, LPVOI TRACE("(%ld,%p,%p,%s,%p,%p,%ld)\n", (unsigned long)msiHandle, pUnkOuter, ppObj, debugstr_guid(clsid), funcInvoke, funcFree, sizetPrivateData); if( pUnkOuter ) - return CLASS_E_NOAGGREGATION; + return CLASS_E_NOAGGREGATION; object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AutomationObject)+sizetPrivateData); @@ -161,8 +180,8 @@ HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, LPVOI object->iTypeInfo = NULL; hr = load_type_info((IDispatch *)object, &object->iTypeInfo, clsid, 0x0); if (FAILED(hr)) { - HeapFree(GetProcessHeap(), 0, object); - return hr; + HeapFree(GetProcessHeap(), 0, object); + return hr; } *ppObj = object; @@ -170,6 +189,31 @@ HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, LPVOI return S_OK; } +/* Create a list enumerator, placing the result in the pointer ppObj. */ +HRESULT create_list_enumerator(IUnknown *pUnkOuter, LPVOID *ppObj, AutomationObject *pObj, ULONG ulPos) +{ + ListEnumerator *object; + + TRACE("(%p,%p,%p,%uld)\n", pUnkOuter, ppObj, pObj, ulPos); + + if( pUnkOuter ) + return CLASS_E_NOAGGREGATION; + + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ListEnumerator)); + + /* Set all the VTable references */ + object->lpVtbl = &ListEnumerator_Vtbl; + object->ref = 1; + + /* Store data that was passed */ + object->ulPos = ulPos; + object->pObj = pObj; + if (pObj) IDispatch_AddRef((IDispatch *)pObj); + + *ppObj = object; + return S_OK; +} + /* Macros to get pointer to AutomationObject from the other VTables. */ static inline AutomationObject *obj_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface ) { @@ -206,8 +250,8 @@ static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID r *ppvObject = &This->lpvtblIProvideMultipleClassInfo; else { - TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid)); - return E_NOINTERFACE; + TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid)); + return E_NOINTERFACE; } /* @@ -238,7 +282,7 @@ static ULONG WINAPI AutomationObject_Release(IDispatch* iface) if (!ref) { if (This->funcFree) This->funcFree(This); - MsiCloseHandle(This->msiHandle); + MsiCloseHandle(This->msiHandle); HeapFree(GetProcessHeap(), 0, This); } @@ -322,14 +366,14 @@ static HRESULT WINAPI AutomationObject_Invoke( if (!IsEqualIID(riid, &IID_NULL)) { - ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid)); - return DISP_E_UNKNOWNNAME; + ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid)); + return DISP_E_UNKNOWNNAME; } if (wFlags & DISPATCH_PROPERTYGET && !pVarResult) { - ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n"); - return DISP_E_PARAMNOTOPTIONAL; + ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n"); + return DISP_E_PARAMNOTOPTIONAL; } /* This simplifies our individual object invocation functions */ @@ -342,15 +386,15 @@ static HRESULT WINAPI AutomationObject_Invoke( /* If we are tracing, we want to see the name of the member we are invoking */ if (TRACE_ON(msi)) { - ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL); - TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName)); + ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL); + TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName)); } hr = This->funcInvoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr); if (hr == DISP_E_MEMBERNOTFOUND) { - if (bstrName == NULL) ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL); - FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags, debugstr_guid(This->clsid)); + if (bstrName == NULL) ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL); + FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags, debugstr_guid(This->clsid)); } else if (pExcepInfo && (hr == DISP_E_PARAMNOTFOUND || @@ -448,10 +492,10 @@ static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvid TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID)); if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID) - return E_INVALIDARG; + return E_INVALIDARG; else { - *pGUID = *This->clsid; - return S_OK; + *pGUID = *This->clsid; + return S_OK; } } @@ -478,19 +522,19 @@ static HRESULT WINAPI AutomationObject_GetInfoOfIndex(IProvideMultipleClassInfo* TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, pptiCoClass, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource); if (iti != 0) - return E_INVALIDARG; + return E_INVALIDARG; if (dwFlags & MULTICLASSINFO_GETTYPEINFO) load_type_info((IDispatch *)This, pptiCoClass, This->clsid, 0); if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS) { - *pdwTIFlags = 0; - *pcdispidReserved = 0; + *pdwTIFlags = 0; + *pcdispidReserved = 0; } if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY){ - *piidPrimary = *This->clsid; + *piidPrimary = *This->clsid; } if (dwFlags & MULTICLASSINFO_GETIIDSOURCE){ @@ -512,6 +556,148 @@ static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClas }; /* + * ListEnumerator methods + */ + +/*** IUnknown methods ***/ +static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID riid, void** ppvObject) +{ + ListEnumerator *This = (ListEnumerator *)iface; + + TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject); + + if (ppvObject == NULL) + return E_INVALIDARG; + + *ppvObject = 0; + + if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumVARIANT)) + *ppvObject = This; + else + { + TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid)); + return E_NOINTERFACE; + } + + IClassFactory_AddRef(iface); + return S_OK; +} + +static ULONG WINAPI ListEnumerator_AddRef(IEnumVARIANT* iface) +{ + ListEnumerator *This = (ListEnumerator *)iface; + + TRACE("(%p/%p)\n", iface, This); + + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface) +{ + ListEnumerator *This = (ListEnumerator *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p/%p)\n", iface, This); + + if (!ref) + { + if (This->pObj) IDispatch_Release((IDispatch *)This->pObj); + HeapFree(GetProcessHeap(), 0, This); + } + + return ref; +} + +/* IEnumVARIANT methods */ + +static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched) +{ + ListEnumerator *This = (ListEnumerator *)iface; + ListData *data = (ListData *)private_data(This->pObj); + ULONG idx, local; + + TRACE("(%p,%uld,%p,%p)\n", iface, celt, rgVar, pCeltFetched); + + if (pCeltFetched != NULL) + *pCeltFetched = 0; + + if (rgVar == NULL) + return S_FALSE; + + for (local = 0; local < celt; local++) + VariantInit(&rgVar[local]); + + for (idx = This->ulPos, local = 0; idx < data->ulCount && local < celt; idx++, local++) + VariantCopy(&rgVar[local], &data->pVars[idx]); + + if (pCeltFetched != NULL) + *pCeltFetched = local; + This->ulPos = idx; + + return (local < celt) ? S_FALSE : S_OK; +} + +static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt) +{ + ListEnumerator *This = (ListEnumerator *)iface; + ListData *data = (ListData *)private_data(This->pObj); + + TRACE("(%p,%uld)\n", iface, celt); + + This->ulPos += celt; + if (This->ulPos >= data->ulCount) + { + This->ulPos = data->ulCount; + return S_FALSE; + } + return S_OK; +} + +static HRESULT WINAPI ListEnumerator_Reset(IEnumVARIANT* iface) +{ + ListEnumerator *This = (ListEnumerator *)iface; + + TRACE("(%p)\n", iface); + + This->ulPos = 0; + return S_OK; +} + +static HRESULT WINAPI ListEnumerator_Clone(IEnumVARIANT* iface, IEnumVARIANT **ppEnum) +{ + ListEnumerator *This = (ListEnumerator *)iface; + HRESULT hr; + + TRACE("(%p,%p)\n", iface, ppEnum); + + if (ppEnum == NULL) + return S_FALSE; + + *ppEnum = NULL; + hr = create_list_enumerator(NULL, (LPVOID *)ppEnum, This->pObj, 0); + if (FAILED(hr)) + { + if (*ppEnum) + IUnknown_Release(*ppEnum); + return hr; + } + + IUnknown_AddRef(*ppEnum); + return S_OK; +} + +static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl = +{ + ListEnumerator_QueryInterface, + ListEnumerator_AddRef, + ListEnumerator_Release, + ListEnumerator_Next, + ListEnumerator_Skip, + ListEnumerator_Reset, + ListEnumerator_Clone +}; + +/* * Individual Object Invocation Functions */ @@ -519,9 +705,9 @@ static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClas This function is only for VARIANT type parameters that have several types that cannot be properly discriminated using DispGetParam/VariantChangeType. */ HRESULT WINAPI DispGetParam_CopyOnly( - DISPPARAMS *pdispparams, /* [in] Parameter list */ - UINT *position, /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */ - VARIANT *pvarResult) /* [out] Destination for resulting variant */ + DISPPARAMS *pdispparams, /* [in] Parameter list */ + UINT *position, /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */ + VARIANT *pvarResult) /* [out] Destination for resulting variant */ { /* position is counted backwards */ UINT pos; @@ -566,15 +752,15 @@ static HRESULT WINAPI RecordImpl_Invoke( switch (dispIdMember) { - case DISPID_RECORD_FIELDCOUNT: - if (wFlags & DISPATCH_PROPERTYGET) { + case DISPID_RECORD_FIELDCOUNT: + if (wFlags & DISPATCH_PROPERTYGET) { V_VT(pVarResult) = VT_I4; V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle); - } + } else return DISP_E_MEMBERNOTFOUND; - break; + break; - case DISPID_RECORD_STRINGDATA: + case DISPID_RECORD_STRINGDATA: if (wFlags & DISPATCH_PROPERTYGET) { hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); if (FAILED(hr)) return hr; @@ -590,28 +776,28 @@ static HRESULT WINAPI RecordImpl_Invoke( } if (ret != ERROR_SUCCESS) ERR("MsiRecordGetString returned %d\n", ret); - } else if (wFlags & DISPATCH_PROPERTYPUT) { + } else if (wFlags & DISPATCH_PROPERTYPUT) { hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); if (FAILED(hr)) return hr; hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr); if (FAILED(hr)) return hr; - if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS) + if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS) { VariantClear(&varg1); ERR("MsiRecordSetString returned %d\n", ret); return DISP_E_EXCEPTION; } - } + } else return DISP_E_MEMBERNOTFOUND; - break; + break; - case DISPID_RECORD_INTEGERDATA: - if (wFlags & DISPATCH_PROPERTYGET) { + case DISPID_RECORD_INTEGERDATA: + if (wFlags & DISPATCH_PROPERTYGET) { hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); if (FAILED(hr)) return hr; V_VT(pVarResult) = VT_I4; V_I4(pVarResult) = MsiRecordGetInteger(This->msiHandle, V_I4(&varg0)); - } else if (wFlags & DISPATCH_PROPERTYPUT) { + } else if (wFlags & DISPATCH_PROPERTYPUT) { hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); if (FAILED(hr)) return hr; hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr); @@ -621,9 +807,9 @@ static HRESULT WINAPI RecordImpl_Invoke( ERR("MsiRecordSetInteger returned %d\n", ret); return DISP_E_EXCEPTION; } - } + } else return DISP_E_MEMBERNOTFOUND; - break; + break; default: return DISP_E_MEMBERNOTFOUND; @@ -635,7 +821,7 @@ static HRESULT WINAPI RecordImpl_Invoke( return S_OK; } -static HRESULT WINAPI StringListImpl_Invoke( +static HRESULT WINAPI ListImpl_Invoke( AutomationObject* This, DISPID dispIdMember, REFIID riid, @@ -646,31 +832,45 @@ static HRESULT WINAPI StringListImpl_Invoke( EXCEPINFO* pExcepInfo, UINT* puArgErr) { - StringListData *data = (StringListData *)private_data(This); + ListData *data = (ListData *)private_data(This); HRESULT hr; VARIANTARG varg0; + IUnknown *pUnk = NULL; VariantInit(&varg0); switch (dispIdMember) { - case DISPID_STRINGLIST_ITEM: - if (wFlags & DISPATCH_PROPERTYGET) { + case DISPID_LIST__NEWENUM: + if (wFlags & DISPATCH_METHOD) { + V_VT(pVarResult) = VT_UNKNOWN; + if (SUCCEEDED(hr = create_list_enumerator(NULL, (LPVOID *)&pUnk, This, 0))) + { + IUnknown_AddRef(pUnk); + V_UNKNOWN(pVarResult) = pUnk; + } + else + ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr); + } + else return DISP_E_MEMBERNOTFOUND; + break; + + case DISPID_LIST_ITEM: + if (wFlags & DISPATCH_PROPERTYGET) { hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); if (FAILED(hr)) return hr; - if (V_I4(&varg0) < 0 || V_I4(&varg0) >= data->iCount) + if (V_I4(&varg0) < 0 || V_I4(&varg0) >= data->ulCount) return DISP_E_BADINDEX; - V_VT(pVarResult) = VT_BSTR; - V_BSTR(pVarResult) = SysAllocString(data->pszStrings[V_I4(&varg0)]); + VariantCopy(pVarResult, &data->pVars[V_I4(&varg0)]); } else return DISP_E_MEMBERNOTFOUND; break; - case DISPID_STRINGLIST_COUNT: - if (wFlags & DISPATCH_PROPERTYGET) { + case DISPID_LIST_COUNT: + if (wFlags & DISPATCH_PROPERTYGET) { V_VT(pVarResult) = VT_I4; - V_I4(pVarResult) = data->iCount; - } + V_I4(pVarResult) = data->ulCount; + } else return DISP_E_MEMBERNOTFOUND; break; @@ -683,14 +883,14 @@ static HRESULT WINAPI StringListImpl_Invoke( return S_OK; } -static void WINAPI StringListImpl_Free(AutomationObject *This) +static void WINAPI ListImpl_Free(AutomationObject *This) { - StringListData *data = private_data(This); - int idx; + ListData *data = private_data(This); + ULONG idx; - for (idx=0; idxiCount; idx++) - SysFreeString(data->pszStrings[idx]); - HeapFree(GetProcessHeap(), 0, data->pszStrings); + for (idx=0; idxulCount; idx++) + VariantClear(&data->pVars[idx]); + HeapFree(GetProcessHeap(), 0, data->pVars); } static HRESULT WINAPI ViewImpl_Invoke( @@ -715,21 +915,21 @@ static HRESULT WINAPI ViewImpl_Invoke( switch (dispIdMember) { - case DISPID_VIEW_EXECUTE: - if (wFlags & DISPATCH_METHOD) - { + case DISPID_VIEW_EXECUTE: + if (wFlags & DISPATCH_METHOD) + { hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr); if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL) MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle); else MsiViewExecute(This->msiHandle, 0); - } + } else return DISP_E_MEMBERNOTFOUND; - break; + break; - case DISPID_VIEW_FETCH: - if (wFlags & DISPATCH_METHOD) - { + case DISPID_VIEW_FETCH: + if (wFlags & DISPATCH_METHOD) + { V_VT(pVarResult) = VT_DISPATCH; if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS) { @@ -741,20 +941,20 @@ static HRESULT WINAPI ViewImpl_Invoke( else ERR("Failed to create Record object, hresult 0x%08x\n", hr); } - else if (ret == ERROR_NO_MORE_ITEMS) + else if (ret == ERROR_NO_MORE_ITEMS) V_DISPATCH(pVarResult) = NULL; else { ERR("MsiViewFetch returned %d\n", ret); return DISP_E_EXCEPTION; } - } + } else return DISP_E_MEMBERNOTFOUND; - break; + break; - case DISPID_VIEW_MODIFY: - if (wFlags & DISPATCH_METHOD) - { + case DISPID_VIEW_MODIFY: + if (wFlags & DISPATCH_METHOD) + { hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); if (FAILED(hr)) return hr; hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr); @@ -766,17 +966,17 @@ static HRESULT WINAPI ViewImpl_Invoke( ERR("MsiViewModify returned %d\n", ret); return DISP_E_EXCEPTION; } - } + } else return DISP_E_MEMBERNOTFOUND; - break; + break; - case DISPID_VIEW_CLOSE: - if (wFlags & DISPATCH_METHOD) - { - MsiViewClose(This->msiHandle); - } + case DISPID_VIEW_CLOSE: + if (wFlags & DISPATCH_METHOD) + { + MsiViewClose(This->msiHandle); + } else return DISP_E_MEMBERNOTFOUND; - break; + break; default: return DISP_E_MEMBERNOTFOUND; @@ -810,9 +1010,9 @@ static HRESULT WINAPI DatabaseImpl_Invoke( switch (dispIdMember) { - case DISPID_DATABASE_OPENVIEW: - if (wFlags & DISPATCH_METHOD) - { + case DISPID_DATABASE_OPENVIEW: + if (wFlags & DISPATCH_METHOD) + { hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); if (FAILED(hr)) return hr; V_VT(pVarResult) = VT_DISPATCH; @@ -826,15 +1026,15 @@ static HRESULT WINAPI DatabaseImpl_Invoke( else ERR("Failed to create View object, hresult 0x%08x\n", hr); } - else + else { VariantClear(&varg0); ERR("MsiDatabaseOpenView returned %d\n", ret); return DISP_E_EXCEPTION; } - } + } else return DISP_E_MEMBERNOTFOUND; - break; + break; default: return DISP_E_MEMBERNOTFOUND; @@ -873,16 +1073,16 @@ static HRESULT WINAPI SessionImpl_Invoke( switch (dispIdMember) { - case DISPID_SESSION_INSTALLER: - if (wFlags & DISPATCH_PROPERTYGET) { + case DISPID_SESSION_INSTALLER: + if (wFlags & DISPATCH_PROPERTYGET) { V_VT(pVarResult) = VT_DISPATCH; IDispatch_AddRef(data->pInstaller); V_DISPATCH(pVarResult) = data->pInstaller; - } + } else return DISP_E_MEMBERNOTFOUND; - break; + break; - case DISPID_SESSION_PROPERTY: + case DISPID_SESSION_PROPERTY: if (wFlags & DISPATCH_PROPERTYGET) { hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); if (FAILED(hr)) return hr; @@ -898,7 +1098,7 @@ static HRESULT WINAPI SessionImpl_Invoke( } if (ret != ERROR_SUCCESS) ERR("MsiGetProperty returned %d\n", ret); - } else if (wFlags & DISPATCH_PROPERTYPUT) { + } else if (wFlags & DISPATCH_PROPERTYPUT) { hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); if (FAILED(hr)) return hr; hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr); @@ -906,50 +1106,50 @@ static HRESULT WINAPI SessionImpl_Invoke( VariantClear(&varg0); return hr; } - if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS) + if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS) { VariantClear(&varg0); VariantClear(&varg1); ERR("MsiSetProperty returned %d\n", ret); return DISP_E_EXCEPTION; } - } + } else return DISP_E_MEMBERNOTFOUND; - break; + break; - case DISPID_SESSION_LANGUAGE: - if (wFlags & DISPATCH_PROPERTYGET) { - langId = MsiGetLanguage(This->msiHandle); + case DISPID_SESSION_LANGUAGE: + if (wFlags & DISPATCH_PROPERTYGET) { + langId = MsiGetLanguage(This->msiHandle); V_VT(pVarResult) = VT_I4; V_I4(pVarResult) = langId; - } + } else return DISP_E_MEMBERNOTFOUND; - break; + break; - case DISPID_SESSION_MODE: - if (wFlags & DISPATCH_PROPERTYGET) { + case DISPID_SESSION_MODE: + if (wFlags & DISPATCH_PROPERTYGET) { hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); if (FAILED(hr)) return hr; V_VT(pVarResult) = VT_BOOL; - V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0)); - } else if (wFlags & DISPATCH_PROPERTYPUT) { + V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0)); + } else if (wFlags & DISPATCH_PROPERTYPUT) { hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); if (FAILED(hr)) return hr; hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BOOL, &varg1, puArgErr); if (FAILED(hr)) return hr; - if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS) + if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS) { ERR("MsiSetMode returned %d\n", ret); return DISP_E_EXCEPTION; } - } + } else return DISP_E_MEMBERNOTFOUND; - break; + break; - case DISPID_SESSION_DATABASE: - if (wFlags & DISPATCH_PROPERTYGET) { + case DISPID_SESSION_DATABASE: + if (wFlags & DISPATCH_PROPERTYGET) { V_VT(pVarResult) = VT_DISPATCH; - if ((msiHandle = MsiGetActiveDatabase(This->msiHandle))) + if ((msiHandle = MsiGetActiveDatabase(This->msiHandle))) { if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Database, DatabaseImpl_Invoke, NULL, 0))) { @@ -959,14 +1159,14 @@ static HRESULT WINAPI SessionImpl_Invoke( else ERR("Failed to create Database object, hresult 0x%08x\n", hr); } - else + else { ERR("MsiGetActiveDatabase failed\n"); return DISP_E_EXCEPTION; } - } + } else return DISP_E_MEMBERNOTFOUND; - break; + break; case DISPID_SESSION_DOACTION: if (wFlags & DISPATCH_METHOD) { @@ -1032,35 +1232,35 @@ static HRESULT WINAPI SessionImpl_Invoke( else return DISP_E_MEMBERNOTFOUND; break; - case DISPID_SESSION_FEATURECURRENTSTATE: - if (wFlags & DISPATCH_PROPERTYGET) { + case DISPID_SESSION_FEATURECURRENTSTATE: + if (wFlags & DISPATCH_PROPERTYGET) { hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); if (FAILED(hr)) return hr; V_VT(pVarResult) = VT_I4; - if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS) - V_I4(pVarResult) = iInstalled; - else - { - ERR("MsiGetFeatureState returned %d\n", ret); + if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS) + V_I4(pVarResult) = iInstalled; + else + { + ERR("MsiGetFeatureState returned %d\n", ret); V_I4(pVarResult) = msiInstallStateUnknown; - } - } + } + } else return DISP_E_MEMBERNOTFOUND; - break; + break; - case DISPID_SESSION_FEATUREREQUESTSTATE: - if (wFlags & DISPATCH_PROPERTYGET) { + case DISPID_SESSION_FEATUREREQUESTSTATE: + if (wFlags & DISPATCH_PROPERTYGET) { hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); if (FAILED(hr)) return hr; V_VT(pVarResult) = VT_I4; - if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS) - V_I4(pVarResult) = iAction; - else - { - ERR("MsiGetFeatureState returned %d\n", ret); + if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS) + V_I4(pVarResult) = iAction; + else + { + ERR("MsiGetFeatureState returned %d\n", ret); V_I4(pVarResult) = msiInstallStateUnknown; - } - } else if (wFlags & DISPATCH_PROPERTYPUT) { + } + } else if (wFlags & DISPATCH_PROPERTYPUT) { hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); if (FAILED(hr)) return hr; hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr); @@ -1068,15 +1268,15 @@ static HRESULT WINAPI SessionImpl_Invoke( VariantClear(&varg0); return hr; } - if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS) + if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS) { VariantClear(&varg0); ERR("MsiSetFeatureState returned %d\n", ret); return DISP_E_EXCEPTION; } - } + } else return DISP_E_MEMBERNOTFOUND; - break; + break; default: return DISP_E_MEMBERNOTFOUND; @@ -1167,6 +1367,8 @@ static HRESULT WINAPI InstallerImpl_Invoke( UINT ret; VARIANTARG varg0, varg1, varg2; HRESULT hr; + LPWSTR szString = NULL; + DWORD dwSize = 0; VariantInit(&varg0); VariantInit(&varg1); @@ -1175,8 +1377,8 @@ static HRESULT WINAPI InstallerImpl_Invoke( switch (dispIdMember) { case DISPID_INSTALLER_CREATERECORD: - if (wFlags & DISPATCH_METHOD) - { + if (wFlags & DISPATCH_METHOD) + { hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); if (FAILED(hr)) return hr; V_VT(pVarResult) = VT_DISPATCH; @@ -1199,9 +1401,9 @@ static HRESULT WINAPI InstallerImpl_Invoke( else return DISP_E_MEMBERNOTFOUND; break; - case DISPID_INSTALLER_OPENPACKAGE: - if (wFlags & DISPATCH_METHOD) - { + case DISPID_INSTALLER_OPENPACKAGE: + if (wFlags & DISPATCH_METHOD) + { hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); if (FAILED(hr)) return hr; hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr); @@ -1211,7 +1413,7 @@ static HRESULT WINAPI InstallerImpl_Invoke( return hr; } V_VT(pVarResult) = VT_DISPATCH; - if ((ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &msiHandle)) == ERROR_SUCCESS) + if ((ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &msiHandle)) == ERROR_SUCCESS) { if (SUCCEEDED(hr = create_session(msiHandle, (IDispatch *)This, &pDispatch))) { @@ -1221,19 +1423,19 @@ static HRESULT WINAPI InstallerImpl_Invoke( else ERR("Failed to create Session object, hresult 0x%08x\n", hr); } - else + else { VariantClear(&varg0); ERR("MsiOpenPackageEx returned %d\n", ret); return DISP_E_EXCEPTION; } - } + } else return DISP_E_MEMBERNOTFOUND; - break; + break; case DISPID_INSTALLER_INSTALLPRODUCT: - if (wFlags & DISPATCH_METHOD) - { + if (wFlags & DISPATCH_METHOD) + { hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); if (FAILED(hr)) return hr; hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr); @@ -1242,22 +1444,21 @@ static HRESULT WINAPI InstallerImpl_Invoke( VariantClear(&varg0); return hr; } - if ((ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS) + if ((ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS) { VariantClear(&varg1); VariantClear(&varg0); ERR("MsiInstallProduct returned %d\n", ret); return DISP_E_EXCEPTION; } - } + } else return DISP_E_MEMBERNOTFOUND; - break; + break; case DISPID_INSTALLER_REGISTRYVALUE: if (wFlags & DISPATCH_METHOD) { HKEY hkey; - LPWSTR szString = NULL; - DWORD dwSize = 0, dwType; + DWORD dwType; UINT posValue = 2; /* Save valuePos so we can save puArgErr if we are unable to do our type conversions */ hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); @@ -1353,11 +1554,42 @@ static HRESULT WINAPI InstallerImpl_Invoke( else return DISP_E_MEMBERNOTFOUND; break; + case DISPID_INSTALLER_PRODUCTINFO: + if (wFlags & DISPATCH_PROPERTYGET) { + hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); + if (FAILED(hr)) return hr; + hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr); + if (FAILED(hr)) + { + VariantClear(&varg0); + return hr; + } + V_VT(pVarResult) = VT_BSTR; + V_BSTR(pVarResult) = NULL; + if ((ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &dwSize)) == ERROR_SUCCESS) + { + if (!(szString = msi_alloc((++dwSize)*sizeof(WCHAR)))) + ERR("Out of memory\n"); + else if ((ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), szString, &dwSize)) == ERROR_SUCCESS) + V_BSTR(pVarResult) = SysAllocString(szString); + msi_free(szString); + } + if (ret != ERROR_SUCCESS) + { + ERR("MsiGetProductInfo returned %d\n", ret); + VariantClear(&varg1); + VariantClear(&varg0); + return DISP_E_EXCEPTION; + } + } + else return DISP_E_MEMBERNOTFOUND; + break; + case DISPID_INSTALLER_PRODUCTS: if (wFlags & DISPATCH_PROPERTYGET) { - StringListData *sldata = NULL; - int idx = 0; + ListData *ldata = NULL; + ULONG idx = 0; WCHAR szProductBuf[GUID_SIZE]; /* Find number of products */ @@ -1369,22 +1601,24 @@ static HRESULT WINAPI InstallerImpl_Invoke( } V_VT(pVarResult) = VT_DISPATCH; - if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, StringListImpl_Invoke, StringListImpl_Free, sizeof(StringListData)))) + if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, ListImpl_Invoke, ListImpl_Free, sizeof(ListData)))) { IDispatch_AddRef(pDispatch); V_DISPATCH(pVarResult) = pDispatch; /* Save product strings */ - sldata = (StringListData *)private_data((AutomationObject *)pDispatch); - if (!(sldata->pszStrings = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LPWSTR)*sldata->iCount))) + ldata = (ListData *)private_data((AutomationObject *)pDispatch); + if (!(ldata->pVars = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*idx))) ERR("Out of memory\n"); else { - sldata->iCount = idx; - for (idx = 0; idx < sldata->iCount; idx++) + ldata->ulCount = idx; + for (idx = 0; idx < ldata->ulCount; idx++) { ret = MsiEnumProductsW(idx, szProductBuf); - sldata->pszStrings[idx] = SysAllocString(szProductBuf); + VariantInit(&ldata->pVars[idx]); + V_VT(&ldata->pVars[idx]) = VT_BSTR; + V_BSTR(&ldata->pVars[idx]) = SysAllocString(szProductBuf); } } } @@ -1397,8 +1631,8 @@ static HRESULT WINAPI InstallerImpl_Invoke( case DISPID_INSTALLER_RELATEDPRODUCTS: if (wFlags & DISPATCH_PROPERTYGET) { - StringListData *sldata = NULL; - int idx = 0; + ListData *ldata = NULL; + ULONG idx = 0; WCHAR szProductBuf[GUID_SIZE]; hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); @@ -1414,22 +1648,24 @@ static HRESULT WINAPI InstallerImpl_Invoke( } V_VT(pVarResult) = VT_DISPATCH; - if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, StringListImpl_Invoke, StringListImpl_Free, sizeof(StringListData)))) + if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, ListImpl_Invoke, ListImpl_Free, sizeof(ListData)))) { IDispatch_AddRef(pDispatch); V_DISPATCH(pVarResult) = pDispatch; /* Save product strings */ - sldata = (StringListData *)private_data((AutomationObject *)pDispatch); - if (!(sldata->pszStrings = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LPWSTR)*sldata->iCount))) + ldata = (ListData *)private_data((AutomationObject *)pDispatch); + if (!(ldata->pVars = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*idx))) ERR("Out of memory\n"); else { - sldata->iCount = idx; - for (idx = 0; idx < sldata->iCount; idx++) + ldata->ulCount = idx; + for (idx = 0; idx < ldata->ulCount; idx++) { ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, szProductBuf); - sldata->pszStrings[idx] = SysAllocString(szProductBuf); + VariantInit(&ldata->pVars[idx]); + V_VT(&ldata->pVars[idx]) = VT_BSTR; + V_BSTR(&ldata->pVars[idx]) = SysAllocString(szProductBuf); } } } diff --git a/dlls/msi/msi.c b/dlls/msi/msi.c index ae67b75b96b..34721dfcc3a 100644 --- a/dlls/msi/msi.c +++ b/dlls/msi/msi.c @@ -444,7 +444,7 @@ static UINT WINAPI MSI_GetProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, * FIXME: Values seem scattered/duplicated in the registry. Is there a system? */ - if ((szValue->str.w && !pcchValueBuf) || !szProduct || !szAttribute) + if ((szValue->str.w && !pcchValueBuf) || !szProduct || !szProduct[0] || !szAttribute) return ERROR_INVALID_PARAMETER; /* check for special properties */ @@ -505,6 +505,10 @@ static UINT WINAPI MSI_GetProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, RegCloseKey(hkey); } + else if (!szAttribute[0]) + { + return ERROR_UNKNOWN_PROPERTY; + } else { static const WCHAR szDisplayVersion[] = { diff --git a/dlls/msi/msiserver.idl b/dlls/msi/msiserver.idl index 5721319eddb..360e4f140ae 100644 --- a/dlls/msi/msiserver.idl +++ b/dlls/msi/msiserver.idl @@ -77,6 +77,10 @@ library WindowsInstaller [id(DISPID_INSTALLER_PRODUCTSTATE), propget] MsiInstallState ProductState( [in] BSTR Product); + [id(DISPID_INSTALLER_PRODUCTINFO), propget] + BSTR ProductInfo( + [in] BSTR Product, + [in] BSTR Attribute); [id(DISPID_INSTALLER_PRODUCTS), propget] StringList *Products(); [id(DISPID_INSTALLER_RELATEDPRODUCTS), propget] @@ -110,9 +114,11 @@ library WindowsInstaller { properties: methods: - [id(DISPID_STRINGLIST_ITEM), propget] + [id(DISPID_LIST__NEWENUM)] + IUnknown _NewEnum(); + [id(DISPID_LIST_ITEM), propget] BSTR Item(long Index); - [id(DISPID_STRINGLIST_COUNT), propget] + [id(DISPID_LIST_COUNT), propget] long Count(); } diff --git a/dlls/msi/msiserver_dispids.h b/dlls/msi/msiserver_dispids.h index 92c342930e5..694090e1024 100644 --- a/dlls/msi/msiserver_dispids.h +++ b/dlls/msi/msiserver_dispids.h @@ -21,6 +21,7 @@ #define DISPID_INSTALLER_INSTALLPRODUCT 8 #define DISPID_INSTALLER_REGISTRYVALUE 11 #define DISPID_INSTALLER_PRODUCTSTATE 17 +#define DISPID_INSTALLER_PRODUCTINFO 18 #define DISPID_INSTALLER_PRODUCTS 35 #define DISPID_INSTALLER_RELATEDPRODUCTS 40 @@ -28,8 +29,9 @@ #define DISPID_RECORD_STRINGDATA 1 #define DISPID_RECORD_INTEGERDATA 2 -#define DISPID_STRINGLIST_ITEM 0 -#define DISPID_STRINGLIST_COUNT 1 +#define DISPID_LIST__NEWENUM -4 +#define DISPID_LIST_ITEM 0 +#define DISPID_LIST_COUNT 1 #define DISPID_VIEW_EXECUTE 1 #define DISPID_VIEW_FETCH 2 diff --git a/dlls/msi/script.c b/dlls/msi/script.c index 54d0ee817e4..cbce0ce3983 100644 --- a/dlls/msi/script.c +++ b/dlls/msi/script.c @@ -111,21 +111,21 @@ DWORD call_script(MSIHANDLE hPackage, INT type, LPCWSTR script, LPCWSTR function /* Create the scripting engine */ if ((type & 7) == msidbCustomActionTypeJScript) - hr = CLSIDFromProgID(szJScript, &clsid); + hr = CLSIDFromProgID(szJScript, &clsid); else if ((type & 7) == msidbCustomActionTypeVBScript) - hr = CLSIDFromProgID(szVBScript, &clsid); + hr = CLSIDFromProgID(szVBScript, &clsid); else { - ERR("Unknown script type %d\n", type); - goto done; + ERR("Unknown script type %d\n", type); + goto done; } if (FAILED(hr)) { - ERR("Could not find CLSID for Windows Script\n"); - goto done; + ERR("Could not find CLSID for Windows Script\n"); + goto done; } hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IActiveScript, (void **)&pActiveScript); if (FAILED(hr)) { - ERR("Could not instantiate class for Windows Script\n"); - goto done; + ERR("Could not instantiate class for Windows Script\n"); + goto done; } /* If we got this far, Windows Script is installed, so don't return success by default anymore */ @@ -156,29 +156,29 @@ DWORD call_script(MSIHANDLE hPackage, INT type, LPCWSTR script, LPCWSTR function /* Call a function if necessary through the IDispatch interface */ if (function != NULL && strlenW(function) > 0) { - TRACE("Calling function %s\n", debugstr_w(function)); + TRACE("Calling function %s\n", debugstr_w(function)); - hr = IActiveScript_GetScriptDispatch(pActiveScript, NULL, &pDispatch); - if (FAILED(hr)) goto done; + hr = IActiveScript_GetScriptDispatch(pActiveScript, NULL, &pDispatch); + if (FAILED(hr)) goto done; - hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, (WCHAR **)&function, 1,LOCALE_USER_DEFAULT, &dispid); - if (FAILED(hr)) goto done; + hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, (WCHAR **)&function, 1,LOCALE_USER_DEFAULT, &dispid); + if (FAILED(hr)) goto done; - hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparamsNoArgs, &var, NULL, NULL); - if (FAILED(hr)) goto done; + hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparamsNoArgs, &var, NULL, NULL); + if (FAILED(hr)) goto done; - /* Check return value, if it's not IDOK we failed */ - hr = VariantChangeType(&var, &var, 0, VT_I4); - if (FAILED(hr)) goto done; + /* Check return value, if it's not IDOK we failed */ + hr = VariantChangeType(&var, &var, 0, VT_I4); + if (FAILED(hr)) goto done; - if (V_I4(&var) == IDOK) - ret = ERROR_SUCCESS; - else ret = ERROR_INSTALL_FAILURE; + if (V_I4(&var) == IDOK) + ret = ERROR_SUCCESS; + else ret = ERROR_INSTALL_FAILURE; - VariantClear(&var); + VariantClear(&var); } else { - /* If no function to be called, MSI behavior is to succeed */ - ret = ERROR_SUCCESS; + /* If no function to be called, MSI behavior is to succeed */ + ret = ERROR_SUCCESS; } done: @@ -187,9 +187,9 @@ done: if (pDispatch) IDispatch_Release(pDispatch); if (pActiveScript) IActiveScriptSite_Release(pActiveScript); if (pActiveScriptSite && - pActiveScriptSite->pSession) IUnknown_Release((IUnknown *)pActiveScriptSite->pSession); + pActiveScriptSite->pSession) IUnknown_Release((IUnknown *)pActiveScriptSite->pSession); if (pActiveScriptSite && - pActiveScriptSite->pInstaller) IUnknown_Release((IUnknown *)pActiveScriptSite->pInstaller); + pActiveScriptSite->pInstaller) IUnknown_Release((IUnknown *)pActiveScriptSite->pInstaller); if (pActiveScriptSite) IUnknown_Release((IUnknown *)pActiveScriptSite); CoUninitialize(); /* must call even if CoInitialize failed */ @@ -258,21 +258,21 @@ static HRESULT WINAPI MsiActiveScriptSite_GetItemInfo(IActiveScriptSite* iface, /* Determine the kind of pointer that is requested, and make sure placeholder is valid */ if (dwReturnMask & SCRIPTINFO_ITYPEINFO) { - if (!ppti) return E_INVALIDARG; - *ppti = NULL; + if (!ppti) return E_INVALIDARG; + *ppti = NULL; } if (dwReturnMask & SCRIPTINFO_IUNKNOWN) { - if (!ppiunkItem) return E_INVALIDARG; - *ppiunkItem = NULL; + if (!ppiunkItem) return E_INVALIDARG; + *ppiunkItem = NULL; } /* Are we looking for the session object? */ if (!strcmpW(szSession, pstrName)) { - if (dwReturnMask & SCRIPTINFO_ITYPEINFO) - return load_type_info(This->pSession, ppti, &DIID_Session, 0); - else if (dwReturnMask & SCRIPTINFO_IUNKNOWN) { - IDispatch_QueryInterface(This->pSession, &IID_IUnknown, (void **)ppiunkItem); - return S_OK; + if (dwReturnMask & SCRIPTINFO_ITYPEINFO) + return load_type_info(This->pSession, ppti, &DIID_Session, 0); + else if (dwReturnMask & SCRIPTINFO_IUNKNOWN) { + IDispatch_QueryInterface(This->pSession, &IID_IUnknown, (void **)ppiunkItem); + return S_OK; } } @@ -296,33 +296,33 @@ static HRESULT WINAPI MsiActiveScriptSite_OnScriptTerminate(IActiveScriptSite* i static HRESULT WINAPI MsiActiveScriptSite_OnStateChange(IActiveScriptSite* iface, SCRIPTSTATE ssScriptState) { switch (ssScriptState) { - case SCRIPTSTATE_UNINITIALIZED: - TRACE("State: Uninitialized.\n"); - break; + case SCRIPTSTATE_UNINITIALIZED: + TRACE("State: Uninitialized.\n"); + break; - case SCRIPTSTATE_INITIALIZED: - TRACE("State: Initialized.\n"); - break; + case SCRIPTSTATE_INITIALIZED: + TRACE("State: Initialized.\n"); + break; - case SCRIPTSTATE_STARTED: - TRACE("State: Started.\n"); - break; + case SCRIPTSTATE_STARTED: + TRACE("State: Started.\n"); + break; - case SCRIPTSTATE_CONNECTED: - TRACE("State: Connected.\n"); - break; + case SCRIPTSTATE_CONNECTED: + TRACE("State: Connected.\n"); + break; - case SCRIPTSTATE_DISCONNECTED: - TRACE("State: Disconnected.\n"); - break; + case SCRIPTSTATE_DISCONNECTED: + TRACE("State: Disconnected.\n"); + break; - case SCRIPTSTATE_CLOSED: - TRACE("State: Closed.\n"); - break; + case SCRIPTSTATE_CLOSED: + TRACE("State: Closed.\n"); + break; - default: - ERR("Unknown State: %d\n", ssScriptState); - break; + default: + ERR("Unknown State: %d\n", ssScriptState); + break; } return S_OK; @@ -338,7 +338,7 @@ static HRESULT WINAPI MsiActiveScriptSite_OnScriptError(IActiveScriptSite* iface hr = IActiveScriptError_GetExceptionInfo(pscripterror, &exception); if (SUCCEEDED(hr)) - ERR("script error: %s\n", debugstr_w(exception.bstrDescription)); + ERR("script error: %s\n", debugstr_w(exception.bstrDescription)); return S_OK; } diff --git a/dlls/msi/tests/automation.c b/dlls/msi/tests/automation.c index c9ff1f8f2fd..9bd7d03517b 100644 --- a/dlls/msi/tests/automation.c +++ b/dlls/msi/tests/automation.c @@ -443,8 +443,8 @@ static void test_dispid(void) ok( get_dispid( pInstaller, "FileVersion" ) == 16, "dispid wrong\n"); } ok( get_dispid( pInstaller, "ProductState" ) == 17, "dispid wrong\n"); - todo_wine { ok( get_dispid( pInstaller, "ProductInfo" ) == 18, "dispid wrong\n"); + todo_wine { ok( get_dispid( pInstaller, "ConfigureProduct" ) == 19, "dispid wrong\n"); ok( get_dispid( pInstaller, "ReinstallProduct" ) == 20 , "dispid wrong\n"); ok( get_dispid( pInstaller, "CollectUserInfo" ) == 21, "dispid wrong\n"); @@ -526,7 +526,7 @@ static void test_dispatch(void) /* Test getting ID of a function name that does exist */ name = (WCHAR *)szOpenPackage; hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid); - ok(SUCCEEDED(hr), "IDispatch::GetIDsOfNames returned 0x%08x\n", hr); + ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr); /* Test invoking this function (without parameters passed) */ if (0) /* All of these crash MSI on Windows XP */ @@ -570,7 +570,7 @@ static void test_dispatch(void) /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */ name = (WCHAR *)szProductState; hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid); - ok(SUCCEEDED(hr), "IDispatch::GetIDsOfNames returned 0x%08x\n", hr); + ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr); dispparams.rgvarg = NULL; dispparams.cArgs = 0; @@ -601,19 +601,19 @@ static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARA len = MultiByteToWideChar(CP_ACP, 0, szName, -1, name, len ); hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid); HeapFree(GetProcessHeap(), 0, name); - ok(SUCCEEDED(hr), "IDispatch::GetIDsOfNames returned 0x%08x\n", hr); - if (!SUCCEEDED(hr)) return hr; + ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr); + if (!hr == S_OK) return hr; memset(&excepinfo, 0, sizeof(excepinfo)); hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL); - if (SUCCEEDED(hr)) + if (hr == S_OK) { ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult); if (vtResult != VT_EMPTY) { hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult); - ok(SUCCEEDED(hr), "VariantChangeTypeEx returned 0x%08x\n", hr); + ok(hr == S_OK, "VariantChangeTypeEx returned 0x%08x\n", hr); } } @@ -684,7 +684,7 @@ static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValu V_BSTR(&vararg) = SysAllocString(szValue); hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR); - lstrcpyW(szString, V_BSTR(&varresult)); + if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult)); VariantClear(&varresult); return hr; } @@ -804,14 +804,14 @@ static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringL return hr; } -static HRESULT Installer_VersionGet(LPCWSTR szVersion) +static HRESULT Installer_VersionGet(LPWSTR szVersion) { VARIANT varresult; DISPPARAMS dispparams = {NULL, NULL, 0, 0}; HRESULT hr; hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR); - lstrcpyW((WCHAR *)szVersion, V_BSTR(&varresult)); + if (V_BSTR(&varresult)) lstrcpyW(szVersion, V_BSTR(&varresult)); VariantClear(&varresult); return hr; } @@ -827,7 +827,7 @@ static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst) return hr; } -static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPCWSTR szReturn) +static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR szReturn) { VARIANT varresult; VARIANTARG vararg[1]; @@ -839,7 +839,7 @@ static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPCWSTR V_BSTR(&vararg[0]) = SysAllocString(szName); hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR); - lstrcpyW((WCHAR *)szReturn, V_BSTR(&varresult)); + if (V_BSTR(&varresult)) lstrcpyW(szReturn, V_BSTR(&varresult)); VariantClear(&varresult); return hr; } @@ -1089,7 +1089,7 @@ static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount) return hr; } -static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPCWSTR szString) +static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString) { VARIANT varresult; VARIANTARG vararg[1]; @@ -1101,7 +1101,7 @@ static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPCWSTR szSt V_I4(&vararg[0]) = iField; hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR); - lstrcpyW((WCHAR *)szString, V_BSTR(&varresult)); + if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult)); VariantClear(&varresult); return hr; } @@ -1157,6 +1157,15 @@ static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue) return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY); } +static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT) +{ + VARIANT varresult; + DISPPARAMS dispparams = {NULL, NULL, 0, 0}; + HRESULT hr = invoke(pList, "_NewEnum", DISPATCH_METHOD, &dispparams, &varresult, VT_UNKNOWN); + *ppEnumVARIANT = V_UNKNOWN(&varresult); + return hr; +} + static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString) { VARIANT varresult; @@ -1169,7 +1178,7 @@ static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szStri V_I4(&vararg[0]) = iIndex; hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR); - lstrcpyW(szString, V_BSTR(&varresult)); + if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult)); VariantClear(&varresult); return hr; } @@ -1197,36 +1206,36 @@ static void test_Database(IDispatch *pDatabase) HRESULT hr; hr = Database_OpenView(pDatabase, szSql, &pView); - ok(SUCCEEDED(hr), "Database_OpenView failed, hresult 0x%08x\n", hr); - if (SUCCEEDED(hr)) + ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr); + if (hr == S_OK) { IDispatch *pRecord = NULL; WCHAR szString[MAX_PATH]; /* View::Execute */ hr = View_Execute(pView, NULL); - ok(SUCCEEDED(hr), "View_Execute failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr); /* View::Fetch */ hr = View_Fetch(pView, &pRecord); - ok(SUCCEEDED(hr), "View_Fetch failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr); ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n"); if (pRecord) { /* Record::StringDataGet */ memset(szString, 0, sizeof(szString)); hr = Record_StringDataGet(pRecord, 1, szString); - ok(SUCCEEDED(hr), "Record_StringDataGet failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr); ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree); /* Record::StringDataPut with correct index */ hr = Record_StringDataPut(pRecord, 1, szTwo); - ok(SUCCEEDED(hr), "Record_StringDataPut failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr); /* Record::StringDataGet */ memset(szString, 0, sizeof(szString)); hr = Record_StringDataGet(pRecord, 1, szString); - ok(SUCCEEDED(hr), "Record_StringDataGet failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr); ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo); /* Record::StringDataPut with incorrect index */ @@ -1250,12 +1259,12 @@ static void test_Database(IDispatch *pDatabase) /* View::Modify with MSIMODIFY_REFRESH should undo our changes */ hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord); /* Wine's MsiViewModify currently does not support MSIMODIFY_REFRESH */ - todo_wine ok(SUCCEEDED(hr), "View_Modify failed, hresult 0x%08x\n", hr); + todo_wine ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr); /* Record::StringDataGet, confirm that the record is back to its unmodified value */ memset(szString, 0, sizeof(szString)); hr = Record_StringDataGet(pRecord, 1, szString); - ok(SUCCEEDED(hr), "Record_StringDataGet failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr); todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree); IDispatch_Release(pRecord); @@ -1263,14 +1272,14 @@ static void test_Database(IDispatch *pDatabase) /* View::Fetch */ hr = View_Fetch(pView, &pRecord); - ok(SUCCEEDED(hr), "View_Fetch failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr); ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n"); if (pRecord) { /* Record::StringDataGet */ memset(szString, 0, sizeof(szString)); hr = Record_StringDataGet(pRecord, 1, szString); - ok(SUCCEEDED(hr), "Record_StringDataGet failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr); ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo); IDispatch_Release(pRecord); @@ -1278,14 +1287,14 @@ static void test_Database(IDispatch *pDatabase) /* View::Fetch */ hr = View_Fetch(pView, &pRecord); - ok(SUCCEEDED(hr), "View_Fetch failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr); ok(pRecord == NULL, "View_Fetch should have returned NULL record\n"); if (pRecord) IDispatch_Release(pRecord); /* View::Close */ hr = View_Close(pView); - ok(SUCCEEDED(hr), "View_Close failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr); IDispatch_Release(pView); } @@ -1313,14 +1322,14 @@ static void test_Session(IDispatch *pSession) /* Session::Installer */ hr = Session_Installer(pSession, &pInst); - ok(SUCCEEDED(hr), "Session_Installer failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr); ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n"); ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n"); /* Session::Property, get */ memset(stringw, 0, sizeof(stringw)); hr = Session_PropertyGet(pSession, szProductName, stringw); - ok(SUCCEEDED(hr), "Session_PropertyGet failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr); if (lstrcmpW(stringw, szMSITEST) != 0) { len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL); @@ -1330,10 +1339,10 @@ static void test_Session(IDispatch *pSession) /* Session::Property, put */ hr = Session_PropertyPut(pSession, szProductName, szProductName); - ok(SUCCEEDED(hr), "Session_PropertyPut failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr); memset(stringw, 0, sizeof(stringw)); hr = Session_PropertyGet(pSession, szProductName, stringw); - ok(SUCCEEDED(hr), "Session_PropertyGet failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr); if (lstrcmpW(stringw, szProductName) != 0) { len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL); @@ -1348,31 +1357,31 @@ static void test_Session(IDispatch *pSession) /* Try putting a property using illegal property identifier */ hr = Session_PropertyPut(pSession, szEquals, szProductName); - ok(SUCCEEDED(hr), "Session_PropertyPut failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr); /* Session::Language, get */ hr = Session_LanguageGet(pSession, &len); - ok(SUCCEEDED(hr), "Session_LanguageGet failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr); /* Not sure how to check the language is correct */ /* Session::Mode, get */ hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool); - ok(SUCCEEDED(hr), "Session_ModeGet failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr); todo_wine ok(!bool, "Reboot at end session mode is %d\n", bool); /* Session::Mode, put */ hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, TRUE); - todo_wine ok(SUCCEEDED(hr), "Session_ModePut failed, hresult 0x%08x\n", hr); + todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr); hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool); - ok(SUCCEEDED(hr), "Session_ModeGet failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr); ok(bool, "Reboot at end session mode is %d, expected 1\n", bool); hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, FALSE); /* set it again so we don't reboot */ - todo_wine ok(SUCCEEDED(hr), "Session_ModePut failed, hresult 0x%08x\n", hr); + todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr); /* Session::Database, get */ hr = Session_Database(pSession, &pDatabase); - ok(SUCCEEDED(hr), "Session_Database failed, hresult 0x%08x\n", hr); - if (SUCCEEDED(hr)) + ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr); + if (hr == S_OK) { test_Database(pDatabase); IDispatch_Release(pDatabase); @@ -1380,54 +1389,54 @@ static void test_Session(IDispatch *pSession) /* Session::EvaluateCondition */ hr = Session_EvaluateCondition(pSession, NULL, &myint); - ok(SUCCEEDED(hr), "Session_EvaluateCondition failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr); ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN); hr = Session_EvaluateCondition(pSession, szEmpty, &myint); - ok(SUCCEEDED(hr), "Session_EvaluateCondition failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr); ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN); hr = Session_EvaluateCondition(pSession, szEquals, &myint); - ok(SUCCEEDED(hr), "Session_EvaluateCondition failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr); ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN); /* Session::DoAction(CostInitialize) must occur before the next statements */ hr = Session_DoAction(pSession, szCostInitialize, &myint); - ok(SUCCEEDED(hr), "Session_DoAction failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr); ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK); /* Session::SetInstallLevel */ hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM); - ok(SUCCEEDED(hr), "Session_SetInstallLevel failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr); /* Session::FeatureCurrentState, get */ hr = Session_FeatureCurrentState(pSession, szOne, &myint); - ok(SUCCEEDED(hr), "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr); ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN); /* Session::EvaluateCondition */ hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint); - ok(SUCCEEDED(hr), "Session_EvaluateCondition failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr); ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN); hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint); - ok(SUCCEEDED(hr), "Session_EvaluateCondition failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr); ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN); /* Session::FeatureRequestState, put */ hr = Session_FeatureRequestStatePut(pSession, szOne, INSTALLSTATE_ADVERTISED); - ok(SUCCEEDED(hr), "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr); hr = Session_FeatureRequestStateGet(pSession, szOne, &myint); - ok(SUCCEEDED(hr), "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr); ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED); /* Session::EvaluateCondition */ hr = Session_EvaluateCondition(pSession, szOneActionFalse, &myint); - ok(SUCCEEDED(hr), "Session_EvaluateCondition failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr); ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN); hr = Session_EvaluateCondition(pSession, szOneActionTrue, &myint); - ok(SUCCEEDED(hr), "Session_EvaluateCondition failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr); ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN); } @@ -1481,7 +1490,7 @@ static void test_Installer_RegistryValue(void) /* Does our key exist? Shouldn't; check with all three possible value parameter types */ hr = Installer_RegistryValueE(HKEY_CURRENT_USER, szKey, &bRet); - ok(SUCCEEDED(hr), "Installer_RegistryValueE failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr); ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n"); memset(szString, 0, sizeof(szString)); @@ -1519,12 +1528,12 @@ static void test_Installer_RegistryValue(void) /* Does our key exist? It should, and make sure we retrieve the correct default value */ bRet = FALSE; hr = Installer_RegistryValueE(HKEY_CURRENT_USER, szKey, &bRet); - ok(SUCCEEDED(hr), "Installer_RegistryValueE failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr); ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n"); memset(szString, 0, sizeof(szString)); hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, NULL, szString); - ok(SUCCEEDED(hr), "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne); /* Ask for the value of a nonexistent key */ @@ -1535,71 +1544,71 @@ static void test_Installer_RegistryValue(void) /* Get values of keys */ memset(szString, 0, sizeof(szString)); hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szOne, szString); - ok(SUCCEEDED(hr), "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne); VariantInit(&vararg); V_VT(&vararg) = VT_BSTR; V_BSTR(&vararg) = SysAllocString(szTwo); hr = Installer_RegistryValue(HKEY_CURRENT_USER, szKey, vararg, &varresult, VT_I4); - ok(SUCCEEDED(hr), "Installer_RegistryValue failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr); ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult)); VariantClear(&varresult); memset(szString, 0, sizeof(szString)); hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szThree, szString); - ok(SUCCEEDED(hr), "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY); memset(szString, 0, sizeof(szString)); hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szFour, szString); - ok(SUCCEEDED(hr), "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour); memset(szString, 0, sizeof(szString)); hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szFive, szString); - ok(SUCCEEDED(hr), "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFiveHi); memset(szString, 0, sizeof(szString)); hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szSix, szString); - ok(SUCCEEDED(hr), "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_); VariantInit(&vararg); V_VT(&vararg) = VT_BSTR; V_BSTR(&vararg) = SysAllocString(szSeven); hr = Installer_RegistryValue(HKEY_CURRENT_USER, szKey, vararg, &varresult, VT_EMPTY); - ok(SUCCEEDED(hr), "Installer_RegistryValue failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr); /* Get string class name for the key */ memset(szString, 0, sizeof(szString)); hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 0, szString, VT_BSTR); - ok(SUCCEEDED(hr), "Installer_RegistryValueI failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr); ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank); /* Get name of a value by positive number (RegEnumValue like), valid index */ memset(szString, 0, sizeof(szString)); hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 2, szString, VT_BSTR); - ok(SUCCEEDED(hr), "Installer_RegistryValueI failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr); /* RegEnumValue order seems different on wine */ todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo); /* Get name of a value by positive number (RegEnumValue like), invalid index */ memset(szString, 0, sizeof(szString)); hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 10, szString, VT_EMPTY); - ok(SUCCEEDED(hr), "Installer_RegistryValueI failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr); /* Get name of a subkey by negative number (RegEnumValue like), valid index */ memset(szString, 0, sizeof(szString)); hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, -1, szString, VT_BSTR); - ok(SUCCEEDED(hr), "Installer_RegistryValueI failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr); ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight); /* Get name of a subkey by negative number (RegEnumValue like), invalid index */ memset(szString, 0, sizeof(szString)); hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, -10, szString, VT_EMPTY); - ok(SUCCEEDED(hr), "Installer_RegistryValueI failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr); /* clean up */ delete_key(hkey); @@ -1678,55 +1687,53 @@ static void test_Installer_InstallProduct(LPCWSTR szPath) /* Installer::InstallProduct */ hr = Installer_InstallProduct(szMsifile, NULL); - ok(SUCCEEDED(hr), "Installer_InstallProduct failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr); /* Installer::ProductState for our product code, which has been installed */ hr = Installer_ProductState(szProductCode, &iValue); - ok(SUCCEEDED(hr), "Installer_ProductState failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr); ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT); /* Installer::ProductInfo for our product code */ - todo_wine - { - /* NULL attribute */ - memset(szString, 0, sizeof(szString)); - hr = Installer_ProductInfo(szProductCode, NULL, szString); - ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr); - ok_exception(hr, szProductInfoException); - /* Non-existent attribute */ - memset(szString, 0, sizeof(szString)); - hr = Installer_ProductInfo(szProductCode, szMsifile, szString); - ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr); - ok_exception(hr, szProductInfoException); + /* NULL attribute */ + memset(szString, 0, sizeof(szString)); + hr = Installer_ProductInfo(szProductCode, NULL, szString); + ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr); + ok_exception(hr, szProductInfoException); - /* Package name */ - memset(szString, 0, sizeof(szString)); - hr = Installer_ProductInfo(szProductCode, INSTALLPROPERTY_PACKAGENAMEW, szString); - ok(SUCCEEDED(hr), "Installer_ProductInfo failed, hresult 0x%08x\n", hr); - ok_w2("StringList_Item returned %s but expected %s\n", szString, szMsifile); + /* Non-existent attribute */ + memset(szString, 0, sizeof(szString)); + hr = Installer_ProductInfo(szProductCode, szMsifile, szString); + ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr); + ok_exception(hr, szProductInfoException); - /* Product name */ - memset(szString, 0, sizeof(szString)); - hr = Installer_ProductInfo(szProductCode, INSTALLPROPERTY_PRODUCTNAMEW, szString); - ok(SUCCEEDED(hr), "Installer_ProductInfo failed, hresult 0x%08x\n", hr); - ok_w2("StringList_Item returned %s but expected %s\n", szString, szMSITEST); - } + /* Package name */ + memset(szString, 0, sizeof(szString)); + hr = Installer_ProductInfo(szProductCode, INSTALLPROPERTY_PACKAGENAMEW, szString); + todo_wine ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr); + todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile); + + /* Product name */ + memset(szString, 0, sizeof(szString)); + hr = Installer_ProductInfo(szProductCode, INSTALLPROPERTY_PRODUCTNAMEW, szString); + ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr); + ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST); /* Installer::RelatedProducts for our upgrade code */ hr = Installer_RelatedProducts(szUpgradeCode, &pStringList); - ok(SUCCEEDED(hr), "Installer_RelatedProducts failed, hresult 0x%08x\n", hr); - if (SUCCEEDED(hr)) + ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr); + if (hr == S_OK) { /* StringList::Count */ hr = StringList_Count(pStringList, &iCount); - ok(SUCCEEDED(hr), "StringList_Count failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr); ok(iCount == 1, "Expected one related product but found %d\n", iCount); /* StringList::Item */ memset(szString, 0, sizeof(szString)); hr = StringList_Item(pStringList, 0, szString); - ok(SUCCEEDED(hr), "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr); + ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr); ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode); IDispatch_Release(pStringList); @@ -1833,28 +1840,28 @@ static void test_Installer(void) /* Test for success */ hr = Installer_CreateRecord(1, &pRecord); - ok(SUCCEEDED(hr), "Installer_CreateRecord failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr); ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n"); if (pRecord) { /* Record::FieldCountGet */ hr = Record_FieldCountGet(pRecord, &iValue); - ok(SUCCEEDED(hr), "Record_FiledCountGet failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr); ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue); /* Record::IntegerDataGet */ hr = Record_IntegerDataGet(pRecord, 1, &iValue); - ok(SUCCEEDED(hr), "Record_IntegerDataGet failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr); ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER); /* Record::IntegerDataGet, bad index */ hr = Record_IntegerDataGet(pRecord, 10, &iValue); - ok(SUCCEEDED(hr), "Record_IntegerDataGet failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr); ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER); /* Record::IntegerDataPut */ hr = Record_IntegerDataPut(pRecord, 1, 100); - ok(SUCCEEDED(hr), "Record_IntegerDataPut failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr); /* Record::IntegerDataPut, bad index */ hr = Record_IntegerDataPut(pRecord, 10, 100); @@ -1863,7 +1870,7 @@ static void test_Installer(void) /* Record::IntegerDataGet */ hr = Record_IntegerDataGet(pRecord, 1, &iValue); - ok(SUCCEEDED(hr), "Record_IntegerDataGet failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr); ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue); IDispatch_Release(pRecord); @@ -1881,8 +1888,8 @@ static void test_Installer(void) /* Installer::OpenPackage */ hr = Installer_OpenPackage(szPath, 0, &pSession); - ok(SUCCEEDED(hr), "Installer_OpenPackage failed, hresult 0x%08x\n", hr); - if (SUCCEEDED(hr)) + ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr); + if (hr == S_OK) { test_Session(pSession); IDispatch_Release(pSession); @@ -1893,30 +1900,125 @@ static void test_Installer(void) /* Installer::Products */ hr = Installer_Products(&pStringList); - ok(SUCCEEDED(hr), "Installer_Products failed, hresult 0x%08x\n", hr); - if (SUCCEEDED(hr)) + ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr); + if (hr == S_OK) { int idx; + IUnknown *pUnk = NULL; + IEnumVARIANT *pEnum = NULL; + VARIANT var; + ULONG celt; + + /* StringList::_NewEnum */ + hr = StringList__NewEnum(pStringList, &pUnk); + ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr); + if (hr == S_OK) + { + hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum); + ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr); + } + if (!pEnum) + skip("IEnumVARIANT tests\n"); /* StringList::Count */ hr = StringList_Count(pStringList, &iCount); - ok(SUCCEEDED(hr), "StringList_Count failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr); for (idx=0; idx(%s, %p)\n", This, debugstr_w(tagName), resultList); - name = xmlChar_from_wchar((WCHAR*)tagName); - *resultList = create_filtered_nodelist((xmlNodePtr)get_doc(This), name, TRUE); - HeapFree(GetProcessHeap(), 0, name); + szPattern = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(2+lstrlenW(tagName)+1)); + szPattern[0] = szPattern[1] = '/'; + lstrcpyW(szPattern + 2, tagName); - if(!*resultList) return S_FALSE; - return S_OK; + hr = queryresult_create((xmlNodePtr)get_doc(This), szPattern, resultList); + HeapFree(GetProcessHeap(), 0, szPattern); + + return hr; } static DOMNodeType get_node_type(VARIANT Type) diff --git a/dlls/msxml3/element.c b/dlls/msxml3/element.c index 7997b2fb409..e7f03d676e8 100644 --- a/dlls/msxml3/element.c +++ b/dlls/msxml3/element.c @@ -555,10 +555,24 @@ static HRESULT WINAPI domelem_removeAttributeNode( static HRESULT WINAPI domelem_getElementsByTagName( IXMLDOMElement *iface, - BSTR p, IXMLDOMNodeList** resultList) + BSTR bstrName, IXMLDOMNodeList** resultList) { - FIXME("\n"); - return E_NOTIMPL; + domelem *This = impl_from_IXMLDOMElement( iface ); + LPWSTR szPattern; + HRESULT hr; + + TRACE("(%p)->(%s,%p)\n", This, debugstr_w(bstrName), resultList); + + szPattern = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(3+lstrlenW(bstrName)+1)); + szPattern[0] = '.'; + szPattern[1] = szPattern[2] = '/'; + lstrcpyW(szPattern+3, bstrName); + TRACE("%s\n", debugstr_w(szPattern)); + + hr = queryresult_create(get_element(This), szPattern, resultList); + HeapFree(GetProcessHeap(), 0, szPattern); + + return hr; } static HRESULT WINAPI domelem_normalize( diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h index 4f459b9bd93..39aaa00eaf4 100644 --- a/dlls/msxml3/msxml_private.h +++ b/dlls/msxml3/msxml_private.h @@ -41,9 +41,10 @@ extern IUnknown *create_attribute( xmlNodePtr attribute ); extern IUnknown *create_text( xmlNodePtr text ); extern IUnknown *create_pi( xmlNodePtr pi ); extern IUnknown *create_comment( xmlNodePtr comment ); -extern IXMLDOMNodeList *create_nodelist( xmlNodePtr node ); +extern IXMLDOMNodeList *create_children_nodelist( xmlNodePtr ); extern IXMLDOMNamedNodeMap *create_nodemap( IXMLDOMNode *node ); -extern IXMLDOMNodeList *create_filtered_nodelist( xmlNodePtr, const xmlChar *, BOOL ); + +extern HRESULT queryresult_create( xmlNodePtr, LPWSTR, IXMLDOMNodeList ** ); extern void attach_xmlnode( IXMLDOMNode *node, xmlNodePtr xmlnode ); diff --git a/dlls/msxml3/node.c b/dlls/msxml3/node.c index 512e4e9e90f..8c48ecf9aba 100644 --- a/dlls/msxml3/node.c +++ b/dlls/msxml3/node.c @@ -311,23 +311,10 @@ static HRESULT WINAPI xmlnode_get_childNodes( if ( !childList ) return E_INVALIDARG; - switch(This->node->type) - { - case XML_ELEMENT_NODE: - *childList = create_filtered_nodelist( This->node->children, (const xmlChar *)"*", FALSE ); - break; + *childList = create_children_nodelist(This->node); + if (*childList == NULL) + return E_OUTOFMEMORY; - case XML_ATTRIBUTE_NODE: - *childList = create_filtered_nodelist( This->node->children, (const xmlChar *)"node()", FALSE ); - break; - - default: - FIXME("unhandled node type %d\n", This->node->type); - break; - } - - if (!*childList) - return S_FALSE; return S_OK; } @@ -658,21 +645,10 @@ static HRESULT WINAPI xmlnode_selectNodes( IXMLDOMNodeList** resultList) { xmlnode *This = impl_from_IXMLDOMNode( iface ); - xmlChar *str = NULL; - HRESULT r = E_FAIL; TRACE("%p %s %p\n", This, debugstr_w(queryString), resultList ); - str = xmlChar_from_wchar( queryString ); - if (!str) - return r; - - if( !This->node->children ) - return S_FALSE; - - *resultList = create_filtered_nodelist( This->node->children, str, FALSE ); - HeapFree( GetProcessHeap(), 0, str ); - return S_OK; + return queryresult_create( This->node, queryString, resultList ); } static HRESULT WINAPI xmlnode_selectSingleNode( @@ -686,6 +662,7 @@ static HRESULT WINAPI xmlnode_selectSingleNode( TRACE("%p %s %p\n", This, debugstr_w(queryString), resultNode ); + *resultNode = NULL; r = IXMLDOMNode_selectNodes(iface, queryString, &list); if(r == S_OK) { diff --git a/dlls/msxml3/nodelist.c b/dlls/msxml3/nodelist.c index a1b43060c12..9b1aa904833 100644 --- a/dlls/msxml3/nodelist.c +++ b/dlls/msxml3/nodelist.c @@ -33,147 +33,25 @@ #include "wine/debug.h" +/* This file implements the object returned by childNodes property. Note that this is + * not the IXMLDOMNodeList returned by XPath querites - it's implemented in queryresult.c. + * They are different because the list returned by childNodes: + * - is "live" - changes to the XML tree are automatically reflected in the list + * - doesn't supports IXMLDOMSelection + * - note that an attribute node have a text child in DOM but not in the XPath data model + * thus the child is inaccessible by an XPath query + */ + WINE_DEFAULT_DEBUG_CHANNEL(msxml); #ifdef HAVE_LIBXML2 -#ifdef HAVE_LIBXSLT - -#ifdef HAVE_LIBXSLT_PATTERN_H -#include -#endif -#ifdef HAVE_LIBXSLT_TRANSFORM_H -#include -#endif - -struct xslt_info { - xsltTransformContextPtr ctxt; - xsltCompMatchPtr pattern; - xsltStylesheetPtr sheet; -}; - -static void xslt_info_init( struct xslt_info *info ) -{ - info->ctxt = NULL; - info->pattern = NULL; - info->sheet = NULL; -} - -static int create_xslt_parser( struct xslt_info *info, xmlNodePtr node, const xmlChar *str ) -{ - if(!node) return 1; - - info->sheet = xsltNewStylesheet(); - if (!info->sheet) - return 0; - - info->ctxt = xsltNewTransformContext( info->sheet, node->doc ); - if (!info->ctxt) - return 0; - - info->pattern = xsltCompilePattern( str, node->doc, - node, info->sheet, info->ctxt ); - if (!info->pattern) - return 0; - return 1; -} - -static void free_xslt_info( struct xslt_info *info ) -{ - if (info->pattern) - xsltFreeCompMatchList( info->pattern ); - if (info->sheet) - xsltFreeStylesheet( info->sheet ); - if (info->ctxt) - xsltFreeTransformContext( info->ctxt ); -} - - -static xmlNodePtr get_next_node( struct xslt_info *info, xmlNodePtr node, xmlNodePtr *top_level_node ); - -static HRESULT xslt_next_match( struct xslt_info *info, xmlNodePtr *node, xmlNodePtr *top_level_node ) -{ - if (!info->ctxt) - return S_FALSE; - - /* make sure that the current element matches the pattern */ - while ( *node ) - { - int r; - - r = xsltTestCompMatchList( info->ctxt, *node, info->pattern ); - if ( 1 == r ) - { - TRACE("Matched %p (%s)\n", *node, (*node)->name ); - return S_OK; - } - if (r != 0) - { - ERR("Pattern match failed\n"); - return E_FAIL; - } - *node = get_next_node(info, *node, top_level_node); - } - return S_OK; -} - -#else - -struct xslt_info { - /* empty */ -}; - -static void xslt_info_init( struct xslt_info *info ) -{ -} - -void free_xslt_info( struct xslt_info *info ) -{ -} - -static int create_xslt_parser( struct xslt_info *info, xmlNodePtr node, const xmlChar *str ) -{ - MESSAGE("libxslt was missing at compile time\n"); - return 0; -} - -static HRESULT xslt_next_match( struct xslt_info *info, xmlNodePtr *node, xmlNodePtr *top_level_node ) -{ - return S_FALSE; -} - -#endif - -static xmlNodePtr get_next_node( struct xslt_info *info, xmlNodePtr node, xmlNodePtr *top_level_node ) -{ - if(!top_level_node) return node->next; - - if(node->children) return node->children; - if(node->next) - { - if(node == *top_level_node) - *top_level_node = node->next; - return node->next; - } - - if(node != *top_level_node && node->parent) - { - if(node->parent == *top_level_node) - *top_level_node = node->parent->next; - return node->parent->next; - } - return NULL; -} - typedef struct _xmlnodelist { const struct IXMLDOMNodeListVtbl *lpVtbl; LONG ref; - xmlNodePtr node; + xmlNodePtr parent; xmlNodePtr current; - xmlNodePtr top_level_node; - BOOL enum_children; - struct xslt_info xinfo; } xmlnodelist; static inline xmlnodelist *impl_from_IXMLDOMNodeList( IXMLDOMNodeList *iface ) @@ -222,8 +100,7 @@ static ULONG WINAPI xmlnodelist_Release( ref = InterlockedDecrement( &This->ref ); if ( ref == 0 ) { - free_xslt_info( &This->xinfo ); - if(This->node) xmldoc_release( This->node->doc ); + xmldoc_release( This->parent->doc ); HeapFree( GetProcessHeap(), 0, This ); } @@ -281,10 +158,8 @@ static HRESULT WINAPI xmlnodelist_get_item( IXMLDOMNode** listItem) { xmlnodelist *This = impl_from_IXMLDOMNodeList( iface ); - xmlNodePtr curr, tmp; - xmlNodePtr *top_level_node = NULL; + xmlNodePtr curr; long nodeIndex = 0; - HRESULT r; TRACE("%p %ld\n", This, index); @@ -293,20 +168,11 @@ static HRESULT WINAPI xmlnodelist_get_item( if (index < 0) return S_FALSE; - curr = This->node; - - if(This->enum_children) - { - tmp = curr; - top_level_node = &tmp; - } - + curr = This->parent->children; while(curr) { - r = xslt_next_match( &This->xinfo, &curr, top_level_node); - if(FAILED(r) || !curr) return S_FALSE; if(nodeIndex++ == index) break; - curr = get_next_node(&This->xinfo, curr, top_level_node); + curr = curr->next; } if(!curr) return S_FALSE; @@ -320,34 +186,18 @@ static HRESULT WINAPI xmlnodelist_get_length( long* listLength) { - xmlNodePtr curr, tmp; - xmlNodePtr *top_level_node = NULL; + xmlNodePtr curr; long nodeCount = 0; - HRESULT r; xmlnodelist *This = impl_from_IXMLDOMNodeList( iface ); TRACE("%p\n", This); - if (This->node == NULL) { - *listLength = 0; - return S_OK; - } - - curr = This->node; - - if(This->enum_children) - { - tmp = curr; - top_level_node = &tmp; - } - + curr = This->parent->children; while (curr) { - r = xslt_next_match( &This->xinfo, &curr, top_level_node ); - if(FAILED(r) || !curr) break; nodeCount++; - curr = get_next_node(&This->xinfo, curr, top_level_node); + curr = curr->next; } *listLength = nodeCount; @@ -359,25 +209,16 @@ static HRESULT WINAPI xmlnodelist_nextNode( IXMLDOMNode** nextItem) { xmlnodelist *This = impl_from_IXMLDOMNodeList( iface ); - HRESULT r; - xmlNodePtr *top_level_node = NULL; TRACE("%p %p\n", This, nextItem ); *nextItem = NULL; - if(This->enum_children) - top_level_node = &This->top_level_node; - - r = xslt_next_match( &This->xinfo, &This->current, top_level_node ); - if (FAILED(r) ) - return r; - if (!This->current) return S_FALSE; *nextItem = create_node( This->current ); - This->current = get_next_node(&This->xinfo, This->current, top_level_node); + This->current = This->current->next; return S_OK; } @@ -387,7 +228,7 @@ static HRESULT WINAPI xmlnodelist_reset( xmlnodelist *This = impl_from_IXMLDOMNodeList( iface ); TRACE("%p\n", This); - This->current = This->node; + This->current = This->parent->children; return S_OK; } @@ -416,7 +257,7 @@ static const struct IXMLDOMNodeListVtbl xmlnodelist_vtbl = xmlnodelist__newEnum, }; -static xmlnodelist *new_nodelist( xmlNodePtr node ) +IXMLDOMNodeList* create_children_nodelist( xmlNodePtr node ) { xmlnodelist *nodelist; @@ -426,34 +267,12 @@ static xmlnodelist *new_nodelist( xmlNodePtr node ) nodelist->lpVtbl = &xmlnodelist_vtbl; nodelist->ref = 1; - nodelist->node = node; - nodelist->current = node; - nodelist->top_level_node = node; - nodelist->enum_children = FALSE; - xslt_info_init( &nodelist->xinfo ); + nodelist->parent = node; + nodelist->current = node->children; - if(node) xmldoc_add_ref( node->doc ); + xmldoc_add_ref( node->doc ); - return nodelist; -} - -IXMLDOMNodeList* create_nodelist( xmlNodePtr node ) -{ - xmlnodelist *nodelist = new_nodelist( node ); return (IXMLDOMNodeList*) &nodelist->lpVtbl; } -IXMLDOMNodeList* create_filtered_nodelist( xmlNodePtr node, const xmlChar *str, BOOL enum_children ) -{ - xmlnodelist *This = new_nodelist( node ); - if (create_xslt_parser( &This->xinfo, node, str )) - { - This->enum_children = enum_children; - return (IXMLDOMNodeList*) &This->lpVtbl; - } - - IXMLDOMNodeList_Release( (IXMLDOMNodeList*) &This->lpVtbl ); - return NULL; -} - #endif diff --git a/dlls/msxml3/queryresult.c b/dlls/msxml3/queryresult.c new file mode 100644 index 00000000000..85d7acaf6e5 --- /dev/null +++ b/dlls/msxml3/queryresult.c @@ -0,0 +1,293 @@ +/* + * XPath query result node list implementation (TODO: XSLPattern support) + * + * Copyright 2005 Mike McCormack + * Copyright 2007 Mikolaj Zalewski + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS + +#include "config.h" + +#include +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "ole2.h" +#include "msxml2.h" + +#include "msxml_private.h" + +#include "wine/debug.h" + +/* This file implements the object returned by a XPath query. Note that this is + * not the IXMLDOMNodeList returned by childNodes - it's implemented in nodelist.c. + * They are different because the list returned by XPath queries: + * - is static - gives the results for the XML tree as it existed during the + * execution of the query + * - supports IXMLDOMSelection (TODO) + * + * TODO: XSLPattern support + */ + +WINE_DEFAULT_DEBUG_CHANNEL(msxml); + +#ifdef HAVE_LIBXML2 + +#include + +static const struct IXMLDOMNodeListVtbl queryresult_vtbl; + +typedef struct _queryresult +{ + const struct IXMLDOMNodeListVtbl *lpVtbl; + LONG ref; + xmlNodePtr node; + xmlXPathObjectPtr result; + int resultPos; +} queryresult; + +static inline queryresult *impl_from_IXMLDOMNodeList( IXMLDOMNodeList *iface ) +{ + return (queryresult *)((char*)iface - FIELD_OFFSET(queryresult, lpVtbl)); +} + +HRESULT queryresult_create(xmlNodePtr node, LPWSTR szQuery, IXMLDOMNodeList **out) +{ + queryresult *This = CoTaskMemAlloc(sizeof(queryresult)); + xmlXPathContextPtr ctxt = xmlXPathNewContext(node->doc); + xmlChar *str = xmlChar_from_wchar(szQuery); + HRESULT hr; + + + TRACE("(%p, %s, %p)\n", node, wine_dbgstr_w(szQuery), out); + + *out = NULL; + if (This == NULL || ctxt == NULL || str == NULL) + { + hr = E_OUTOFMEMORY; + goto cleanup; + } + + This->lpVtbl = &queryresult_vtbl; + This->ref = 1; + This->resultPos = 0; + This->node = node; + xmldoc_add_ref(This->node->doc); + + ctxt->node = node; + This->result = xmlXPathEval(str, ctxt); + if (!This->result || This->result->type != XPATH_NODESET) + { + hr = E_FAIL; + goto cleanup; + } + + *out = (IXMLDOMNodeList *)This; + hr = S_OK; + TRACE("found %d matches\n", This->result->nodesetval->nodeNr); + +cleanup: + if (This != NULL && FAILED(hr)) + IXMLDOMNodeList_Release( (IXMLDOMNodeList*) &This->lpVtbl ); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); + HeapFree(GetProcessHeap(), 0, str); + return hr; +} + + +static HRESULT WINAPI queryresult_QueryInterface( + IXMLDOMNodeList *iface, + REFIID riid, + void** ppvObject ) +{ + TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject); + + if ( IsEqualGUID( riid, &IID_IUnknown ) || + IsEqualGUID( riid, &IID_IDispatch ) || + IsEqualGUID( riid, &IID_IXMLDOMNodeList ) ) + { + *ppvObject = iface; + } + else + { + FIXME("interface %s not implemented\n", debugstr_guid(riid)); + *ppvObject = NULL; + return E_NOINTERFACE; + } + + IXMLDOMNodeList_AddRef( iface ); + + return S_OK; +} + +static ULONG WINAPI queryresult_AddRef( + IXMLDOMNodeList *iface ) +{ + queryresult *This = impl_from_IXMLDOMNodeList( iface ); + return InterlockedIncrement( &This->ref ); +} + +static ULONG WINAPI queryresult_Release( + IXMLDOMNodeList *iface ) +{ + queryresult *This = impl_from_IXMLDOMNodeList( iface ); + ULONG ref; + + ref = InterlockedDecrement(&This->ref); + if ( ref == 0 ) + { + xmlXPathFreeObject(This->result); + xmldoc_release(This->node->doc); + CoTaskMemFree(This); + } + + return ref; +} + +static HRESULT WINAPI queryresult_GetTypeInfoCount( + IXMLDOMNodeList *iface, + UINT* pctinfo ) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI queryresult_GetTypeInfo( + IXMLDOMNodeList *iface, + UINT iTInfo, + LCID lcid, + ITypeInfo** ppTInfo ) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI queryresult_GetIDsOfNames( + IXMLDOMNodeList *iface, + REFIID riid, + LPOLESTR* rgszNames, + UINT cNames, + LCID lcid, + DISPID* rgDispId ) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI queryresult_Invoke( + IXMLDOMNodeList *iface, + DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS* pDispParams, + VARIANT* pVarResult, + EXCEPINFO* pExcepInfo, + UINT* puArgErr ) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI queryresult_get_item( + IXMLDOMNodeList* iface, + long index, + IXMLDOMNode** listItem) +{ + queryresult *This = impl_from_IXMLDOMNodeList( iface ); + + TRACE("%p %ld\n", This, index); + + *listItem = NULL; + + if (index < 0 || index >= This->result->nodesetval->nodeNr) + return S_FALSE; + + *listItem = create_node(This->result->nodesetval->nodeTab[index]); + This->resultPos = index + 1; + + return S_OK; +} + +static HRESULT WINAPI queryresult_get_length( + IXMLDOMNodeList* iface, + long* listLength) +{ + queryresult *This = impl_from_IXMLDOMNodeList( iface ); + + TRACE("%p\n", This); + + *listLength = This->result->nodesetval->nodeNr; + return S_OK; +} + +static HRESULT WINAPI queryresult_nextNode( + IXMLDOMNodeList* iface, + IXMLDOMNode** nextItem) +{ + queryresult *This = impl_from_IXMLDOMNodeList( iface ); + + TRACE("%p %p\n", This, nextItem ); + + *nextItem = NULL; + + if (This->resultPos >= This->result->nodesetval->nodeNr) + return S_FALSE; + + *nextItem = create_node(This->result->nodesetval->nodeTab[This->resultPos]); + This->resultPos++; + return S_OK; +} + +static HRESULT WINAPI queryresult_reset( + IXMLDOMNodeList* iface) +{ + queryresult *This = impl_from_IXMLDOMNodeList( iface ); + + TRACE("%p\n", This); + This->resultPos = 0; + return S_OK; +} + +static HRESULT WINAPI queryresult__newEnum( + IXMLDOMNodeList* iface, + IUnknown** ppUnk) +{ + FIXME("\n"); + return E_NOTIMPL; +} + + +static const struct IXMLDOMNodeListVtbl queryresult_vtbl = +{ + queryresult_QueryInterface, + queryresult_AddRef, + queryresult_Release, + queryresult_GetTypeInfoCount, + queryresult_GetTypeInfo, + queryresult_GetIDsOfNames, + queryresult_Invoke, + queryresult_get_item, + queryresult_get_length, + queryresult_nextNode, + queryresult_reset, + queryresult__newEnum, +}; + +#endif diff --git a/dlls/msxml3/tests/Makefile.in b/dlls/msxml3/tests/Makefile.in index 2aabdb6efa4..e1131b81a90 100644 --- a/dlls/msxml3/tests/Makefile.in +++ b/dlls/msxml3/tests/Makefile.in @@ -3,7 +3,7 @@ TOPOBJDIR = ../../.. SRCDIR = @srcdir@ VPATH = @srcdir@ TESTDLL = msxml3.dll -IMPORTS = oleaut32 ole32 kernel32 +IMPORTS = oleaut32 ole32 user32 kernel32 EXTRALIBS = -luuid CTESTS = \ diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c index 02e8bf99d75..9c51b48041e 100644 --- a/dlls/msxml3/tests/domdoc.c +++ b/dlls/msxml3/tests/domdoc.c @@ -85,6 +85,39 @@ static const WCHAR szComplete5[] = { '<','/','S',':','s','e','a','r','c','h','>',0 }; +static const CHAR szExampleXML[] = +"\n" +"\n" +" \n" +" A1 field\n" +" B1 field\n" +" C1 field\n" +" \n" +" \n" +" This is a description. \n" +" \n" +" \n" +" \n" +"\n" +" \n" +" A2 field\n" +" B2 field\n" +" C2 field\n" +" \n" +"\n" +" \n" +" A3 field\n" +" B3 field\n" +" C3 field\n" +" \n" +"\n" +" \n" +" A4 field\n" +" B4 field\n" +" C4 field\n" +" \n" +"\n"; + static const WCHAR szNonExistentFile[] = { 'c', ':', '\\', 'N', 'o', 'n', 'e', 'x', 'i', 's', 't', 'e', 'n', 't', '.', 'x', 'm', 'l', 0 }; @@ -155,6 +188,144 @@ static VARIANT _variantbstr_(const char *str) return v; } +static void get_str_for_type(DOMNodeType type, char *buf) +{ + switch (type) + { + case NODE_ATTRIBUTE: + strcpy(buf, "A"); + break; + case NODE_ELEMENT: + strcpy(buf, "E"); + break; + case NODE_DOCUMENT: + strcpy(buf, "D"); + break; + default: + wsprintfA(buf, "[%d]", type); + } +} + +static int get_node_position(IXMLDOMNode *node) +{ + HRESULT r; + int pos = 0; + + IXMLDOMNode_AddRef(node); + do + { + IXMLDOMNode *new_node; + + pos++; + r = IXMLDOMNode_get_previousSibling(node, &new_node); + ok(!FAILED(r), "get_previousSibling failed\n"); + IXMLDOMNode_Release(node); + node = new_node; + } while (r == S_OK); + return pos; +} + +static void node_to_string(IXMLDOMNode *node, char *buf) +{ + HRESULT r = S_OK; + DOMNodeType type; + + if (node == NULL) + { + lstrcpyA(buf, "(null)"); + return; + } + + IXMLDOMNode_AddRef(node); + while (r == S_OK) + { + IXMLDOMNode *new_node; + + ole_check(IXMLDOMNode_get_nodeType(node, &type)); + get_str_for_type(type, buf); + buf+=strlen(buf); + + if (type == NODE_ATTRIBUTE) + { + BSTR bstr; + ole_check(IXMLDOMNode_get_nodeName(node, &bstr)); + *(buf++) = '\''; + wsprintfA(buf, "%ws", bstr); + buf += strlen(buf); + *(buf++) = '\''; + SysFreeString(bstr); + + r = IXMLDOMNode_selectSingleNode(node, _bstr_(".."), &new_node); + } + else + { + int pos = get_node_position(node); + DOMNodeType parent_type = NODE_INVALID; + r = IXMLDOMNode_get_parentNode(node, &new_node); + + /* currently wine doesn't create a node for the . To be able to test query + * results we "fix" it */ + if (r == S_OK) + ole_check(IXMLDOMNode_get_nodeType(node, &parent_type)); + /* we need also to workaround the no document node problem - see below */ + if (((r == S_FALSE && type != NODE_DOCUMENT) || parent_type == NODE_DOCUMENT) && type != NODE_PROCESSING_INSTRUCTION && pos==1) + { + todo_wine ok(FALSE, "The first child of the document node in MSXML is the processing instruction\n"); + pos++; + } + wsprintf(buf, "%d", pos); + buf += strlen(buf); + } + + ok(!FAILED(r), "get_parentNode failed (%08x)\n", r); + IXMLDOMNode_Release(node); + node = new_node; + if (r == S_OK) + *(buf++) = '.'; + } + + /* currently we can't access document node in wine. All our examples this is the + * root node so to be able to test query results we add it */ + if (type != NODE_DOCUMENT) + { + todo_wine ok(FALSE, "Document node is not the last returned node!\n"); + *(buf++) = '.'; + *(buf++) = 'D'; + *(buf++) = '1'; + } + *buf = 0; +} + +static char *list_to_string(IXMLDOMNodeList *list) +{ + static char buf[4096]; + char *pos = buf; + long len = 0; + int i; + + if (list == NULL) + { + lstrcpyA(buf, "(null)"); + return buf; + } + ole_check(IXMLDOMNodeList_get_length(list, &len)); + for (i = 0; i < len; i++) + { + IXMLDOMNode *node; + if (i > 0) + *(pos++) = ' '; + ole_check(IXMLDOMNodeList_nextNode(list, &node)); + node_to_string(node, pos); + pos += strlen(pos); + IXMLDOMNode_Release(node); + } + *pos = 0; + return buf; +} + +#define expect_node(node, expstr) { char str[4096]; node_to_string(node, str); ok(strcmp(str, expstr)==0, "Invalid node: %s, exptected %s\n", str, expstr); } +#define expect_list_and_release(list, expstr) { char *str = list_to_string(list); ok(strcmp(str, expstr)==0, "Invalid node list: %s, exptected %s\n", str, expstr); if (list) IXMLDOMNodeList_Release(list); } + static void test_domdoc( void ) { HRESULT r; @@ -590,11 +761,25 @@ todo_wine if (map) IXMLDOMNamedNodeMap_Release( map ); - /* now traverse the tree from the root node */ + /* now traverse the tree from the root element */ if (element) { + IXMLDOMNode *node; r = IXMLDOMNode_get_childNodes( element, &list ); ok( r == S_OK, "get_childNodes returned wrong code\n"); + + /* using get_item for child list doesn't advance the position */ + ole_check(IXMLDOMNodeList_get_item(list, 1, &node)); + expect_node(node, "E2.E2.D1"); + IXMLDOMNode_Release(node); + ole_check(IXMLDOMNodeList_nextNode(list, &node)); + expect_node(node, "E1.E2.D1"); + IXMLDOMNode_Release(node); + ole_check(IXMLDOMNodeList_reset(list)); + + IXMLDOMNodeList_AddRef(list); + expect_list_and_release(list, "E1.E2.D1 E2.E2.D1 E3.E2.D1 E4.E2.D1"); + ole_check(IXMLDOMNodeList_reset(list)); } else ok( FALSE, "no element\n"); @@ -1272,6 +1457,126 @@ static void test_IXMLDOMDocument2(void) free_bstrs(); } +static void test_XPath() +{ + HRESULT r; + VARIANT var; + VARIANT_BOOL b; + IXMLDOMDocument2 *doc; + IXMLDOMNode *rootNode; + IXMLDOMNode *elem1Node; + IXMLDOMNode *node; + IXMLDOMNodeList *list; + + r = CoCreateInstance( &CLSID_DOMDocument, NULL, + CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument2, (LPVOID*)&doc ); + if( r != S_OK ) + return; + + ole_check(IXMLDOMDocument_loadXML(doc, _bstr_(szExampleXML), &b)); + ok(b == VARIANT_TRUE, "failed to load XML string\n"); + + /* switch to XPath */ + ole_check(IXMLDOMDocument2_setProperty(doc, _bstr_("SelectionLanguage"), _variantbstr_("XPath"))); + + /* some simple queries*/ + ole_check(IXMLDOMDocument_selectNodes(doc, _bstr_("root"), &list)); + ole_check(IXMLDOMNodeList_get_item(list, 0, &rootNode)); + ole_check(IXMLDOMNodeList_reset(list)); + expect_list_and_release(list, "E2.D1"); + if (rootNode == NULL) + return; + + ole_check(IXMLDOMDocument_selectNodes(doc, _bstr_("root//c"), &list)); + expect_list_and_release(list, "E3.E1.E2.D1 E3.E2.E2.D1"); + + ole_check(IXMLDOMDocument_selectNodes(doc, _bstr_("//c[@type]"), &list)); + expect_list_and_release(list, "E3.E2.E2.D1"); + + ole_check(IXMLDOMNode_selectNodes(rootNode, _bstr_("elem"), &list)); + /* using get_item for query results advances the position */ + ole_check(IXMLDOMNodeList_get_item(list, 1, &node)); + expect_node(node, "E2.E2.D1"); + IXMLDOMNode_Release(node); + ole_check(IXMLDOMNodeList_nextNode(list, &node)); + expect_node(node, "E4.E2.D1"); + IXMLDOMNode_Release(node); + ole_check(IXMLDOMNodeList_reset(list)); + expect_list_and_release(list, "E1.E2.D1 E2.E2.D1 E4.E2.D1"); + + ole_check(IXMLDOMNode_selectNodes(rootNode, _bstr_("."), &list)); + expect_list_and_release(list, "E2.D1"); + + ole_check(IXMLDOMNode_selectNodes(rootNode, _bstr_("elem[3]/preceding-sibling::*"), &list)); + ole_check(IXMLDOMNodeList_get_item(list, 0, &elem1Node)); + ole_check(IXMLDOMNodeList_reset(list)); + expect_list_and_release(list, "E1.E2.D1 E2.E2.D1 E3.E2.D1"); + + /* select an attribute */ + ole_check(IXMLDOMNode_selectNodes(rootNode, _bstr_(".//@type"), &list)); + expect_list_and_release(list, "A'type'.E3.E2.E2.D1"); + + /* would evaluate to a number */ + ole_expect(IXMLDOMNode_selectNodes(rootNode, _bstr_("count(*)"), &list), E_FAIL); + /* would evaluate to a boolean */ + ole_expect(IXMLDOMNode_selectNodes(rootNode, _bstr_("position()>0"), &list), E_FAIL); + /* would evaluate to a string */ + ole_expect(IXMLDOMNode_selectNodes(rootNode, _bstr_("name()"), &list), E_FAIL); + + /* no results */ + ole_check(IXMLDOMNode_selectNodes(rootNode, _bstr_("c"), &list)); + expect_list_and_release(list, ""); + ole_check(IXMLDOMDocument_selectNodes(doc, _bstr_("elem//c"), &list)); + expect_list_and_release(list, ""); + ole_check(IXMLDOMDocument_selectNodes(doc, _bstr_("//elem[4]"), &list)); + expect_list_and_release(list, ""); + + /* foo undeclared in document node */ + ole_expect(IXMLDOMDocument_selectNodes(doc, _bstr_("root//foo:c"), &list), E_FAIL); + /* undeclared in node */ + ole_expect(IXMLDOMNode_selectNodes(rootNode, _bstr_(".//foo:c"), &list), E_FAIL); + /* undeclared in node */ + ole_expect(IXMLDOMNode_selectNodes(elem1Node, _bstr_("//foo:c"), &list), E_FAIL); + /* but this trick can be used */ + ole_check(IXMLDOMNode_selectNodes(elem1Node, _bstr_("//*[name()='foo:c']"), &list)); + expect_list_and_release(list, "E3.E4.E2.D1"); + + /* it has to be declared in SelectionNamespaces */ + todo_wine ole_check(IXMLDOMDocument2_setProperty(doc, _bstr_("SelectionNamespaces"), + _variantbstr_("xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'"))); + + /* now the namespace can be used */ + todo_wine ole_check(IXMLDOMDocument_selectNodes(doc, _bstr_("root//test:c"), &list)); + todo_wine expect_list_and_release(list, "E3.E3.E2.D1 E3.E4.E2.D1"); + todo_wine ole_check(IXMLDOMNode_selectNodes(rootNode, _bstr_(".//test:c"), &list)); + todo_wine expect_list_and_release(list, "E3.E3.E2.D1 E3.E4.E2.D1"); + todo_wine ole_check(IXMLDOMNode_selectNodes(elem1Node, _bstr_("//test:c"), &list)); + todo_wine expect_list_and_release(list, "E3.E3.E2.D1 E3.E4.E2.D1"); + todo_wine ole_check(IXMLDOMNode_selectNodes(elem1Node, _bstr_(".//test:x"), &list)); + todo_wine expect_list_and_release(list, "E5.E1.E4.E1.E2.D1"); + + /* SelectionNamespaces syntax error - the namespaces doesn't work anymore but the value is stored */ + ole_expect(IXMLDOMDocument2_setProperty(doc, _bstr_("SelectionNamespaces"), + _variantbstr_("xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29' xmlns:foo=###")), E_FAIL); + + ole_expect(IXMLDOMDocument_selectNodes(doc, _bstr_("root//foo:c"), &list), E_FAIL); + + todo_wine ole_check(IXMLDOMDocument2_getProperty(doc, _bstr_("SelectionNamespaces"), &var)); + todo_wine expect_eq(V_VT(&var), VT_BSTR, int, "%x"); + if (V_VT(&var) == VT_BSTR) + expect_bstr_eq_and_free(V_BSTR(&var), "xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29' xmlns:foo=###"); + + /* extra attributes - same thing*/ + ole_expect(IXMLDOMDocument2_setProperty(doc, _bstr_("SelectionNamespaces"), + _variantbstr_("xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29' param='test'")), E_FAIL); + ole_expect(IXMLDOMDocument_selectNodes(doc, _bstr_("root//foo:c"), &list), E_FAIL); + + IXMLDOMNode_Release(rootNode); + IXMLDOMNode_Release(elem1Node); + IXMLDOMDocument_Release(doc); + free_bstrs(); +} + START_TEST(domdoc) { HRESULT r; @@ -1289,6 +1594,7 @@ START_TEST(domdoc) test_removeChild(); test_XMLHTTP(); test_IXMLDOMDocument2(); + test_XPath(); CoUninitialize(); } diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index a7d7f0fec4e..0f50653e734 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -40,6 +40,7 @@ #include "wine/debug.h" #include "wine/server.h" #include "ntdll_misc.h" +#include "ddk/wdm.h" WINE_DEFAULT_DEBUG_CHANNEL(module); WINE_DECLARE_DEBUG_CHANNEL(relay); @@ -1136,64 +1137,6 @@ NTSTATUS WINAPI LdrUnlockLoaderLock( ULONG flags, ULONG magic ) /****************************************************************** - * LdrGetDllHandle (NTDLL.@) - */ -NTSTATUS WINAPI LdrGetDllHandle(ULONG x, ULONG y, const UNICODE_STRING *name, HMODULE *base) -{ - NTSTATUS status = STATUS_DLL_NOT_FOUND; - WCHAR dllname[MAX_PATH+4], *p; - UNICODE_STRING str; - PLIST_ENTRY mark, entry; - PLDR_MODULE mod; - - if (x != 0 || y != 0) - FIXME("Unknown behavior, please report\n"); - - /* Append .DLL to name if no extension present */ - if (!(p = strrchrW( name->Buffer, '.')) || strchrW( p, '/' ) || strchrW( p, '\\')) - { - if (name->Length >= MAX_PATH) return STATUS_NAME_TOO_LONG; - strcpyW( dllname, name->Buffer ); - strcatW( dllname, dllW ); - RtlInitUnicodeString( &str, dllname ); - name = &str; - } - - RtlEnterCriticalSection( &loader_section ); - - if (cached_modref) - { - if (RtlEqualUnicodeString( name, &cached_modref->ldr.FullDllName, TRUE ) || - RtlEqualUnicodeString( name, &cached_modref->ldr.BaseDllName, TRUE )) - { - *base = cached_modref->ldr.BaseAddress; - status = STATUS_SUCCESS; - goto done; - } - } - - mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList; - for (entry = mark->Flink; entry != mark; entry = entry->Flink) - { - mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList); - - if (RtlEqualUnicodeString( name, &mod->FullDllName, TRUE ) || - RtlEqualUnicodeString( name, &mod->BaseDllName, TRUE )) - { - cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr); - *base = mod->BaseAddress; - status = STATUS_SUCCESS; - break; - } - } -done: - RtlLeaveCriticalSection( &loader_section ); - TRACE("%x %x %s -> %p\n", x, y, debugstr_us(name), status ? NULL : *base); - return status; -} - - -/****************************************************************** * LdrGetProcedureAddress (NTDLL.@) */ NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, const ANSI_STRING *name, @@ -1642,7 +1585,7 @@ static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, if (len) { if (len >= *size) goto overflow; - if ((*pwm = find_fullname_module( filename )) != NULL) goto found; + if ((*pwm = find_fullname_module( filename )) || !handle) goto found; if (!RtlDosPathNameToNtPathName_U( filename, &nt_name, NULL, NULL )) { @@ -1682,7 +1625,7 @@ static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, len = nt_name.Length - 4*sizeof(WCHAR); /* for \??\ prefix */ if (len >= *size) goto overflow; memcpy( filename, nt_name.Buffer + 4, len + sizeof(WCHAR) ); - if (!(*pwm = find_fullname_module( filename ))) + if (!(*pwm = find_fullname_module( filename )) && handle) { attr.Length = sizeof(attr); attr.RootDirectory = 0; @@ -1839,6 +1782,69 @@ NTSTATUS WINAPI LdrLoadDll(LPCWSTR path_name, DWORD flags, return nts; } + +/****************************************************************** + * LdrGetDllHandle (NTDLL.@) + */ +NTSTATUS WINAPI LdrGetDllHandle( LPCWSTR load_path, ULONG flags, const UNICODE_STRING *name, HMODULE *base ) +{ + NTSTATUS status; + WCHAR buffer[128]; + WCHAR *filename; + ULONG size; + WINE_MODREF *wm; + + RtlEnterCriticalSection( &loader_section ); + + if (!load_path) load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer; + + filename = buffer; + size = sizeof(buffer); + for (;;) + { + status = find_dll_file( load_path, name->Buffer, filename, &size, &wm, NULL ); + if (filename != buffer) RtlFreeHeap( GetProcessHeap(), 0, filename ); + if (status != STATUS_BUFFER_TOO_SMALL) break; + /* grow the buffer and retry */ + if (!(filename = RtlAllocateHeap( GetProcessHeap(), 0, size ))) return STATUS_NO_MEMORY; + } + + if (status == STATUS_SUCCESS) + { + if (wm) *base = wm->ldr.BaseAddress; + else status = STATUS_DLL_NOT_FOUND; + } + + RtlLeaveCriticalSection( &loader_section ); + TRACE( "%s -> %p (load path %s)\n", debugstr_us(name), status ? NULL : *base, debugstr_w(load_path) ); + return status; +} + + +/****************************************************************** + * LdrAddRefDll (NTDLL.@) + */ +NTSTATUS WINAPI LdrAddRefDll( ULONG flags, HMODULE module ) +{ + NTSTATUS ret = STATUS_SUCCESS; + WINE_MODREF *wm; + + if (flags) FIXME( "%p flags %x not implemented\n", module, flags ); + + RtlEnterCriticalSection( &loader_section ); + + if ((wm = get_modref( module ))) + { + if (wm->ldr.LoadCount != -1) wm->ldr.LoadCount++; + TRACE( "(%s) ldr.LoadCount: %d\n", debugstr_w(wm->ldr.BaseDllName.Buffer), wm->ldr.LoadCount ); + } + else ret = STATUS_INVALID_PARAMETER; + + RtlLeaveCriticalSection( &loader_section ); + return ret; +} + + /****************************************************************** * LdrQueryProcessModuleInformation * @@ -2302,6 +2308,7 @@ void __wine_init_windows_dir( const WCHAR *windir, const WCHAR *sysdir ) LPWSTR buffer, p; RtlCreateUnicodeString( &system_dir, sysdir ); + strcpyW( user_shared_data->NtSystemRoot, windir ); /* prepend the system dir to the name of the already created modules */ mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList; diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 346f002c65e..3b268803f1e 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -50,7 +50,7 @@ @ stub KiUserExceptionDispatcher # @ stub LdrAccessOutOfProcessResource @ stdcall LdrAccessResource(long ptr ptr ptr) -# @ stub LdrAddRefDll +@ stdcall LdrAddRefDll(long ptr) # @ stub LdrAlternateResourcesEnabled # @ stub LdrCreateOutOfProcessImage # @ stub LdrDestroyOutOfProcessImage @@ -63,7 +63,7 @@ # @ stub LdrFindResourceEx_U @ stdcall LdrFindResource_U(long ptr long ptr) @ stub LdrFlushAlternateResourceModules -@ stdcall LdrGetDllHandle(long long ptr ptr) +@ stdcall LdrGetDllHandle(wstr long ptr ptr) # @ stub LdrGetDllHandleEx @ stdcall LdrGetProcedureAddress(ptr ptr long ptr) # @ stub LdrHotPatchRoutine diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index 741aec4bba4..c6ef77ce5c7 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -25,7 +25,6 @@ #include "windef.h" #include "winnt.h" #include "winternl.h" -#include "winioctl.h" #include "wine/server.h" #define MAX_NT_PATH_LENGTH 277 @@ -117,6 +116,7 @@ extern NTSTATUS DIR_get_unix_cwd( char **cwd ); extern NTSTATUS VIRTUAL_HandleFault(LPCVOID addr); extern void VIRTUAL_SetForceExec( BOOL enable ); extern void VIRTUAL_UseLargeAddressSpace(void); +extern struct _KUSER_SHARED_DATA *user_shared_data; /* code pages */ extern int ntdll_umbstowcs(DWORD flags, const char* src, int srclen, WCHAR* dst, int dstlen); diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index fa30e539c9e..30e441ddb0f 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -40,11 +40,14 @@ #include "wine/pthread.h" #include "wine/debug.h" #include "ntdll_misc.h" +#include "ddk/wdm.h" #include "wine/exception.h" WINE_DEFAULT_DEBUG_CHANNEL(thread); WINE_DECLARE_DEBUG_CHANNEL(relay); +struct _KUSER_SHARED_DATA *user_shared_data = NULL; + /* info passed to a starting thread */ struct startup_info { @@ -225,6 +228,7 @@ HANDLE thread_init(void) void *addr; SIZE_T size, info_size; HANDLE exe_file = 0; + LARGE_INTEGER now; struct ntdll_thread_data *thread_data; struct ntdll_thread_regs *thread_regs; struct wine_pthread_thread_info thread_info; @@ -236,7 +240,8 @@ HANDLE thread_init(void) addr = (void *)0x7ffe0000; size = 0x10000; - NtAllocateVirtualMemory( NtCurrentProcess(), &addr, 0, &size, MEM_RESERVE, PAGE_READONLY ); + NtAllocateVirtualMemory( NtCurrentProcess(), &addr, 0, &size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE ); + user_shared_data = addr; /* allocate and initialize the PEB */ @@ -325,6 +330,15 @@ HANDLE thread_init(void) /* initialize LDT locking */ wine_ldt_init_locking( ldt_lock, ldt_unlock ); + /* initialize time values in user_shared_data */ + NtQuerySystemTime( &now ); + user_shared_data->SystemTime.LowPart = now.LowPart; + user_shared_data->SystemTime.High1Time = user_shared_data->SystemTime.High2Time = now.HighPart; + user_shared_data->u.TickCountQuad = (now.QuadPart - server_start_time) / 10000; + user_shared_data->u.TickCount.High2Time = user_shared_data->u.TickCount.High1Time; + user_shared_data->TickCountLowDeprecated = user_shared_data->u.TickCount.LowPart; + user_shared_data->TickCountMultiplier = 1 << 24; + return exe_file; } diff --git a/dlls/ntdll/version.c b/dlls/ntdll/version.c index f29b49563d6..0f188330b31 100644 --- a/dlls/ntdll/version.c +++ b/dlls/ntdll/version.c @@ -34,6 +34,7 @@ #include "wine/unicode.h" #include "wine/debug.h" #include "ntdll_misc.h" +#include "ddk/wdm.h" WINE_DEFAULT_DEBUG_CHANNEL(ver); @@ -505,6 +506,13 @@ done: NtCurrentTeb()->Peb->OSBuildNumber = current_version->dwBuildNumber; NtCurrentTeb()->Peb->OSPlatformId = current_version->dwPlatformId; + user_shared_data->NtProductType = current_version->wProductType; + user_shared_data->ProductTypeIsValid = TRUE; + user_shared_data->MajorNtVersion = current_version->dwMajorVersion; + user_shared_data->MinorNtVersion = current_version->dwMinorVersion; + user_shared_data->MinorNtVersion = current_version->dwMinorVersion; + user_shared_data->SuiteMask = current_version->wSuiteMask; + TRACE( "got %d.%d plaform %d build %x name %s service pack %d.%d product %d\n", current_version->dwMajorVersion, current_version->dwMinorVersion, current_version->dwPlatformId, current_version->dwBuildNumber, diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index 8884622f1d0..3bbb20557eb 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -30,12 +30,14 @@ #define WIN32_NO_STATUS #include "windef.h" #include "winternl.h" +#include "excpt.h" #include "ddk/wdm.h" #include "wine/unicode.h" #include "wine/server.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(ntoskrnl); +WINE_DECLARE_DEBUG_CHANNEL(relay); KSYSTEM_TIME KeTickCount; @@ -50,6 +52,7 @@ typedef struct _KSERVICE_TABLE_DESCRIPTOR KSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable[4]; +typedef void (WINAPI *PCREATE_PROCESS_NOTIFY_ROUTINE)(HANDLE,HANDLE,BOOLEAN); #ifdef __i386__ #define DEFINE_FASTCALL1_ENTRYPOINT( name ) \ @@ -101,6 +104,149 @@ static HANDLE get_device_manager(void) return ret; } +/* exception handler for emulation of privileged instructions */ +static LONG CALLBACK vectored_handler( EXCEPTION_POINTERS *ptrs ) +{ + extern DWORD __wine_emulate_instruction( EXCEPTION_RECORD *rec, CONTEXT86 *context ); + + EXCEPTION_RECORD *record = ptrs->ExceptionRecord; + CONTEXT86 *context = ptrs->ContextRecord; + + if (record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION || + record->ExceptionCode == EXCEPTION_PRIV_INSTRUCTION) + { + if (__wine_emulate_instruction( record, context ) == ExceptionContinueExecution) + return EXCEPTION_CONTINUE_EXECUTION; + } + return EXCEPTION_CONTINUE_SEARCH; +} + +/* process an ioctl request for a given device */ +static NTSTATUS process_ioctl( DEVICE_OBJECT *device, ULONG code, void *in_buff, ULONG in_size, + void *out_buff, ULONG *out_size ) +{ + IRP irp; + MDL mdl; + IO_STACK_LOCATION irpsp; + PDRIVER_DISPATCH dispatch = device->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]; + NTSTATUS status; + LARGE_INTEGER count; + + TRACE( "ioctl %x device %p in_size %u out_size %u\n", code, device, in_size, *out_size ); + + /* so we can spot things that we should initialize */ + memset( &irp, 0x55, sizeof(irp) ); + memset( &irpsp, 0x66, sizeof(irpsp) ); + memset( &mdl, 0x77, sizeof(mdl) ); + + irp.RequestorMode = UserMode; + irp.AssociatedIrp.SystemBuffer = in_buff; + irp.UserBuffer = out_buff; + irp.MdlAddress = &mdl; + irp.Tail.Overlay.s.u.CurrentStackLocation = &irpsp; + + irpsp.MajorFunction = IRP_MJ_DEVICE_CONTROL; + irpsp.Parameters.DeviceIoControl.OutputBufferLength = *out_size; + irpsp.Parameters.DeviceIoControl.InputBufferLength = in_size; + irpsp.Parameters.DeviceIoControl.IoControlCode = code; + irpsp.Parameters.DeviceIoControl.Type3InputBuffer = in_buff; + irpsp.DeviceObject = device; + + mdl.Next = NULL; + mdl.Size = 0; + mdl.StartVa = out_buff; + mdl.ByteCount = *out_size; + mdl.ByteOffset = 0; + + device->CurrentIrp = &irp; + + KeQueryTickCount( &count ); /* update the global KeTickCount */ + + if (TRACE_ON(relay)) + DPRINTF( "%04x:Call driver dispatch %p (device=%p,irp=%p)\n", + GetCurrentThreadId(), dispatch, device, &irp ); + + status = dispatch( device, &irp ); + + if (TRACE_ON(relay)) + DPRINTF( "%04x:Ret driver dispatch %p (device=%p,irp=%p) retval=%08x\n", + GetCurrentThreadId(), dispatch, device, &irp, status ); + + *out_size = irp.IoStatus.u.Status ? 0 : irp.IoStatus.Information; + return irp.IoStatus.u.Status; +} + + +/*********************************************************************** + * wine_ntoskrnl_main_loop (Not a Windows API) + */ +NTSTATUS wine_ntoskrnl_main_loop( HANDLE stop_event ) +{ + HANDLE manager = get_device_manager(); + HANDLE ioctl = 0; + NTSTATUS status = STATUS_SUCCESS; + ULONG code = 0; + void *in_buff, *out_buff = NULL; + DEVICE_OBJECT *device = NULL; + ULONG in_size = 4096, out_size = 0; + HANDLE handles[2]; + + if (!(in_buff = HeapAlloc( GetProcessHeap(), 0, in_size ))) + { + ERR( "failed to allocate buffer\n" ); + return STATUS_NO_MEMORY; + } + + handles[0] = stop_event; + handles[1] = manager; + + for (;;) + { + SERVER_START_REQ( get_next_device_request ) + { + req->manager = manager; + req->prev = ioctl; + req->status = status; + wine_server_add_data( req, out_buff, out_size ); + wine_server_set_reply( req, in_buff, in_size ); + if (!(status = wine_server_call( req ))) + { + code = reply->code; + ioctl = reply->next; + device = reply->user_ptr; + in_size = reply->in_size; + out_size = reply->out_size; + } + else + { + ioctl = 0; /* no previous ioctl */ + out_size = 0; + in_size = reply->in_size; + } + } + SERVER_END_REQ; + + switch(status) + { + case STATUS_SUCCESS: + HeapFree( GetProcessHeap(), 0, out_buff ); + if (out_size) out_buff = HeapAlloc( GetProcessHeap(), 0, out_size ); + else out_buff = NULL; + status = process_ioctl( device, code, in_buff, in_size, out_buff, &out_size ); + break; + case STATUS_BUFFER_OVERFLOW: + HeapFree( GetProcessHeap(), 0, in_buff ); + in_buff = HeapAlloc( GetProcessHeap(), 0, in_size ); + /* restart with larger buffer */ + break; + case STATUS_PENDING: + if (WaitForMultipleObjects( 2, handles, FALSE, INFINITE ) == WAIT_OBJECT_0) + return STATUS_SUCCESS; + break; + } + } +} + /*********************************************************************** * IoCreateDevice (NTOSKRNL.EXE.@) @@ -214,15 +360,181 @@ void WINAPI IofCompleteRequest( IRP *irp, UCHAR priority_boost ) } +/*********************************************************************** + * ExAllocatePool (NTOSKRNL.EXE.@) + */ +PVOID WINAPI ExAllocatePool( POOL_TYPE type, SIZE_T size ) +{ + return ExAllocatePoolWithTag( type, size, 0 ); +} + + +/*********************************************************************** + * ExAllocatePoolWithQuota (NTOSKRNL.EXE.@) + */ +PVOID WINAPI ExAllocatePoolWithQuota( POOL_TYPE type, SIZE_T size ) +{ + return ExAllocatePoolWithTag( type, size, 0 ); +} + + +/*********************************************************************** + * ExAllocatePoolWithTag (NTOSKRNL.EXE.@) + */ +PVOID WINAPI ExAllocatePoolWithTag( POOL_TYPE type, SIZE_T size, ULONG tag ) +{ + /* FIXME: handle page alignment constraints */ + void *ret = HeapAlloc( GetProcessHeap(), 0, size ); + TRACE( "%lu pool %u -> %p\n", size, type, ret ); + return ret; +} + + +/*********************************************************************** + * ExAllocatePoolWithQuotaTag (NTOSKRNL.EXE.@) + */ +PVOID WINAPI ExAllocatePoolWithQuotaTag( POOL_TYPE type, SIZE_T size, ULONG tag ) +{ + return ExAllocatePoolWithTag( type, size, tag ); +} + + +/*********************************************************************** + * ExFreePool (NTOSKRNL.EXE.@) + */ +void WINAPI ExFreePool( void *ptr ) +{ + ExFreePoolWithTag( ptr, 0 ); +} + + +/*********************************************************************** + * ExFreePoolWithTag (NTOSKRNL.EXE.@) + */ +void WINAPI ExFreePoolWithTag( void *ptr, ULONG tag ) +{ + TRACE( "%p\n", ptr ); + HeapFree( GetProcessHeap(), 0, ptr ); +} + + +/*********************************************************************** + * KeQuerySystemTime (NTOSKRNL.EXE.@) + */ +void WINAPI KeQuerySystemTime( LARGE_INTEGER *time ) +{ + NtQuerySystemTime( time ); +} + + +/*********************************************************************** + * KeQueryTickCount (NTOSKRNL.EXE.@) + */ +void WINAPI KeQueryTickCount( LARGE_INTEGER *count ) +{ + count->QuadPart = NtGetTickCount(); + /* update the global variable too */ + KeTickCount.LowPart = count->u.LowPart; + KeTickCount.High1Time = count->u.HighPart; + KeTickCount.High2Time = count->u.HighPart; +} + + +/*********************************************************************** + * KeQueryTimeIncrement (NTOSKRNL.EXE.@) + */ +ULONG WINAPI KeQueryTimeIncrement(void) +{ + return 10000; +} + + +/*********************************************************************** + * MmAllocateNonCachedMemory (NTOSKRNL.EXE.@) + */ +LPVOID WINAPI MmAllocateNonCachedMemory( SIZE_T size ) +{ + TRACE( "%lu\n", size ); + return VirtualAlloc( NULL, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE|PAGE_NOCACHE ); +} + + +/*********************************************************************** + * MmFreeNonCachedMemory (NTOSKRNL.EXE.@) + */ +void WINAPI MmFreeNonCachedMemory( void *addr, SIZE_T size ) +{ + TRACE( "%p %lu\n", addr, size ); + VirtualFree( addr, 0, MEM_RELEASE ); +} + + +/*********************************************************************** + * PsGetCurrentProcessId (NTOSKRNL.EXE.@) + */ +HANDLE WINAPI PsGetCurrentProcessId(void) +{ + return (HANDLE)GetCurrentProcessId(); /* FIXME: not quite right... */ +} + + +/*********************************************************************** + * PsGetCurrentThreadId (NTOSKRNL.EXE.@) + */ +HANDLE WINAPI PsGetCurrentThreadId(void) +{ + return (HANDLE)GetCurrentThreadId(); /* FIXME: not quite right... */ +} + + +/*********************************************************************** + * PsGetVersion (NTOSKRNL.EXE.@) + */ +BOOLEAN WINAPI PsGetVersion(ULONG *major, ULONG *minor, ULONG *build, UNICODE_STRING *version ) +{ + RTL_OSVERSIONINFOEXW info; + + RtlGetVersion( &info ); + if (major) *major = info.dwMajorVersion; + if (minor) *minor = info.dwMinorVersion; + if (build) *build = info.dwBuildNumber; + + if (version) + { +#if 0 /* FIXME: GameGuard passes an uninitialized pointer in version->Buffer */ + size_t len = min( strlenW(info.szCSDVersion)*sizeof(WCHAR), version->MaximumLength ); + memcpy( version->Buffer, info.szCSDVersion, len ); + if (len < version->MaximumLength) version->Buffer[len / sizeof(WCHAR)] = 0; + version->Length = len; +#endif + } + return TRUE; +} + + +/*********************************************************************** + * PsSetCreateProcessNotifyRoutine (NTOSKRNL.EXE.@) + */ +NTSTATUS WINAPI PsSetCreateProcessNotifyRoutine( PCREATE_PROCESS_NOTIFY_ROUTINE callback, BOOLEAN remove ) +{ + FIXME( "stub: %p %d\n", callback, remove ); + return STATUS_SUCCESS; +} + + /***************************************************** * DllMain */ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved ) { + LARGE_INTEGER count; + switch(reason) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls( inst ); + RtlAddVectoredExceptionHandler( TRUE, vectored_handler ); + KeQueryTickCount( &count ); /* initialize the global KeTickCount */ break; } return TRUE; diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec index 5bfd7924c30..f1996020e64 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec +++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec @@ -116,10 +116,10 @@ @ stub ExAcquireSharedStarveExclusive @ stub ExAcquireSharedWaitForExclusive @ stub ExAllocateFromPagedLookasideList -@ stub ExAllocatePool -@ stub ExAllocatePoolWithQuota -@ stub ExAllocatePoolWithQuotaTag -@ stub ExAllocatePoolWithTag +@ stdcall ExAllocatePool(long long) +@ stdcall ExAllocatePoolWithQuota(long long) +@ stdcall ExAllocatePoolWithQuotaTag(long long long) +@ stdcall ExAllocatePoolWithTag(long long long) @ stub ExAllocatePoolWithTagPriority @ stub ExConvertExclusiveToSharedLite @ stub ExCreateCallback @@ -131,8 +131,8 @@ @ stub ExEnumHandleTable @ stub ExEventObjectType @ stub ExExtendZone -@ stub ExFreePool -@ stub ExFreePoolWithTag +@ stdcall ExFreePool(ptr) +@ stdcall ExFreePoolWithTag(ptr long) @ stub ExFreeToPagedLookasideList @ stub ExGetCurrentProcessorCounts @ stub ExGetCurrentProcessorCpuUsage @@ -573,9 +573,9 @@ @ stub KeQueryInterruptTime @ stub KeQueryPriorityThread @ stub KeQueryRuntimeThread -@ stub KeQuerySystemTime -@ stub KeQueryTickCount -@ stub KeQueryTimeIncrement +@ stdcall KeQuerySystemTime(ptr) +@ stdcall KeQueryTickCount(ptr) +@ stdcall KeQueryTimeIncrement() @ stub KeRaiseUserException @ stub KeReadStateEvent @ stub KeReadStateMutant @@ -658,7 +658,7 @@ @ stub MmAllocateContiguousMemory @ stub MmAllocateContiguousMemorySpecifyCache @ stub MmAllocateMappingAddress -@ stub MmAllocateNonCachedMemory +@ stdcall MmAllocateNonCachedMemory(long) @ stub MmAllocatePagesForMdl @ stub MmBuildMdlForNonPagedPool @ stub MmCanFileBeTruncated @@ -671,7 +671,7 @@ @ stub MmFreeContiguousMemory @ stub MmFreeContiguousMemorySpecifyCache @ stub MmFreeMappingAddress -@ stub MmFreeNonCachedMemory +@ stdcall MmFreeNonCachedMemory(ptr long) @ stub MmFreePagesFromMdl @ stub MmGetPhysicalAddress @ stub MmGetPhysicalMemoryRanges @@ -850,10 +850,10 @@ @ stub PsEstablishWin32Callouts @ stub PsGetContextThread @ stub PsGetCurrentProcess -@ stub PsGetCurrentProcessId +@ stdcall PsGetCurrentProcessId() @ stub PsGetCurrentProcessSessionId @ stub PsGetCurrentThread -@ stub PsGetCurrentThreadId +@ stdcall PsGetCurrentThreadId() @ stub PsGetCurrentThreadPreviousMode @ stub PsGetCurrentThreadStackBase @ stub PsGetCurrentThreadStackLimit @@ -884,7 +884,7 @@ @ stub PsGetThreadSessionId @ stub PsGetThreadTeb @ stub PsGetThreadWin32Thread -@ stub PsGetVersion +@ stdcall PsGetVersion(ptr ptr ptr ptr) @ stub PsImpersonateClient @ stub PsInitialSystemProcess @ stub PsIsProcessBeingDebugged @@ -907,7 +907,7 @@ @ stub PsRevertThreadToSelf @ stub PsRevertToSelf @ stub PsSetContextThread -@ stub PsSetCreateProcessNotifyRoutine +@ stdcall PsSetCreateProcessNotifyRoutine(ptr long) @ stub PsSetCreateThreadNotifyRoutine @ stub PsSetJobUIRestrictionsClass @ stub PsSetLegoNotifyRoutine @@ -1481,3 +1481,11 @@ @ cdecl -private wcsstr(wstr wstr) msvcrt.wcsstr @ cdecl -private wcstombs(ptr ptr long) msvcrt.wcstombs @ cdecl -private wctomb(ptr long) msvcrt.wctomb + +################################################################ +# Wine internal extensions +# +# All functions must be prefixed with '__wine_' (for internal functions) +# or 'wine_' (for user-visible functions) to avoid namespace conflicts. + +@ cdecl wine_ntoskrnl_main_loop(long) diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index b0720265b41..8e883a8ff2e 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -372,6 +372,7 @@ DWORD apartment_release(struct apartment *apt) apartment_disconnectproxies(apt); if (apt->win) DestroyWindow(apt->win); + if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0); LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs) { @@ -510,6 +511,8 @@ struct host_object_params HKEY hkeydll; CLSID clsid; /* clsid of object to marshal */ IID iid; /* interface to marshal */ + HANDLE event; /* event signalling when ready for multi-threaded case */ + HRESULT hr; /* result for multi-threaded case */ IStream *stream; /* stream that the object will be marshaled into */ }; @@ -521,7 +524,7 @@ static HRESULT apartment_hostobject(struct apartment *apt, static const LARGE_INTEGER llZero; WCHAR dllpath[MAX_PATH+1]; - TRACE("\n"); + TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms->clsid), debugstr_guid(¶ms->iid)); if (COM_RegReadPath(params->hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS) { @@ -556,6 +559,167 @@ static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LP } } +struct host_thread_params +{ + COINIT threading_model; + HANDLE ready_event; + HWND apartment_hwnd; +}; + +static DWORD CALLBACK apartment_hostobject_thread(LPVOID p) +{ + struct host_thread_params *params = p; + MSG msg; + HRESULT hr; + struct apartment *apt; + + TRACE("\n"); + + hr = CoInitializeEx(NULL, params->threading_model); + if (FAILED(hr)) return hr; + + apt = COM_CurrentApt(); + if (params->threading_model == COINIT_APARTMENTTHREADED) + { + apartment_createwindowifneeded(apt); + params->apartment_hwnd = apartment_getwindow(apt); + } + else + params->apartment_hwnd = NULL; + + /* force the message queue to be created before signaling parent thread */ + PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); + + SetEvent(params->ready_event); + params = NULL; /* can't touch params after here as it may be invalid */ + + while (GetMessageW(&msg, NULL, 0, 0)) + { + if (!msg.hwnd && (msg.message == DM_HOSTOBJECT)) + { + struct host_object_params *params = (struct host_object_params *)msg.lParam; + params->hr = apartment_hostobject(apt, params); + SetEvent(params->event); + } + else + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } + + TRACE("exiting\n"); + + CoUninitialize(); + + return S_OK; +} + +static HRESULT apartment_hostobject_in_hostapt(struct apartment *apt, BOOL multi_threaded, BOOL main_apartment, HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv) +{ + struct host_object_params params; + HWND apartment_hwnd = NULL; + DWORD apartment_tid = 0; + HRESULT hr; + + if (!multi_threaded && main_apartment) + { + APARTMENT *host_apt = apartment_findfromtype(FALSE, FALSE); + if (host_apt) + { + apartment_hwnd = apartment_getwindow(host_apt); + apartment_release(host_apt); + } + } + + if (!apartment_hwnd) + { + EnterCriticalSection(&apt->cs); + + if (!apt->host_apt_tid) + { + struct host_thread_params thread_params; + HANDLE handles[2]; + DWORD wait_value; + + thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED; + handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL); + thread_params.apartment_hwnd = NULL; + handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid); + if (!handles[1]) + { + CloseHandle(handles[0]); + LeaveCriticalSection(&apt->cs); + return E_OUTOFMEMORY; + } + wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE); + CloseHandle(handles[0]); + CloseHandle(handles[1]); + if (wait_value == WAIT_OBJECT_0) + apt->host_apt_hwnd = thread_params.apartment_hwnd; + else + { + LeaveCriticalSection(&apt->cs); + return E_OUTOFMEMORY; + } + } + + if (multi_threaded || !main_apartment) + { + apartment_hwnd = apt->host_apt_hwnd; + apartment_tid = apt->host_apt_tid; + } + + LeaveCriticalSection(&apt->cs); + } + + /* another thread may have become the main apartment in the time it took + * us to create the thread for the host apartment */ + if (!apartment_hwnd && !multi_threaded && main_apartment) + { + APARTMENT *host_apt = apartment_findfromtype(FALSE, FALSE); + if (host_apt) + { + apartment_hwnd = apartment_getwindow(host_apt); + apartment_release(host_apt); + } + } + + params.hkeydll = hkeydll; + params.clsid = *rclsid; + params.iid = *riid; + hr = CreateStreamOnHGlobal(NULL, TRUE, ¶ms.stream); + if (FAILED(hr)) + return hr; + if (multi_threaded) + { + params.hr = S_OK; + params.event = CreateEventW(NULL, FALSE, FALSE, NULL); + if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)¶ms)) + hr = E_OUTOFMEMORY; + else + { + WaitForSingleObject(params.event, INFINITE); + hr = params.hr; + } + CloseHandle(params.event); + } + else + { + if (!apartment_hwnd) + { + ERR("host apartment didn't create window\n"); + hr = E_OUTOFMEMORY; + } + else + hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)¶ms); + } + if (SUCCEEDED(hr)) + hr = CoUnmarshalInterface(params.stream, riid, ppv); + IStream_Release(params.stream); + return hr; +} + HRESULT apartment_createwindowifneeded(struct apartment *apt) { if (apt->multi_threaded) @@ -1927,45 +2091,19 @@ static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll, static const WCHAR wszBoth[] = {'B','o','t','h',0}; WCHAR dllpath[MAX_PATH+1]; WCHAR threading_model[10 /* strlenW(L"apartment")+1 */]; - HRESULT hr; get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model)); /* "Apartment" */ if (!strcmpiW(threading_model, wszApartment)) { if (apt->multi_threaded) - { - /* try to find an STA */ - APARTMENT *host_apt = apartment_findfromtype(FALSE, FALSE); - if (!host_apt) - FIXME("create a host apartment for apartment-threaded object %s\n", debugstr_guid(rclsid)); - if (host_apt) - { - struct host_object_params params; - HWND hwnd = apartment_getwindow(host_apt); - - params.hkeydll = hkeydll; - params.clsid = *rclsid; - params.iid = *riid; - hr = CreateStreamOnHGlobal(NULL, TRUE, ¶ms.stream); - if (FAILED(hr)) - return hr; - hr = SendMessageW(hwnd, DM_HOSTOBJECT, 0, (LPARAM)¶ms); - if (SUCCEEDED(hr)) - hr = CoUnmarshalInterface(params.stream, riid, ppv); - IStream_Release(params.stream); - return hr; - } - } + return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv); } /* "Free" */ else if (!strcmpiW(threading_model, wszFree)) { if (!apt->multi_threaded) - { - FIXME("should create object %s in multi-threaded apartment\n", - debugstr_guid(rclsid)); - } + return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv); } /* everything except "Apartment", "Free" and "Both" */ else if (strcmpiW(threading_model, wszBoth)) @@ -1976,29 +2114,7 @@ static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll, debugstr_w(threading_model), debugstr_guid(rclsid)); if (apt->multi_threaded || !apt->main) - { - /* try to find an STA */ - APARTMENT *host_apt = apartment_findfromtype(FALSE, TRUE); - if (!host_apt) - FIXME("create a host apartment for main-threaded object %s\n", debugstr_guid(rclsid)); - if (host_apt) - { - struct host_object_params params; - HWND hwnd = apartment_getwindow(host_apt); - - params.hkeydll = hkeydll; - params.clsid = *rclsid; - params.iid = *riid; - hr = CreateStreamOnHGlobal(NULL, TRUE, ¶ms.stream); - if (FAILED(hr)) - return hr; - hr = SendMessageW(hwnd, DM_HOSTOBJECT, 0, (LPARAM)¶ms); - if (SUCCEEDED(hr)) - hr = CoUnmarshalInterface(params.stream, riid, ppv); - IStream_Release(params.stream); - return hr; - } - } + return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv); } if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS) diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h index e877cce0269..a5d83787d33 100644 --- a/dlls/ole32/compobj_private.h +++ b/dlls/ole32/compobj_private.h @@ -158,6 +158,8 @@ struct apartment LONG remoting_started; /* has the RPC system been started for this apartment? (LOCK) */ struct list psclsids; /* list of registered PS CLSIDs (CS cs) */ struct list loaded_dlls; /* list of dlls loaded by this apartment (CS cs) */ + DWORD host_apt_tid; /* thread ID of apartment hosting objects of differing threading model (CS cs) */ + HWND host_apt_hwnd; /* handle to apartment window of host apartment (CS cs) */ /* FIXME: OID's should be given out by RPCSS */ OID oidc; /* object ID counter, starts at 1, zero is invalid OID (CS cs) */ diff --git a/dlls/ole32/hglobalstream.c b/dlls/ole32/hglobalstream.c index 872fb24b1cf..e6d2f731dfc 100644 --- a/dlls/ole32/hglobalstream.c +++ b/dlls/ole32/hglobalstream.c @@ -233,6 +233,12 @@ static HRESULT WINAPI HGLOBALStreamImpl_Read( * Lock the buffer in position and copy the data. */ supportBuffer = GlobalLock(This->supportHandle); + if (!supportBuffer) + { + WARN("read from invalid hglobal %p\n", This->supportHandle); + *pcbRead = 0; + return S_OK; + } memcpy(pv, (char *) supportBuffer+This->currentPosition.u.LowPart, bytesToReadFromBuffer); @@ -293,6 +299,8 @@ static HRESULT WINAPI HGLOBALStreamImpl_Write( if (cb == 0) goto out; + *pcbWritten = 0; + newSize.u.HighPart = 0; newSize.u.LowPart = This->currentPosition.u.LowPart + cb; @@ -314,6 +322,11 @@ static HRESULT WINAPI HGLOBALStreamImpl_Write( * Lock the buffer in position and copy the data. */ supportBuffer = GlobalLock(This->supportHandle); + if (!supportBuffer) + { + WARN("write to invalid hglobal %p\n", This->supportHandle); + return S_OK; + } memcpy((char *) supportBuffer+This->currentPosition.u.LowPart, pv, cb); diff --git a/dlls/ole32/tests/hglobalstream.c b/dlls/ole32/tests/hglobalstream.c index 8f14544b3cc..6338dfeb586 100644 --- a/dlls/ole32/tests/hglobalstream.c +++ b/dlls/ole32/tests/hglobalstream.c @@ -259,6 +259,50 @@ static void test_copyto(void) IStream_Release(pStream); } +static void test_freed_hglobal(void) +{ + HRESULT hr; + IStream *pStream; + HGLOBAL hglobal; + char *p; + char buffer[10]; + ULARGE_INTEGER ull; + ULONG read, written; + + hglobal = GlobalAlloc(GMEM_DDESHARE|GMEM_NODISCARD|GMEM_MOVEABLE, strlen("Rob") + 1); + ok(hglobal != NULL, "GlobalAlloc failed with error %d\n", GetLastError()); + p = GlobalLock(hglobal); + strcpy(p, "Rob"); + GlobalUnlock(hglobal); + + hr = CreateStreamOnHGlobal(hglobal, FALSE, &pStream); + ok_ole_success(hr, "CreateStreamOnHGlobal"); + + hr = IStream_Read(pStream, buffer, sizeof(buffer), &read); + ok_ole_success(hr, "IStream_Read"); + ok(!strcmp(buffer, "Rob"), "buffer data %s differs\n", buffer); + ok(read == strlen("Rob") + 1, "read should be 4 instead of %d\n", read); + + GlobalFree(hglobal); + + memset(buffer, 0, sizeof(buffer)); + read = -1; + hr = IStream_Read(pStream, buffer, sizeof(buffer), &read); + ok_ole_success(hr, "IStream_Read"); + ok(buffer[0] == 0, "buffer data should be untouched\n"); + ok(read == 0, "read should be 0 instead of %d\n", read); + + ull.QuadPart = sizeof(buffer); + hr = IStream_SetSize(pStream, ull); + ok(hr == E_OUTOFMEMORY, "IStream_SetSize with invalid HGLOBAL should return E_OUTOFMEMORY instead of 0x%08x\n", hr); + + hr = IStream_Write(pStream, buffer, sizeof(buffer), &written); + ok(hr == E_OUTOFMEMORY, "IStream_Write with invalid HGLOBAL should return E_OUTOFMEMORY instead of 0x%08x\n", hr); + ok(written == 0, "written should be 0 instead of %d\n", written); + + IStream_Release(pStream); +} + START_TEST(hglobalstream) { HRESULT hr; @@ -270,4 +314,5 @@ START_TEST(hglobalstream) test_streamonhglobal(pStream); IStream_Release(pStream); test_copyto(); + test_freed_hglobal(); } diff --git a/dlls/ole32/tests/marshal.c b/dlls/ole32/tests/marshal.c index 7e3e82e766a..2ad02eedf42 100644 --- a/dlls/ole32/tests/marshal.c +++ b/dlls/ole32/tests/marshal.c @@ -78,7 +78,6 @@ static void test_cocreateinstance_proxy(void) hr = CoCreateInstance(&CLSID_ShellDesktop, NULL, CLSCTX_INPROC, &IID_IUnknown, (void **)&pProxy); ok_ole_success(hr, CoCreateInstance); hr = IUnknown_QueryInterface(pProxy, &IID_IMultiQI, (void **)&pMQI); - todo_wine ok(hr == S_OK, "created object is not a proxy, so was created in the wrong apartment\n"); if (hr == S_OK) IMultiQI_Release(pMQI); diff --git a/dlls/oleaut32/tests/tmarshal.idl b/dlls/oleaut32/tests/tmarshal.idl index e99dbc77bdc..2d1a9bc5560 100644 --- a/dlls/oleaut32/tests/tmarshal.idl +++ b/dlls/oleaut32/tests/tmarshal.idl @@ -158,4 +158,113 @@ library TestTypelib interface IWidget; [source] interface IWidget; }; + + [ + odl, + uuid(375f8a9d-33d0-44f3-b972-61f8407899e0) + ] + interface ItestIF1 : IUnknown + { + HRESULT fn1([in] int x); + HRESULT fn2([out,retval] int *x); + } + + [ + odl, + uuid(094056a3-666f-4956-be12-1859668310b8) + ] + interface ItestIF2 : ItestIF1 + { + HRESULT fn3([in] int y); + } + + [ + odl, + uuid(33baba09-2e68-43ab-81fe-d84b403df2e5) + ] + dispinterface ItestIF3 + { + interface ItestIF2; + } + + [ + odl, + uuid(a01005c7-7491-42eb-94f3-668e37ce60a6) + ] + dispinterface ItestIF4 + { + properties: + methods: + [id(0x1c)] HRESULT fn([in] int z); + } + + [ + odl, + uuid(4ab61e25-c09f-4239-8f7f-7a018ea0199f), + dual + ] + interface ItestIF5 : ItestIF2 + { + [id(0x1234)] HRESULT fn4([in] int a); + [id(0x1235)] HRESULT fn5([in] int a); + } + + [ + odl, + uuid(ec236d8e-2cc7-44f2-b394-36c86ff3da74) + ] + interface ItestIF6 : IDispatch + { + [id(0x1234)] HRESULT fn4([in] int a); + [id(0x1235)] HRESULT fn5([in] int a); + } + + [ + odl, + uuid(f711b105-554d-4751-818c-46fcc5d7c0d5), + dual + ] + interface ItestIF7 : ItestIF6 + { + [id(0x1236)] HRESULT fn6([in] int a); + } + + [ + odl, + uuid(bdfa260b-ef40-43d3-b071-cddec919f132) + ] + interface ItestIF8 + { + HRESULT fn1([in] int x); + HRESULT fn2([out,retval] int *x); + } + + [ + odl, + uuid(51033a23-dc37-4f19-aa34-4d8a670458a0) + + ] + interface ItestIF9 : ItestIF8 + { + HRESULT fn3([in] int y); + } + + [ + odl, + uuid(2e8f14fe-0bce-42f0-8b7d-3af8393c7967) + ] + dispinterface ItestIF10 + { + interface ItestIF9; + } + + [ + odl, + uuid(7d9e9371-482e-4944-9b19-511fc705236f) + ] + dispinterface ItestIF11 + { + interface ItestIF7; + } + }; diff --git a/dlls/oleaut32/tests/typelib.c b/dlls/oleaut32/tests/typelib.c index 0af97749c34..d19afd3038a 100644 --- a/dlls/oleaut32/tests/typelib.c +++ b/dlls/oleaut32/tests/typelib.c @@ -29,6 +29,7 @@ #include "oleauto.h" #include "ocidl.h" #include "shlwapi.h" +#include "tmarshal.h" #define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error 0x%08x\n", hr) @@ -343,18 +344,21 @@ static void test_CreateDispTypeInfo(void) hr = ITypeInfo_GetRefTypeOfImplType(pTypeInfo, 0, &href); ok(hr == S_OK, "hr %08x\n", hr); - todo_wine { ok(href == 0, "href = 0x%x\n", href); - } hr = ITypeInfo_GetRefTypeInfo(pTypeInfo, href, &pTI2); ok(hr == S_OK, "hr %08x\n", hr); hr = ITypeInfo_GetTypeAttr(pTI2, &pTypeAttr); ok(hr == S_OK, "hr %08x\n", hr); ok(pTypeAttr->typekind == TKIND_INTERFACE, "typekind %0x\n", pTypeAttr->typekind); + ok(pTypeAttr->cFuncs == 4, "cFuncs %d\n", pTypeAttr->cFuncs); + ok(IsEqualGUID(&pTypeAttr->guid, &GUID_NULL), "guid {%08x-...}\n", pTypeAttr->guid.Data1); + ok(pTypeAttr->wTypeFlags == 0, "typeflags %08x\n", pTypeAttr->wTypeFlags); + ITypeInfo_ReleaseTypeAttr(pTI2, pTypeAttr); hr = ITypeInfo_GetFuncDesc(pTI2, 0, &pFuncDesc); ok(hr == S_OK, "hr %08x\n", hr); + ok(pFuncDesc->memid == 0x123, "memid %x\n", pFuncDesc->memid); ok(pFuncDesc->funckind == FUNC_VIRTUAL, "funckind %d\n", pFuncDesc->funckind); ok(pFuncDesc->invkind == methdata[0].wFlags, "invkind %d\n", pFuncDesc->invkind); ok(pFuncDesc->callconv == methdata[0].cc, "callconv %d\n", pFuncDesc->callconv); @@ -575,6 +579,253 @@ static void test_QueryPathOfRegTypeLib(void) do_typelib_reg_key(&uid, 0, 0, NULL, 1); } +static void test_inheritance(void) +{ + HRESULT hr; + ITypeLib *pTL; + ITypeInfo *pTI, *pTI_p; + TYPEATTR *pTA; + HREFTYPE href; + FUNCDESC *pFD; + WCHAR path[MAX_PATH]; + static const WCHAR tl_path[] = {'.','\\','m','i','d','l','_','t','m','a','r','s','h','a','l','.','t','l','b',0}; + + BOOL use_midl_tlb = 0; + + GetModuleFileNameW(NULL, path, MAX_PATH); + + if(use_midl_tlb) + memcpy(path, tl_path, sizeof(tl_path)); + + hr = LoadTypeLib(path, &pTL); + if(FAILED(hr)) return; + + + /* ItestIF3 is a syntax 2 dispinterface */ + hr = ITypeLib_GetTypeInfoOfGuid(pTL, &DIID_ItestIF3, &pTI); + ok(hr == S_OK, "hr %08x\n", hr); + + hr = ITypeInfo_GetTypeAttr(pTI, &pTA); + ok(hr == S_OK, "hr %08x\n", hr); + ok(pTA->typekind == TKIND_DISPATCH, "kind %04x\n", pTA->typekind); + ok(pTA->cbSizeVft == 28, "sizevft %d\n", pTA->cbSizeVft); + ok(pTA->wTypeFlags == TYPEFLAG_FDISPATCHABLE, "typeflags %x\n", pTA->wTypeFlags); +if(use_midl_tlb) { + ok(pTA->cFuncs == 6, "cfuncs %d\n", pTA->cFuncs); + ok(pTA->cImplTypes == 1, "cimpltypes %d\n", pTA->cImplTypes); + ITypeInfo_ReleaseTypeAttr(pTI, pTA); + + hr = ITypeInfo_GetRefTypeOfImplType(pTI, 0, &href); + ok(hr == S_OK, "hr %08x\n", hr); + hr = ITypeInfo_GetRefTypeInfo(pTI, href, &pTI_p); + ok(hr == S_OK, "hr %08x\n", hr); + hr = ITypeInfo_GetTypeAttr(pTI_p, &pTA); + ok(IsEqualGUID(&pTA->guid, &IID_IDispatch), "guid {%08x-....\n", pTA->guid.Data1); + ITypeInfo_ReleaseTypeAttr(pTI_p, pTA); + ITypeInfo_Release(pTI_p); + + /* Should have six methods */ + hr = ITypeInfo_GetFuncDesc(pTI, 6, &pFD); + ok(hr == TYPE_E_ELEMENTNOTFOUND, "hr %08x\n", hr); + hr = ITypeInfo_GetFuncDesc(pTI, 5, &pFD); + ok(hr == S_OK, "hr %08x\n", hr); + ok(pFD->memid == 0x60020000, "memid %08x\n", pFD->memid); + ok(pFD->oVft == 20, "oVft %d\n", pFD->oVft); + ITypeInfo_ReleaseFuncDesc(pTI, pFD); +} + ITypeInfo_Release(pTI); + + + /* ItestIF4 is a syntax 1 dispinterface */ + hr = ITypeLib_GetTypeInfoOfGuid(pTL, &DIID_ItestIF4, &pTI); + ok(hr == S_OK, "hr %08x\n", hr); + + hr = ITypeInfo_GetTypeAttr(pTI, &pTA); + ok(hr == S_OK, "hr %08x\n", hr); + ok(pTA->typekind == TKIND_DISPATCH, "kind %04x\n", pTA->typekind); + ok(pTA->cbSizeVft == 28, "sizevft %d\n", pTA->cbSizeVft); + ok(pTA->wTypeFlags == TYPEFLAG_FDISPATCHABLE, "typeflags %x\n", pTA->wTypeFlags); + ok(pTA->cFuncs == 1, "cfuncs %d\n", pTA->cFuncs); + ok(pTA->cImplTypes == 1, "cimpltypes %d\n", pTA->cImplTypes); + ITypeInfo_ReleaseTypeAttr(pTI, pTA); + + hr = ITypeInfo_GetRefTypeOfImplType(pTI, 0, &href); + ok(hr == S_OK, "hr %08x\n", hr); + hr = ITypeInfo_GetRefTypeInfo(pTI, href, &pTI_p); + ok(hr == S_OK, "hr %08x\n", hr); + hr = ITypeInfo_GetTypeAttr(pTI_p, &pTA); + ok(IsEqualGUID(&pTA->guid, &IID_IDispatch), "guid {%08x-....\n", pTA->guid.Data1); + ITypeInfo_ReleaseTypeAttr(pTI_p, pTA); + ITypeInfo_Release(pTI_p); + hr = ITypeInfo_GetFuncDesc(pTI, 1, &pFD); + ok(hr == TYPE_E_ELEMENTNOTFOUND, "hr %08x\n", hr); + hr = ITypeInfo_GetFuncDesc(pTI, 0, &pFD); + ok(hr == S_OK, "hr %08x\n", hr); + ok(pFD->memid == 0x1c, "memid %08x\n", pFD->memid); + ITypeInfo_ReleaseFuncDesc(pTI, pFD); + ITypeInfo_Release(pTI); + + + /* ItestIF5 is dual with inherited ifaces which derive from IUnknown but not IDispatch */ + hr = ITypeLib_GetTypeInfoOfGuid(pTL, &IID_ItestIF5, &pTI); + ok(hr == S_OK, "hr %08x\n", hr); + + hr = ITypeInfo_GetTypeAttr(pTI, &pTA); + ok(hr == S_OK, "hr %08x\n", hr); + ok(pTA->typekind == TKIND_DISPATCH, "kind %04x\n", pTA->typekind); + ok(pTA->cbSizeVft == 28, "sizevft %d\n", pTA->cbSizeVft); +if(use_midl_tlb) { + ok(pTA->wTypeFlags == TYPEFLAG_FDUAL, "typeflags %x\n", pTA->wTypeFlags); + } + ok(pTA->cFuncs == 8, "cfuncs %d\n", pTA->cFuncs); + ok(pTA->cImplTypes == 1, "cimpltypes %d\n", pTA->cImplTypes); + ITypeInfo_ReleaseTypeAttr(pTI, pTA); + + hr = ITypeInfo_GetRefTypeOfImplType(pTI, 0, &href); + ok(hr == S_OK, "hr %08x\n", hr); + hr = ITypeInfo_GetRefTypeInfo(pTI, href, &pTI_p); + ok(hr == S_OK, "hr %08x\n", hr); + hr = ITypeInfo_GetTypeAttr(pTI_p, &pTA); + ok(IsEqualGUID(&pTA->guid, &IID_IDispatch), "guid {%08x-....\n", pTA->guid.Data1); + ITypeInfo_ReleaseTypeAttr(pTI_p, pTA); + ITypeInfo_Release(pTI_p); +if(use_midl_tlb) { + hr = ITypeInfo_GetFuncDesc(pTI, 6, &pFD); + ok(hr == S_OK, "hr %08x\n", hr); + ok(pFD->memid == 0x1234, "memid %08x\n", pFD->memid); + ITypeInfo_ReleaseFuncDesc(pTI, pFD); +} + ITypeInfo_Release(pTI); + + /* ItestIF7 is dual with inherited ifaces which derive from Dispatch */ + hr = ITypeLib_GetTypeInfoOfGuid(pTL, &IID_ItestIF7, &pTI); + ok(hr == S_OK, "hr %08x\n", hr); + + hr = ITypeInfo_GetTypeAttr(pTI, &pTA); + ok(hr == S_OK, "hr %08x\n", hr); + ok(pTA->typekind == TKIND_DISPATCH, "kind %04x\n", pTA->typekind); + ok(pTA->cbSizeVft == 28, "sizevft %d\n", pTA->cbSizeVft); + ok(pTA->wTypeFlags == (TYPEFLAG_FDISPATCHABLE|TYPEFLAG_FDUAL), "typeflags %x\n", pTA->wTypeFlags); + ok(pTA->cFuncs == 10, "cfuncs %d\n", pTA->cFuncs); + ok(pTA->cImplTypes == 1, "cimpltypes %d\n", pTA->cImplTypes); + ITypeInfo_ReleaseTypeAttr(pTI, pTA); + + hr = ITypeInfo_GetRefTypeOfImplType(pTI, 0, &href); + ok(hr == S_OK, "hr %08x\n", hr); + hr = ITypeInfo_GetRefTypeInfo(pTI, href, &pTI_p); + ok(hr == S_OK, "hr %08x\n", hr); + hr = ITypeInfo_GetTypeAttr(pTI_p, &pTA); + ok(IsEqualGUID(&pTA->guid, &IID_IDispatch), "guid {%08x-....\n", pTA->guid.Data1); + ITypeInfo_ReleaseTypeAttr(pTI_p, pTA); + ITypeInfo_Release(pTI_p); + + hr = ITypeInfo_GetFuncDesc(pTI, 9, &pFD); + ok(hr == S_OK, "hr %08x\n", hr); + ok(pFD->memid == 0x1236, "memid %08x\n", pFD->memid); + ITypeInfo_ReleaseFuncDesc(pTI, pFD); + ITypeInfo_Release(pTI); + + /* ItestIF10 is a syntax 2 dispinterface which doesn't derive from IUnknown */ + hr = ITypeLib_GetTypeInfoOfGuid(pTL, &DIID_ItestIF10, &pTI); + ok(hr == S_OK, "hr %08x\n", hr); + + hr = ITypeInfo_GetTypeAttr(pTI, &pTA); + ok(hr == S_OK, "hr %08x\n", hr); + ok(pTA->typekind == TKIND_DISPATCH, "kind %04x\n", pTA->typekind); + ok(pTA->cbSizeVft == 28, "sizevft %d\n", pTA->cbSizeVft); + ok(pTA->wTypeFlags == TYPEFLAG_FDISPATCHABLE, "typeflags %x\n", pTA->wTypeFlags); +if(use_midl_tlb) { + ok(pTA->cFuncs == 3, "cfuncs %d\n", pTA->cFuncs); + ok(pTA->cImplTypes == 1, "cimpltypes %d\n", pTA->cImplTypes); + ITypeInfo_ReleaseTypeAttr(pTI, pTA); + + hr = ITypeInfo_GetRefTypeOfImplType(pTI, -1, &href); + ok(hr == TYPE_E_ELEMENTNOTFOUND, "hr %08x\n", hr); + hr = ITypeInfo_GetRefTypeOfImplType(pTI, 0, &href); + ok(hr == S_OK, "hr %08x\n", hr); + hr = ITypeInfo_GetRefTypeInfo(pTI, href, &pTI_p); + ok(hr == S_OK, "hr %08x\n", hr); + hr = ITypeInfo_GetTypeAttr(pTI_p, &pTA); + ok(IsEqualGUID(&pTA->guid, &IID_IDispatch), "guid {%08x-....\n", pTA->guid.Data1); + ITypeInfo_ReleaseTypeAttr(pTI_p, pTA); + ITypeInfo_Release(pTI_p); + + /* Should have three methods */ + hr = ITypeInfo_GetFuncDesc(pTI, 3, &pFD); + ok(hr == TYPE_E_ELEMENTNOTFOUND, "hr %08x\n", hr); + hr = ITypeInfo_GetFuncDesc(pTI, 2, &pFD); + ok(hr == S_OK, "hr %08x\n", hr); + ok(pFD->memid == 0x60010000, "memid %08x\n", pFD->memid); + ok(pFD->oVft == 8, "oVft %d\n", pFD->oVft); + ITypeInfo_ReleaseFuncDesc(pTI, pFD); +} + ITypeInfo_Release(pTI); + + /* ItestIF11 is a syntax 2 dispinterface which derives from IDispatch */ + hr = ITypeLib_GetTypeInfoOfGuid(pTL, &DIID_ItestIF11, &pTI); + ok(hr == S_OK, "hr %08x\n", hr); + + hr = ITypeInfo_GetTypeAttr(pTI, &pTA); + ok(hr == S_OK, "hr %08x\n", hr); + ok(pTA->typekind == TKIND_DISPATCH, "kind %04x\n", pTA->typekind); + ok(pTA->cbSizeVft == 28, "sizevft %d\n", pTA->cbSizeVft); + ok(pTA->wTypeFlags == TYPEFLAG_FDISPATCHABLE, "typeflags %x\n", pTA->wTypeFlags); +if(use_midl_tlb) { + ok(pTA->cFuncs == 10, "cfuncs %d\n", pTA->cFuncs); + ok(pTA->cImplTypes == 1, "cimpltypes %d\n", pTA->cImplTypes); + ITypeInfo_ReleaseTypeAttr(pTI, pTA); + + hr = ITypeInfo_GetRefTypeOfImplType(pTI, 0, &href); + ok(hr == S_OK, "hr %08x\n", hr); + hr = ITypeInfo_GetRefTypeInfo(pTI, href, &pTI_p); + ok(hr == S_OK, "hr %08x\n", hr); + hr = ITypeInfo_GetTypeAttr(pTI_p, &pTA); + ok(IsEqualGUID(&pTA->guid, &IID_IDispatch), "guid {%08x-....\n", pTA->guid.Data1); + ITypeInfo_ReleaseTypeAttr(pTI_p, pTA); + ITypeInfo_Release(pTI_p); + + /* Should have ten methods */ + hr = ITypeInfo_GetFuncDesc(pTI, 10, &pFD); + ok(hr == TYPE_E_ELEMENTNOTFOUND, "hr %08x\n", hr); + hr = ITypeInfo_GetFuncDesc(pTI, 9, &pFD); + ok(hr == S_OK, "hr %08x\n", hr); + ok(pFD->memid == 0x1236, "memid %08x\n", pFD->memid); + ok(pFD->oVft == 36, "oVft %d\n", pFD->oVft); + ITypeInfo_ReleaseFuncDesc(pTI, pFD); +} + ITypeInfo_Release(pTI); + + + /* ItestIF2 is an interface which derives from IUnknown */ + hr = ITypeLib_GetTypeInfoOfGuid(pTL, &IID_ItestIF2, &pTI); + ok(hr == S_OK, "hr %08x\n", hr); + + hr = ITypeInfo_GetTypeAttr(pTI, &pTA); + ok(hr == S_OK, "hr %08x\n", hr); + ok(pTA->typekind == TKIND_INTERFACE, "kind %04x\n", pTA->typekind); + ok(pTA->cbSizeVft == 24, "sizevft %d\n", pTA->cbSizeVft); + ok(pTA->wTypeFlags == 0, "typeflags %x\n", pTA->wTypeFlags); +if(use_midl_tlb) { + ok(pTA->cFuncs == 1, "cfuncs %d\n", pTA->cFuncs); + ok(pTA->cImplTypes == 1, "cimpltypes %d\n", pTA->cImplTypes); + ITypeInfo_ReleaseTypeAttr(pTI, pTA); + + /* Should have one method */ + hr = ITypeInfo_GetFuncDesc(pTI, 1, &pFD); + ok(hr == TYPE_E_ELEMENTNOTFOUND, "hr %08x\n", hr); + hr = ITypeInfo_GetFuncDesc(pTI, 0, &pFD); + ok(hr == S_OK, "hr %08x\n", hr); + ok(pFD->memid == 0x60020000, "memid %08x\n", pFD->memid); + ok(pFD->oVft == 20, "oVft %d\n", pFD->oVft); + ITypeInfo_ReleaseFuncDesc(pTI, pFD); +} + ITypeInfo_Release(pTI); + + ITypeLib_Release(pTL); + + return; +} + START_TEST(typelib) { ref_count_test(wszStdOle2); @@ -582,4 +833,5 @@ START_TEST(typelib) test_CreateDispTypeInfo(); test_TypeInfo(); test_QueryPathOfRegTypeLib(); + test_inheritance(); } diff --git a/dlls/oleaut32/tmarshal.c b/dlls/oleaut32/tmarshal.c index 94c6e58c591..37729108db7 100644 --- a/dlls/oleaut32/tmarshal.c +++ b/dlls/oleaut32/tmarshal.c @@ -320,49 +320,49 @@ _get_typeinfo_for_iid(REFIID riid, ITypeInfo**ti) { return hres; } -/* Determine nr of functions. Since we use the toplevel interface and all - * inherited ones have lower numbers, we are ok to not to descent into - * the inheritance tree I think. +/* + * Determine the number of functions including all inherited functions. + * Note for non-dual dispinterfaces we simply return the size of IDispatch. */ -static int _nroffuncs(ITypeInfo *tinfo) { - int n, i, j; - const FUNCDESC *fdesc; - HRESULT hres; +static HRESULT num_of_funcs(ITypeInfo *tinfo, unsigned int *num) +{ + HRESULT hres; TYPEATTR *attr; ITypeInfo *tinfo2; - n=0; + *num = 0; hres = ITypeInfo_GetTypeAttr(tinfo, &attr); if (hres) { ERR("GetTypeAttr failed with %x\n",hres); return hres; } - /* look in inherited ifaces. */ - for (j=0;jcImplTypes;j++) { + + if(attr->typekind == TKIND_DISPATCH && (attr->wTypeFlags & TYPEFLAG_FDUAL)) + { HREFTYPE href; - hres = ITypeInfo_GetRefTypeOfImplType(tinfo, j, &href); - if (hres) { - ERR("Did not find a reftype for interface offset %d?\n",j); - break; + hres = ITypeInfo_GetRefTypeOfImplType(tinfo, -1, &href); + if(FAILED(hres)) + { + ERR("Unable to get interface href from dual dispinterface\n"); + goto end; } hres = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2); - if (hres) { - ERR("Did not find a typeinfo for reftype %d?\n",href); - continue; + if(FAILED(hres)) + { + ERR("Unable to get interface from dual dispinterface\n"); + goto end; } - n += _nroffuncs(tinfo2); + hres = num_of_funcs(tinfo2, num); ITypeInfo_Release(tinfo2); } - ITypeInfo_ReleaseTypeAttr(tinfo, attr); - i = 0; - while (1) { - hres = ITypeInfoImpl_GetInternalFuncDesc(tinfo,i,&fdesc); - if (hres) - return n; - n++; - i++; + else + { + *num = attr->cbSizeVft / 4; } - /*NOTREACHED*/ + + end: + ITypeInfo_ReleaseTypeAttr(tinfo, attr); + return hres; } #ifdef __i386__ @@ -1215,6 +1215,37 @@ static HRESULT get_funcdesc(ITypeInfo *tinfo, int iMethod, ITypeInfo **tactual, ERR("GetTypeAttr failed with %x\n",hr); return hr; } + + if(attr->typekind == TKIND_DISPATCH) + { + if(attr->wTypeFlags & TYPEFLAG_FDUAL) + { + HREFTYPE href; + ITypeInfo *tinfo2; + + hr = ITypeInfo_GetRefTypeOfImplType(tinfo, -1, &href); + if(FAILED(hr)) + { + ERR("Cannot get interface href from dual dispinterface\n"); + ITypeInfo_ReleaseTypeAttr(tinfo, attr); + return hr; + } + hr = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2); + if(FAILED(hr)) + { + ERR("Cannot get interface from dual dispinterface\n"); + ITypeInfo_ReleaseTypeAttr(tinfo, attr); + return hr; + } + hr = get_funcdesc(tinfo2, iMethod, tactual, fdesc, iname, fname, num); + ITypeInfo_Release(tinfo2); + ITypeInfo_ReleaseTypeAttr(tinfo, attr); + return hr; + } + ERR("Shouldn't be called with a non-dual dispinterface\n"); + return E_FAIL; + } + impl_types = attr->cImplTypes; ITypeInfo_ReleaseTypeAttr(tinfo, attr); @@ -1640,6 +1671,58 @@ static inline HRESULT get_facbuf_for_iid(REFIID riid, IPSFactoryBuffer **facbuf) &IID_IPSFactoryBuffer, (LPVOID*)facbuf); } +static HRESULT init_proxy_entry_point(TMProxyImpl *proxy, unsigned int num) +{ + int j; + /* nrofargs without This */ + int nrofargs; + ITypeInfo *tinfo2; + TMAsmProxy *xasm = proxy->asmstubs + num; + HRESULT hres; + const FUNCDESC *fdesc; + + hres = get_funcdesc(proxy->tinfo, num, &tinfo2, &fdesc, NULL, NULL, NULL); + if (hres) { + ERR("GetFuncDesc %x should not fail here.\n",hres); + return hres; + } + ITypeInfo_Release(tinfo2); + /* some args take more than 4 byte on the stack */ + nrofargs = 0; + for (j=0;jcParams;j++) + nrofargs += _argsize(fdesc->lprgelemdescParam[j].tdesc.vt); + +#ifdef __i386__ + if (fdesc->callconv != CC_STDCALL) { + ERR("calling convention is not stdcall????\n"); + return E_FAIL; + } +/* popl %eax - return ptr + * pushl + * pushl %eax + * call xCall + * lret (+4) + * + * + * arg3 arg2 arg1 + */ + xasm->popleax = 0x58; + xasm->pushlval = 0x6a; + xasm->nr = num; + xasm->pushleax = 0x50; + xasm->lcall = 0xe8; /* relative jump */ + xasm->xcall = (DWORD)xCall; + xasm->xcall -= (DWORD)&(xasm->lret); + xasm->lret = 0xc2; + xasm->bytestopop = (nrofargs+2)*4; /* pop args, This, iMethod */ + proxy->lpvtbl[num] = xasm; +#else + FIXME("not implemented on non i386\n"); + return E_FAIL; +#endif + return S_OK; +} + static HRESULT WINAPI PSFacBuf_CreateProxy( LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid, @@ -1647,10 +1730,10 @@ PSFacBuf_CreateProxy( { HRESULT hres; ITypeInfo *tinfo; - int i, nroffuncs; - const FUNCDESC *fdesc; + unsigned int i, nroffuncs; TMProxyImpl *proxy; TYPEATTR *typeattr; + BOOL defer_to_dispatch = FALSE; TRACE("(...%s...)\n",debugstr_guid(riid)); hres = _get_typeinfo_for_iid(riid,&tinfo); @@ -1658,7 +1741,14 @@ PSFacBuf_CreateProxy( ERR("No typeinfo for %s?\n",debugstr_guid(riid)); return hres; } - nroffuncs = _nroffuncs(tinfo); + + hres = num_of_funcs(tinfo, &nroffuncs); + if (FAILED(hres)) { + ERR("Cannot get number of functions for typeinfo %s\n",debugstr_guid(riid)); + ITypeInfo_Release(tinfo); + return hres; + } + proxy = CoTaskMemAlloc(sizeof(TMProxyImpl)); if (!proxy) return E_OUTOFMEMORY; @@ -1684,67 +1774,6 @@ PSFacBuf_CreateProxy( proxy->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TMProxyImpl.crit"); proxy->lpvtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPBYTE)*nroffuncs); - for (i=0;iasmstubs+i; - - switch (i) { - case 0: - proxy->lpvtbl[i] = ProxyIUnknown_QueryInterface; - break; - case 1: - proxy->lpvtbl[i] = ProxyIUnknown_AddRef; - break; - case 2: - proxy->lpvtbl[i] = ProxyIUnknown_Release; - break; - default: { - int j; - /* nrofargs without This */ - int nrofargs; - ITypeInfo *tinfo2; - hres = get_funcdesc(tinfo,i,&tinfo2,&fdesc,NULL,NULL,NULL); - if (hres) { - ERR("GetFuncDesc %x should not fail here.\n",hres); - return hres; - } - ITypeInfo_Release(tinfo2); - /* some args take more than 4 byte on the stack */ - nrofargs = 0; - for (j=0;jcParams;j++) - nrofargs += _argsize(fdesc->lprgelemdescParam[j].tdesc.vt); - -#ifdef __i386__ - if (fdesc->callconv != CC_STDCALL) { - ERR("calling convention is not stdcall????\n"); - return E_FAIL; - } -/* popl %eax - return ptr - * pushl - * pushl %eax - * call xCall - * lret (+4) - * - * - * arg3 arg2 arg1 - */ - xasm->popleax = 0x58; - xasm->pushlval = 0x6a; - xasm->nr = i; - xasm->pushleax = 0x50; - xasm->lcall = 0xe8; /* relative jump */ - xasm->xcall = (DWORD)xCall; - xasm->xcall -= (DWORD)&(xasm->lret); - xasm->lret = 0xc2; - xasm->bytestopop= (nrofargs+2)*4; /* pop args, This, iMethod */ - proxy->lpvtbl[i] = xasm; - break; -#else - FIXME("not implemented on non i386\n"); - return E_FAIL; -#endif - } - } - } /* if we derive from IDispatch then defer to its proxy for its methods */ hres = ITypeInfo_GetTypeAttr(tinfo, &typeattr); @@ -1768,15 +1797,61 @@ PSFacBuf_CreateProxy( } if (hres == S_OK) { - proxy->lpvtbl[3] = ProxyIDispatch_GetTypeInfoCount; - proxy->lpvtbl[4] = ProxyIDispatch_GetTypeInfo; - proxy->lpvtbl[5] = ProxyIDispatch_GetIDsOfNames; - proxy->lpvtbl[6] = ProxyIDispatch_Invoke; + defer_to_dispatch = TRUE; } } ITypeInfo_ReleaseTypeAttr(tinfo, typeattr); } + for (i=0;ilpvtbl[i] = ProxyIUnknown_QueryInterface; + break; + case 1: + proxy->lpvtbl[i] = ProxyIUnknown_AddRef; + break; + case 2: + proxy->lpvtbl[i] = ProxyIUnknown_Release; + break; + case 3: + if(!defer_to_dispatch) + { + hres = init_proxy_entry_point(proxy, i); + if(FAILED(hres)) return hres; + } + else proxy->lpvtbl[3] = ProxyIDispatch_GetTypeInfoCount; + break; + case 4: + if(!defer_to_dispatch) + { + hres = init_proxy_entry_point(proxy, i); + if(FAILED(hres)) return hres; + } + else proxy->lpvtbl[4] = ProxyIDispatch_GetTypeInfo; + break; + case 5: + if(!defer_to_dispatch) + { + hres = init_proxy_entry_point(proxy, i); + if(FAILED(hres)) return hres; + } + else proxy->lpvtbl[5] = ProxyIDispatch_GetIDsOfNames; + break; + case 6: + if(!defer_to_dispatch) + { + hres = init_proxy_entry_point(proxy, i); + if(FAILED(hres)) return hres; + } + else proxy->lpvtbl[6] = ProxyIDispatch_Invoke; + break; + default: + hres = init_proxy_entry_point(proxy, i); + if(FAILED(hres)) return hres; + } + } + if (hres == S_OK) { *ppv = (LPVOID)proxy; diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index 50b29280d1d..a1b28ece545 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -70,6 +70,7 @@ #include "typelib.h" #include "wine/debug.h" #include "variant.h" +#include "wine/list.h" WINE_DEFAULT_DEBUG_CHANNEL(ole); WINE_DECLARE_DEBUG_CHANNEL(typelib); @@ -894,8 +895,11 @@ typedef struct tagITypeLibImpl TLBImpLib * pImpLibs; /* linked list to all imported typelibs */ int ctTypeDesc; /* number of items in type desc array */ TYPEDESC * pTypeDesc; /* array of TypeDescriptions found in the - library. Only used while read MSFT + library. Only used while reading MSFT typelibs */ + struct list ref_list; /* list of ref types in this typelib */ + HREFTYPE dispatch_href; /* reference to IDispatch, -1 if unused */ + /* typelibs are cached, keyed by path and index, so store the linked list info within them */ struct tagITypeLibImpl *next, *prev; @@ -932,7 +936,7 @@ typedef struct tagTLBRefType TLB_REF_INTERNAL for internal refs TLB_REF_NOT_FOUND for broken refs */ - struct tagTLBRefType * next; + struct list entry; } TLBRefType; #define TLB_REF_USE_GUID -2 @@ -1015,7 +1019,6 @@ typedef struct tagITypeInfoImpl /* Implemented Interfaces */ TLBImplType * impltypelist; - TLBRefType * reflist; int ctCustData; TLBCustData * pCustData; /* linked list to cust data; */ struct tagITypeInfoImpl * next; @@ -1042,7 +1045,7 @@ typedef struct tagTLBContext } TLBContext; -static void MSFT_DoRefType(TLBContext *pcx, ITypeInfoImpl *pTI, int offset); +static void MSFT_DoRefType(TLBContext *pcx, ITypeLibImpl *pTL, int offset); /* debug @@ -1200,23 +1203,24 @@ static void dump_TLBImpLib(const TLBImpLib *import) import->wVersionMinor, import->lcid, import->offset); } -static void dump_TLBRefType(const TLBRefType * prt) +static void dump_TLBRefType(const ITypeLibImpl *pTL) { - while (prt) - { - TRACE_(typelib)("href:0x%08x\n", prt->reference); - if(prt->index == -1) - TRACE_(typelib)("%s\n", debugstr_guid(&(prt->guid))); - else - TRACE_(typelib)("type no: %d\n", prt->index); - - if(prt->pImpTLInfo != TLB_REF_INTERNAL && - prt->pImpTLInfo != TLB_REF_NOT_FOUND) { - TRACE_(typelib)("in lib\n"); - dump_TLBImpLib(prt->pImpTLInfo); - } - prt = prt->next; - }; + TLBRefType *ref; + + LIST_FOR_EACH_ENTRY(ref, &pTL->ref_list, TLBRefType, entry) + { + TRACE_(typelib)("href:0x%08x\n", ref->reference); + if(ref->index == -1) + TRACE_(typelib)("%s\n", debugstr_guid(&(ref->guid))); + else + TRACE_(typelib)("type no: %d\n", ref->index); + + if(ref->pImpTLInfo != TLB_REF_INTERNAL && ref->pImpTLInfo != TLB_REF_NOT_FOUND) + { + TRACE_(typelib)("in lib\n"); + dump_TLBImpLib(ref->pImpTLInfo); + } + } } static void dump_TLBImplType(const TLBImplType * impl) @@ -1697,7 +1701,7 @@ static void MSFT_GetTdesc(TLBContext *pcx, INT type, TYPEDESC *pTd, *pTd=pcx->pLibInfo->pTypeDesc[type/(2*sizeof(INT))]; if(pTd->vt == VT_USERDEFINED) - MSFT_DoRefType(pcx, pTI, pTd->u.hreftype); + MSFT_DoRefType(pcx, pTI->pTypeLib, pTd->u.hreftype); TRACE_(typelib)("vt type = %X\n", pTd->vt); } @@ -1718,7 +1722,7 @@ static void MSFT_ResolveReferencedTypes(TLBContext *pcx, ITypeInfoImpl *pTI, TYP break; case VT_USERDEFINED: - MSFT_DoRefType(pcx, pTI, + MSFT_DoRefType(pcx, pTI->pTypeLib, lpTypeDesc->u.hreftype); lpTypeDesc = NULL; @@ -2002,22 +2006,21 @@ static void MSFT_DoVars(TLBContext *pcx, ITypeInfoImpl *pTI, int cFuncs, * in the typelib, it's just an (file) offset in the type info base dir. * If comes from import, it's an offset+1 in the ImpInfo table * */ -static void MSFT_DoRefType(TLBContext *pcx, ITypeInfoImpl *pTI, +static void MSFT_DoRefType(TLBContext *pcx, ITypeLibImpl *pTL, int offset) { int j; - TLBRefType **ppRefType = &pTI->reflist; + TLBRefType *ref; TRACE_(typelib)("TLB context %p, TLB offset %x\n", pcx, offset); - while(*ppRefType) { - if((*ppRefType)->reference == offset) - return; - ppRefType = &(*ppRefType)->next; + LIST_FOR_EACH_ENTRY(ref, &pTL->ref_list, TLBRefType, entry) + { + if(ref->reference == offset) return; } - *ppRefType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(**ppRefType)); + ref = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ref)); + list_add_tail(&pTL->ref_list, &ref->entry); if(!MSFT_HREFTYPE_INTHISFILE( offset)) { /* external typelib */ @@ -2033,24 +2036,24 @@ static void MSFT_DoRefType(TLBContext *pcx, ITypeInfoImpl *pTI, pImpLib=pImpLib->next; } if(pImpLib){ - (*ppRefType)->reference=offset; - (*ppRefType)->pImpTLInfo = pImpLib; + ref->reference = offset; + ref->pImpTLInfo = pImpLib; if(impinfo.flags & MSFT_IMPINFO_OFFSET_IS_GUID) { - MSFT_ReadGuid(&(*ppRefType)->guid, impinfo.oGuid, pcx); - TRACE("importing by guid %s\n", debugstr_guid(&(*ppRefType)->guid)); - (*ppRefType)->index = TLB_REF_USE_GUID; + MSFT_ReadGuid(&ref->guid, impinfo.oGuid, pcx); + TRACE("importing by guid %s\n", debugstr_guid(&ref->guid)); + ref->index = TLB_REF_USE_GUID; } else - (*ppRefType)->index = impinfo.oGuid; + ref->index = impinfo.oGuid; }else{ ERR("Cannot find a reference\n"); - (*ppRefType)->reference=-1; - (*ppRefType)->pImpTLInfo=TLB_REF_NOT_FOUND; + ref->reference = -1; + ref->pImpTLInfo = TLB_REF_NOT_FOUND; } }else{ /* in this typelib */ - (*ppRefType)->index = MSFT_HREFTYPE_INDEX(offset); - (*ppRefType)->reference=offset; - (*ppRefType)->pImpTLInfo=TLB_REF_INTERNAL; + ref->index = MSFT_HREFTYPE_INDEX(offset); + ref->reference = offset; + ref->pImpTLInfo = TLB_REF_INTERNAL; } } @@ -2068,7 +2071,7 @@ static void MSFT_DoImplTypes(TLBContext *pcx, ITypeInfoImpl *pTI, int count, if(offset<0) break; /* paranoia */ *ppImpl=TLB_Alloc(sizeof(**ppImpl)); MSFT_ReadLEDWords(&refrec,sizeof(refrec),pcx,offset+pcx->pTblDir->pRefTab.offset); - MSFT_DoRefType(pcx, pTI, refrec.reftype); + MSFT_DoRefType(pcx, pTI->pTypeLib, refrec.reftype); (*ppImpl)->hRef = refrec.reftype; (*ppImpl)->implflags=refrec.flags; (*ppImpl)->ctCustData= @@ -2083,7 +2086,6 @@ static void MSFT_DoImplTypes(TLBContext *pcx, ITypeInfoImpl *pTI, int count, static ITypeInfoImpl * MSFT_DoTypeInfo( TLBContext *pcx, int count, - INT dispatch_href, ITypeLibImpl * pLibInfo) { MSFT_TypeInfoBase tiBase; @@ -2153,22 +2155,22 @@ static ITypeInfoImpl * MSFT_DoTypeInfo( tiBase.datatype1); break; case TKIND_DISPATCH: - ptiRet->impltypelist=TLB_Alloc(sizeof(TLBImplType)); + /* This is not -1 when the interface is a non-base dual interface or + when a dispinterface wraps an interface ie the idl 'dispinterface x {interface y;};'. + Note however that GetRefTypeOfImplType(0) always returns a ref to IDispatch and + not this interface. + */ if (tiBase.datatype1 != -1) { - MSFT_DoRefType(pcx, ptiRet, tiBase.datatype1); - ptiRet->impltypelist->hRef = tiBase.datatype1; - } - else - { - MSFT_DoRefType(pcx, ptiRet, dispatch_href); - ptiRet->impltypelist->hRef = dispatch_href; + ptiRet->impltypelist = TLB_Alloc(sizeof(TLBImplType)); + ptiRet->impltypelist->hRef = tiBase.datatype1; + MSFT_DoRefType(pcx, pLibInfo, tiBase.datatype1); } - break; + break; default: ptiRet->impltypelist=TLB_Alloc(sizeof(TLBImplType)); - MSFT_DoRefType(pcx, ptiRet, tiBase.datatype1); + MSFT_DoRefType(pcx, pLibInfo, tiBase.datatype1); ptiRet->impltypelist->hRef = tiBase.datatype1; break; } @@ -2362,6 +2364,9 @@ static ITypeLibImpl* TypeLibImpl_Constructor(void) pTypeLibImpl->lpVtblTypeComp = &tlbtcvt; pTypeLibImpl->ref = 1; + list_init(&pTypeLibImpl->ref_list); + pTypeLibImpl->dispatch_href = -1; + return pTypeLibImpl; } @@ -2556,6 +2561,10 @@ static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength) } } + pTypeLibImpl->dispatch_href = tlbHeader.dispatchpos; + if(pTypeLibImpl->dispatch_href != -1) + MSFT_DoRefType(&cx, pTypeLibImpl, pTypeLibImpl->dispatch_href); + /* type info's */ if(tlbHeader.nrtypeinfos >= 0 ) { @@ -2565,7 +2574,7 @@ static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength) for(i = 0; i<(int)tlbHeader.nrtypeinfos; i++) { - *ppTI = MSFT_DoTypeInfo(&cx, i, tlbHeader.dispatchpos, pTypeLibImpl); + *ppTI = MSFT_DoTypeInfo(&cx, i, pTypeLibImpl); ppTI = &((*ppTI)->next); (pTypeLibImpl->TypeInfoCount)++; @@ -2781,12 +2790,12 @@ static WORD *SLTG_DoElem(WORD *pType, char *pBlk, ELEMDESC *pElem) } -static void SLTG_DoRefs(SLTG_RefInfo *pRef, ITypeInfoImpl *pTI, +static void SLTG_DoRefs(SLTG_RefInfo *pRef, ITypeLibImpl *pTL, char *pNameTable) { int ref; char *name; - TLBRefType **ppRefType; + TLBRefType *ref_type; if(pRef->magic != SLTG_REF_MAGIC) { FIXME("Ref magic = %x\n", pRef->magic); @@ -2794,19 +2803,17 @@ static void SLTG_DoRefs(SLTG_RefInfo *pRef, ITypeInfoImpl *pTI, } name = ( (char*)(&pRef->names) + pRef->number); - ppRefType = &pTI->reflist; for(ref = 0; ref < pRef->number >> 3; ref++) { char *refname; unsigned int lib_offs, type_num; - *ppRefType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(**ppRefType)); + ref_type = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ref_type)); name += SLTG_ReadStringA(name, &refname); if(sscanf(refname, "*\\R%x*#%x", &lib_offs, &type_num) != 2) FIXME("Can't sscanf ref\n"); if(lib_offs != 0xffff) { - TLBImpLib **import = &pTI->pTypeLib->pImpLibs; + TLBImpLib **import = &pTL->pImpLibs; while(*import) { if((*import)->offset == lib_offs) @@ -2835,19 +2842,24 @@ static void SLTG_DoRefs(SLTG_RefInfo *pRef, ITypeInfoImpl *pTI, fname[len-1] = '\0'; (*import)->name = TLB_MultiByteToBSTR(fname); } - (*ppRefType)->pImpTLInfo = *import; + ref_type->pImpTLInfo = *import; + + /* Store a reference to IDispatch */ + if(pTL->dispatch_href == -1 && IsEqualGUID(&(*import)->guid, &IID_StdOle) && type_num == 4) + pTL->dispatch_href = ref; + } else { /* internal ref */ - (*ppRefType)->pImpTLInfo = TLB_REF_INTERNAL; + ref_type->pImpTLInfo = TLB_REF_INTERNAL; } - (*ppRefType)->reference = ref; - (*ppRefType)->index = type_num; + ref_type->reference = ref; + ref_type->index = type_num; HeapFree(GetProcessHeap(), 0, refname); - ppRefType = &(*ppRefType)->next; + list_add_tail(&pTL->ref_list, &ref_type->entry); } if((BYTE)*name != SLTG_REF_MAGIC) FIXME("End of ref block magic = %x\n", *name); - dump_TLBRefType(pTI->reflist); + dump_TLBRefType(pTL); } static char *SLTG_DoImpls(char *pBlk, ITypeInfoImpl *pTI, @@ -3074,7 +3086,7 @@ static void SLTG_ProcessCoClass(char *pBlk, ITypeInfoImpl *pTI, char *pFirstItem, *pNextItem; if(pTIHeader->href_table != 0xffffffff) { - SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI, + SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib, pNameTable); } @@ -3093,7 +3105,7 @@ static void SLTG_ProcessInterface(char *pBlk, ITypeInfoImpl *pTI, char *pFirstItem, *pNextItem; if(pTIHeader->href_table != 0xffffffff) { - SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI, + SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib, pNameTable); } @@ -3130,7 +3142,7 @@ static void SLTG_ProcessAlias(char *pBlk, ITypeInfoImpl *pTI, } if(pTIHeader->href_table != 0xffffffff) { - SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI, + SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib, pNameTable); } @@ -3145,7 +3157,7 @@ static void SLTG_ProcessDispatch(char *pBlk, ITypeInfoImpl *pTI, SLTG_TypeInfoTail *pTITail) { if (pTIHeader->href_table != 0xffffffff) - SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI, + SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib, pNameTable); if (pTITail->vars_off != 0xffff) @@ -3175,7 +3187,7 @@ static void SLTG_ProcessModule(char *pBlk, ITypeInfoImpl *pTI, SLTG_TypeInfoTail *pTITail) { if (pTIHeader->href_table != 0xffffffff) - SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI, + SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib, pNameTable); if (pTITail->vars_off != 0xffff) @@ -3553,6 +3565,8 @@ static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface) { TLBImpLib *pImpLib, *pImpLibNext; TLBCustData *pCustData, *pCustDataNext; + TLBRefType *ref_type; + void *cursor2; int i; /* remove cache entry */ @@ -3616,6 +3630,12 @@ static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface) TLB_Free(pImpLib); } + LIST_FOR_EACH_ENTRY_SAFE(ref_type, cursor2, &This->ref_list, TLBRefType, entry) + { + list_remove(&ref_type->entry); + TLB_Free(ref_type); + } + if (This->pTypeInfo) /* can be NULL */ ITypeInfo_Release((ITypeInfo*) This->pTypeInfo); HeapFree(GetProcessHeap(),0,This); @@ -4402,7 +4422,6 @@ static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface) TLBFuncDesc *pFInfo, *pFInfoNext; TLBVarDesc *pVInfo, *pVInfoNext; TLBImplType *pImpl, *pImplNext; - TLBRefType *pRefType,*pRefTypeNext; TLBCustData *pCustData, *pCustDataNext; TRACE("destroying ITypeInfo(%p)\n",This); @@ -4481,11 +4500,6 @@ static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface) pImplNext = pImpl->next; TLB_Free(pImpl); } - for(pRefType = This->reflist; pRefType; pRefType = pRefTypeNext) - { - pRefTypeNext = pRefType->next; - TLB_Free(pRefType); - } TLB_Free(This->pCustData); finish_free: @@ -4690,7 +4704,7 @@ HRESULT ITypeInfoImpl_GetInternalFuncDesc( ITypeInfo *iface, UINT index, const F return S_OK; } - return E_INVALIDARG; + return TYPE_E_ELEMENTNOTFOUND; } /* internal function to make the inherited interfaces' methods appear @@ -4700,22 +4714,17 @@ static HRESULT ITypeInfoImpl_GetInternalDispatchFuncDesc( ITypeInfo *iface, { ITypeInfoImpl *This = (ITypeInfoImpl *)iface; HRESULT hr; - UINT i; UINT implemented_funcs = 0; if (funcs) *funcs = 0; - for (i = 0; i < This->TypeAttr.cImplTypes; i++) + if(This->impltypelist) { - HREFTYPE href; ITypeInfo *pSubTypeInfo; UINT sub_funcs; - hr = ITypeInfo_GetRefTypeOfImplType(iface, i, &href); - if (FAILED(hr)) - return hr; - hr = ITypeInfo_GetRefTypeInfo(iface, href, &pSubTypeInfo); + hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pSubTypeInfo); if (FAILED(hr)) return hr; @@ -4753,8 +4762,7 @@ static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( ITypeInfo2 *iface, UINT index, TRACE("(%p) index %d\n", This, index); - if ((This->TypeAttr.typekind == TKIND_DISPATCH) && - (This->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL)) + if (This->TypeAttr.typekind == TKIND_DISPATCH) hr = ITypeInfoImpl_GetInternalDispatchFuncDesc((ITypeInfo *)iface, index, &internal_funcdesc, NULL); else @@ -4885,7 +4893,7 @@ static HRESULT WINAPI ITypeInfo_fnGetNames( ITypeInfo2 *iface, MEMBERID memid, } else { - if(This->TypeAttr.cImplTypes && + if(This->impltypelist && (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) { /* recursive search */ ITypeInfo *pTInfo; @@ -4950,6 +4958,11 @@ static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType( hr = TYPE_E_ELEMENTNOTFOUND; } } + else if(index == 0 && This->TypeAttr.typekind == TKIND_DISPATCH) + { + /* All TKIND_DISPATCHs are made to look like they inherit from IDispatch */ + *pRefType = This->pTypeLib->dispatch_href; + } else { /* get element n from linked list */ @@ -5043,7 +5056,7 @@ static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( ITypeInfo2 *iface, } } /* not found, see if it can be found in an inherited interface */ - if(This->TypeAttr.cImplTypes) { + if(This->impltypelist) { /* recursive search */ ITypeInfo *pTInfo; ret=ITypeInfo_GetRefTypeInfo(iface, @@ -5814,11 +5827,10 @@ func_fail: /* not found, look for it in inherited interfaces */ ITypeInfo2_GetTypeKind(iface, &type_kind); if(type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) { - HREFTYPE ref_type; - if(SUCCEEDED(ITypeInfo2_GetRefTypeOfImplType(iface, 0, &ref_type))) { + if(This->impltypelist) { /* recursive search */ ITypeInfo *pTInfo; - hres = ITypeInfo_GetRefTypeInfo(iface, ref_type, &pTInfo); + hres = ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, &pTInfo); if(SUCCEEDED(hres)){ hres = ITypeInfo_Invoke(pTInfo,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr); ITypeInfo_Release(pTInfo); @@ -5881,7 +5893,7 @@ static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface, } } - if(This->TypeAttr.cImplTypes && + if(This->impltypelist && (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) { /* recursive search */ ITypeInfo *pTInfo; @@ -5999,51 +6011,55 @@ static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo( result = S_OK; } else { - TLBRefType *pRefType; - for(pRefType = This->reflist; pRefType; pRefType = pRefType->next) { - if(pRefType->reference == hRefType) - break; - } - if(!pRefType) - FIXME("Can't find pRefType for ref %x\n", hRefType); - if(pRefType && hRefType != -1) { + TLBRefType *ref_type; + LIST_FOR_EACH_ENTRY(ref_type, &This->pTypeLib->ref_list, TLBRefType, entry) + { + if(ref_type->reference == hRefType) + break; + } + if(&ref_type->entry == &This->pTypeLib->ref_list) + { + FIXME("Can't find pRefType for ref %x\n", hRefType); + goto end; + } + if(hRefType != -1) { ITypeLib *pTLib = NULL; - if(pRefType->pImpTLInfo == TLB_REF_INTERNAL) { + if(ref_type->pImpTLInfo == TLB_REF_INTERNAL) { UINT Index; result = ITypeInfo_GetContainingTypeLib(iface, &pTLib, &Index); } else { - if(pRefType->pImpTLInfo->pImpTypeLib) { + if(ref_type->pImpTLInfo->pImpTypeLib) { TRACE("typeinfo in imported typelib that is already loaded\n"); - pTLib = (ITypeLib*)pRefType->pImpTLInfo->pImpTypeLib; + pTLib = (ITypeLib*)ref_type->pImpTLInfo->pImpTypeLib; ITypeLib2_AddRef((ITypeLib*) pTLib); result = S_OK; } else { TRACE("typeinfo in imported typelib that isn't already loaded\n"); - result = LoadRegTypeLib( &pRefType->pImpTLInfo->guid, - pRefType->pImpTLInfo->wVersionMajor, - pRefType->pImpTLInfo->wVersionMinor, - pRefType->pImpTLInfo->lcid, + result = LoadRegTypeLib( &ref_type->pImpTLInfo->guid, + ref_type->pImpTLInfo->wVersionMajor, + ref_type->pImpTLInfo->wVersionMinor, + ref_type->pImpTLInfo->lcid, &pTLib); if(!SUCCEEDED(result)) { - BSTR libnam=SysAllocString(pRefType->pImpTLInfo->name); + BSTR libnam=SysAllocString(ref_type->pImpTLInfo->name); result=LoadTypeLib(libnam, &pTLib); SysFreeString(libnam); } if(SUCCEEDED(result)) { - pRefType->pImpTLInfo->pImpTypeLib = (ITypeLibImpl*)pTLib; + ref_type->pImpTLInfo->pImpTypeLib = (ITypeLibImpl*)pTLib; ITypeLib2_AddRef(pTLib); } } } if(SUCCEEDED(result)) { - if(pRefType->index == TLB_REF_USE_GUID) + if(ref_type->index == TLB_REF_USE_GUID) result = ITypeLib2_GetTypeInfoOfGuid(pTLib, - &pRefType->guid, + &ref_type->guid, ppTInfo); else - result = ITypeLib2_GetTypeInfo(pTLib, pRefType->index, + result = ITypeLib2_GetTypeInfo(pTLib, ref_type->index, ppTInfo); } if (pTLib != NULL) @@ -6051,6 +6067,7 @@ static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo( } } +end: TRACE("(%p) hreftype 0x%04x loaded %s (%p)\n", This, hRefType, SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo); return result; @@ -6809,6 +6826,7 @@ HRESULT WINAPI CreateDispTypeInfo( ITypeLibImpl *pTypeLibImpl; int param, func; TLBFuncDesc **ppFuncDesc; + TLBRefType *ref; TRACE("\n"); pTypeLibImpl = TypeLibImpl_Constructor(); @@ -6865,6 +6883,7 @@ HRESULT WINAPI CreateDispTypeInfo( (*ppFuncDesc)->ctCustData = 0; (*ppFuncDesc)->pCustData = NULL; (*ppFuncDesc)->next = NULL; + pTIIface->TypeAttr.cFuncs++; ppFuncDesc = &(*ppFuncDesc)->next; } @@ -6892,12 +6911,13 @@ HRESULT WINAPI CreateDispTypeInfo( pTIClass->TypeAttr.wTypeFlags = 0; pTIClass->impltypelist = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pTIClass->impltypelist)); - pTIClass->impltypelist->hRef = 1; + pTIClass->impltypelist->hRef = 0; - pTIClass->reflist = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pTIClass->reflist)); - pTIClass->reflist->index = 0; - pTIClass->reflist->reference = 1; - pTIClass->reflist->pImpTLInfo = TLB_REF_INTERNAL; + ref = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ref)); + ref->index = 0; + ref->reference = 0; + ref->pImpTLInfo = TLB_REF_INTERNAL; + list_add_head(&pTypeLibImpl->ref_list, &ref->entry); dump_TypeInfo(pTIClass); @@ -6989,7 +7009,7 @@ static HRESULT WINAPI ITypeComp_fnBind( } } /* FIXME: search each inherited interface, not just the first */ - if (hr == DISP_E_MEMBERNOTFOUND && This->TypeAttr.cImplTypes) { + if (hr == DISP_E_MEMBERNOTFOUND && This->impltypelist) { /* recursive search */ ITypeInfo *pTInfo; ITypeComp *pTComp; diff --git a/dlls/oleaut32/ungif.c b/dlls/oleaut32/ungif.c index e80f8ab9ca2..415e7bfe342 100644 --- a/dlls/oleaut32/ungif.c +++ b/dlls/oleaut32/ungif.c @@ -65,6 +65,11 @@ static void *ungif_calloc( size_t num, size_t sz ) return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, num*sz ); } +static void *ungif_realloc( void *ptr, size_t sz ) +{ + return HeapReAlloc( GetProcessHeap(), 0, ptr, sz ); +} + static void ungif_free( void *ptr ) { HeapFree( GetProcessHeap(), 0, ptr ); @@ -194,7 +199,7 @@ AddExtensionBlock(SavedImage * New, if (New->ExtensionBlocks == NULL) New->ExtensionBlocks = ungif_alloc(sizeof(ExtensionBlock)); else - New->ExtensionBlocks = realloc(New->ExtensionBlocks, + New->ExtensionBlocks = ungif_realloc(New->ExtensionBlocks, sizeof(ExtensionBlock) * (New->ExtensionBlockCount + 1)); @@ -387,7 +392,7 @@ DGifGetImageDesc(GifFileType * GifFile) { } if (GifFile->SavedImages) { - if ((GifFile->SavedImages = realloc(GifFile->SavedImages, + if ((GifFile->SavedImages = ungif_realloc(GifFile->SavedImages, sizeof(SavedImage) * (GifFile->ImageCount + 1))) == NULL) { return GIF_ERROR; diff --git a/dlls/qcap/capturegraph.c b/dlls/qcap/capturegraph.c index c947980fd4a..c25dfe38555 100644 --- a/dlls/qcap/capturegraph.c +++ b/dlls/qcap/capturegraph.c @@ -30,7 +30,6 @@ #include "winbase.h" #include "winerror.h" #include "objbase.h" -#include "uuids.h" #include "evcode.h" #include "strmif.h" diff --git a/dlls/qcap/vfwcapture.c b/dlls/qcap/vfwcapture.c index d388c00252d..b461054fcd9 100644 --- a/dlls/qcap/vfwcapture.c +++ b/dlls/qcap/vfwcapture.c @@ -38,7 +38,6 @@ #include "pin.h" #include "capture.h" #include "uuids.h" -#include "mmreg.h" #include "vfwmsgs.h" #include "amvideo.h" #include "strmif.h" diff --git a/dlls/qcap/yuv.c b/dlls/qcap/yuv.c index 36e1855f6f2..26048e197cf 100644 --- a/dlls/qcap/yuv.c +++ b/dlls/qcap/yuv.c @@ -24,7 +24,6 @@ #include #include "windef.h" -#include "winbase.h" #include "objbase.h" #include "strmif.h" #include "qcap_main.h" diff --git a/dlls/quartz/acmwrapper.c b/dlls/quartz/acmwrapper.c index 0258e9cb542..210ea1ee9c6 100644 --- a/dlls/quartz/acmwrapper.c +++ b/dlls/quartz/acmwrapper.c @@ -21,7 +21,6 @@ #include "config.h" #include "quartz_private.h" -#include "control_private.h" #include "pin.h" #include "uuids.h" @@ -31,7 +30,6 @@ #include "dshow.h" #include "strmif.h" #include "vfwmsgs.h" -#include "evcode.h" #include "msacm.h" #include diff --git a/dlls/quartz/avidec.c b/dlls/quartz/avidec.c index 0225d385942..139e44df036 100644 --- a/dlls/quartz/avidec.c +++ b/dlls/quartz/avidec.c @@ -21,12 +21,9 @@ #include "config.h" #include "quartz_private.h" -#include "control_private.h" #include "pin.h" #include "uuids.h" -#include "aviriff.h" -#include "mmreg.h" #include "vfwmsgs.h" #include "amvideo.h" #include "windef.h" @@ -34,7 +31,6 @@ #include "dshow.h" #include "strmif.h" #include "vfwmsgs.h" -#include "evcode.h" #include "vfw.h" #include diff --git a/dlls/quartz/avisplit.c b/dlls/quartz/avisplit.c index f3a6f647484..3121ead38dd 100644 --- a/dlls/quartz/avisplit.c +++ b/dlls/quartz/avisplit.c @@ -29,7 +29,6 @@ #include "uuids.h" #include "aviriff.h" -#include "mmreg.h" #include "vfwmsgs.h" #include "amvideo.h" diff --git a/dlls/quartz/dsoundrender.c b/dlls/quartz/dsoundrender.c index 24920522b36..9e73eeeab51 100644 --- a/dlls/quartz/dsoundrender.c +++ b/dlls/quartz/dsoundrender.c @@ -25,9 +25,7 @@ #include "pin.h" #include "uuids.h" -#include "mmreg.h" #include "vfwmsgs.h" -#include "fourcc.h" #include "windef.h" #include "winbase.h" #include "dshow.h" diff --git a/dlls/quartz/mpegsplit.c b/dlls/quartz/mpegsplit.c index 4057d7d9b4c..205f645a34e 100644 --- a/dlls/quartz/mpegsplit.c +++ b/dlls/quartz/mpegsplit.c @@ -29,7 +29,6 @@ #include "uuids.h" #include "mmreg.h" -#include "vfwmsgs.h" #include "mmsystem.h" #include "winternl.h" diff --git a/dlls/quartz/parser.c b/dlls/quartz/parser.c index 8e85456118e..9bbda092031 100644 --- a/dlls/quartz/parser.c +++ b/dlls/quartz/parser.c @@ -23,14 +23,9 @@ #include "control_private.h" #include "pin.h" -#include "uuids.h" -#include "aviriff.h" -#include "mmreg.h" #include "vfwmsgs.h" #include "amvideo.h" -#include "fourcc.h" - #include "wine/unicode.h" #include "wine/debug.h" diff --git a/dlls/quartz/systemclock.c b/dlls/quartz/systemclock.c index d78611f869c..ff1a28ad822 100644 --- a/dlls/quartz/systemclock.c +++ b/dlls/quartz/systemclock.c @@ -22,7 +22,6 @@ #include "wine/debug.h" #include "wine/unicode.h" -#include "uuids.h" #include WINE_DEFAULT_DEBUG_CHANNEL(quartz); diff --git a/dlls/quartz/transform.c b/dlls/quartz/transform.c index 13bd308f872..9adaf174411 100644 --- a/dlls/quartz/transform.c +++ b/dlls/quartz/transform.c @@ -24,17 +24,11 @@ #include "control_private.h" #include "pin.h" -#include "uuids.h" -#include "aviriff.h" -#include "mmreg.h" -#include "vfwmsgs.h" #include "amvideo.h" #include "windef.h" #include "winbase.h" #include "dshow.h" #include "strmif.h" -#include "vfwmsgs.h" -#include "evcode.h" #include "vfw.h" #include diff --git a/dlls/quartz/videorenderer.c b/dlls/quartz/videorenderer.c index a7df440cff7..b42338c62d0 100644 --- a/dlls/quartz/videorenderer.c +++ b/dlls/quartz/videorenderer.c @@ -27,10 +27,8 @@ #include "pin.h" #include "uuids.h" -#include "mmreg.h" #include "vfwmsgs.h" #include "amvideo.h" -#include "fourcc.h" #include "windef.h" #include "winbase.h" #include "dshow.h" diff --git a/dlls/quartz/waveparser.c b/dlls/quartz/waveparser.c index 3997782cf8b..cbb387e1dbd 100644 --- a/dlls/quartz/waveparser.c +++ b/dlls/quartz/waveparser.c @@ -24,7 +24,6 @@ #include "uuids.h" #include "aviriff.h" -#include "mmreg.h" #include "vfwmsgs.h" #include "mmsystem.h" diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c index 83541f25599..b5a26eb5d88 100644 --- a/dlls/riched20/editor.c +++ b/dlls/riched20/editor.c @@ -226,8 +226,6 @@ #include "winreg.h" #define NO_SHLWAPI_STREAM #include "shlwapi.h" -#include "imm.h" -#include "textserv.h" #include "rtf.h" #define STACK_SIZE_DEFAULT 100 diff --git a/dlls/riched20/txtsrv.c b/dlls/riched20/txtsrv.c index 069c916534e..95d6f7cb496 100644 --- a/dlls/riched20/txtsrv.c +++ b/dlls/riched20/txtsrv.c @@ -28,7 +28,6 @@ #include "editor.h" #include "ole2.h" #include "richole.h" -#include "winreg.h" #include "imm.h" #include "textserv.h" #include "wine/debug.h" diff --git a/dlls/rpcrt4/ndr_clientserver.c b/dlls/rpcrt4/ndr_clientserver.c index 1745b90caa1..fe424a63cc0 100644 --- a/dlls/rpcrt4/ndr_clientserver.c +++ b/dlls/rpcrt4/ndr_clientserver.c @@ -32,7 +32,6 @@ #include "windef.h" #include "winbase.h" #include "winerror.h" -#include "winreg.h" #include "objbase.h" diff --git a/dlls/rpcrt4/ndr_marshall.c b/dlls/rpcrt4/ndr_marshall.c index ad95b53abe2..84d502b3e99 100644 --- a/dlls/rpcrt4/ndr_marshall.c +++ b/dlls/rpcrt4/ndr_marshall.c @@ -39,7 +39,6 @@ #include "windef.h" #include "winbase.h" #include "winerror.h" -#include "winreg.h" #include "ndr_misc.h" #include "rpcndr.h" diff --git a/dlls/rpcrt4/ndr_ole.c b/dlls/rpcrt4/ndr_ole.c index b65e18b0a1b..0a8c1f22797 100644 --- a/dlls/rpcrt4/ndr_ole.c +++ b/dlls/rpcrt4/ndr_ole.c @@ -33,7 +33,6 @@ #include "windef.h" #include "winbase.h" #include "winerror.h" -#include "winreg.h" #include "objbase.h" diff --git a/dlls/rpcrt4/ndr_stubless.c b/dlls/rpcrt4/ndr_stubless.c index dbe500ef7b6..6a581a0adf3 100644 --- a/dlls/rpcrt4/ndr_stubless.c +++ b/dlls/rpcrt4/ndr_stubless.c @@ -33,7 +33,6 @@ #include "windef.h" #include "winbase.h" #include "winerror.h" -#include "winreg.h" #include "objbase.h" #include "rpc.h" diff --git a/dlls/rpcrt4/rpc_binding.c b/dlls/rpcrt4/rpc_binding.c index ad96ac6496e..4f276ae9951 100644 --- a/dlls/rpcrt4/rpc_binding.c +++ b/dlls/rpcrt4/rpc_binding.c @@ -30,7 +30,6 @@ #include "winbase.h" #include "winnls.h" #include "winerror.h" -#include "winreg.h" #include "winternl.h" #include "wine/unicode.h" diff --git a/dlls/rpcrt4/rpc_epmap.c b/dlls/rpcrt4/rpc_epmap.c index 45471c175b7..cac3f626c1a 100644 --- a/dlls/rpcrt4/rpc_epmap.c +++ b/dlls/rpcrt4/rpc_epmap.c @@ -29,7 +29,6 @@ #include "windef.h" #include "winbase.h" #include "winerror.h" -#include "winreg.h" #include "rpc.h" diff --git a/dlls/rpcrt4/rpc_message.c b/dlls/rpcrt4/rpc_message.c index a30c9254af0..dd37f33538d 100644 --- a/dlls/rpcrt4/rpc_message.c +++ b/dlls/rpcrt4/rpc_message.c @@ -27,7 +27,6 @@ #include "windef.h" #include "winbase.h" #include "winerror.h" -#include "winreg.h" #include "rpc.h" #include "rpcndr.h" diff --git a/dlls/rpcrt4/rpc_server.c b/dlls/rpcrt4/rpc_server.c index 71524531d40..fd277b37d54 100644 --- a/dlls/rpcrt4/rpc_server.c +++ b/dlls/rpcrt4/rpc_server.c @@ -33,7 +33,6 @@ #include "windef.h" #include "winbase.h" #include "winerror.h" -#include "winreg.h" #include "rpc.h" #include "rpcndr.h" diff --git a/dlls/rpcrt4/rpc_transport.c b/dlls/rpcrt4/rpc_transport.c index b4af8e95bed..c3d1ef3cf60 100644 --- a/dlls/rpcrt4/rpc_transport.c +++ b/dlls/rpcrt4/rpc_transport.c @@ -60,7 +60,6 @@ #include "winbase.h" #include "winnls.h" #include "winerror.h" -#include "winreg.h" #include "winternl.h" #include "wine/unicode.h" diff --git a/dlls/rsaenh/rsaenh.c b/dlls/rsaenh/rsaenh.c index ca9e4a9f68a..101eb8c8b4a 100644 --- a/dlls/rsaenh/rsaenh.c +++ b/dlls/rsaenh/rsaenh.c @@ -33,7 +33,6 @@ #include "winbase.h" #include "winreg.h" #include "wincrypt.h" -#include "lmcons.h" #include "handle.h" #include "implglue.h" #include "objbase.h" diff --git a/dlls/setupapi/query.c b/dlls/setupapi/query.c index 86992640626..3a747174756 100644 --- a/dlls/setupapi/query.c +++ b/dlls/setupapi/query.c @@ -320,7 +320,7 @@ BOOL WINAPI SetupGetSourceFileLocationA( HINF hinf, PINFCONTEXT context, PCSTR f TRACE("%p, %p, %s, %p, %p, 0x%08x, %p\n", hinf, context, debugstr_a(filename), source_id, buffer, buffer_size, required_size); - if (filename && !(filenameW = strdupAtoW( filename ))) + if (filename && *filename && !(filenameW = strdupAtoW( filename ))) return FALSE; if (!SetupGetSourceFileLocationW( hinf, context, filenameW, source_id, NULL, 0, &required )) diff --git a/dlls/setupapi/queue.c b/dlls/setupapi/queue.c index 063e8c04299..f9647ef81fb 100644 --- a/dlls/setupapi/queue.c +++ b/dlls/setupapi/queue.c @@ -216,6 +216,7 @@ UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification, case SPFILENOTIFY_RENAMEERROR: case SPFILENOTIFY_STARTCOPY: case SPFILENOTIFY_ENDCOPY: + case SPFILENOTIFY_QUEUESCAN_EX: { FILEPATHS_W *pathsW = (FILEPATHS_W *)param1; FILEPATHS_A pathsA; @@ -249,8 +250,18 @@ UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification, } break; - case SPFILENOTIFY_NEEDMEDIA: case SPFILENOTIFY_QUEUESCAN: + { + LPWSTR targetW = (LPWSTR)param1; + LPSTR target = strdupWtoA( targetW ); + + ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification, + (UINT_PTR)target, param2 ); + HeapFree( GetProcessHeap(), 0, target ); + } + break; + + case SPFILENOTIFY_NEEDMEDIA: FIXME("mapping for %d not implemented\n",notification); case SPFILENOTIFY_STARTQUEUE: case SPFILENOTIFY_ENDQUEUE: @@ -1203,22 +1214,70 @@ BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBAC /*********************************************************************** * SetupScanFileQueueA (SETUPAPI.@) */ -BOOL WINAPI SetupScanFileQueueA( HSPFILEQ queue, DWORD flags, HWND window, - PSP_FILE_CALLBACK_A callback, PVOID context, PDWORD result ) +BOOL WINAPI SetupScanFileQueueA( HSPFILEQ handle, DWORD flags, HWND window, + PSP_FILE_CALLBACK_A handler, PVOID context, PDWORD result ) { - FIXME("stub\n"); - return FALSE; + struct callback_WtoA_context ctx; + + TRACE("%p %x %p %p %p %p\n", handle, flags, window, handler, context, result); + + ctx.orig_context = context; + ctx.orig_handler = handler; + + return SetupScanFileQueueW( handle, flags, window, QUEUE_callback_WtoA, &ctx, result ); } /*********************************************************************** * SetupScanFileQueueW (SETUPAPI.@) */ -BOOL WINAPI SetupScanFileQueueW( HSPFILEQ queue, DWORD flags, HWND window, - PSP_FILE_CALLBACK_W callback, PVOID context, PDWORD result ) +BOOL WINAPI SetupScanFileQueueW( HSPFILEQ handle, DWORD flags, HWND window, + PSP_FILE_CALLBACK_W handler, PVOID context, PDWORD result ) { - FIXME("stub\n"); - return FALSE; + struct file_queue *queue = handle; + struct file_op *op; + FILEPATHS_W paths; + UINT notification = 0; + BOOL ret = FALSE; + + TRACE("%p %x %p %p %p %p\n", handle, flags, window, handler, context, result); + + if (!queue->copy_queue.count) return TRUE; + + if (flags & SPQ_SCAN_USE_CALLBACK) notification = SPFILENOTIFY_QUEUESCAN; + else if (flags & SPQ_SCAN_USE_CALLBACKEX) notification = SPFILENOTIFY_QUEUESCAN_EX; + + if (flags & ~(SPQ_SCAN_USE_CALLBACK | SPQ_SCAN_USE_CALLBACKEX)) + { + FIXME("flags %x not fully implemented\n", flags); + } + + paths.Source = paths.Target = NULL; + + for (op = queue->copy_queue.head; op; op = op->next) + { + build_filepathsW( op, &paths ); + switch (notification) + { + case SPFILENOTIFY_QUEUESCAN: + /* FIXME: handle delay flag */ + if (handler( context, notification, (UINT_PTR)paths.Target, 0 )) goto done; + break; + case SPFILENOTIFY_QUEUESCAN_EX: + if (handler( context, notification, (UINT_PTR)&paths, 0 )) goto done; + break; + default: + ret = TRUE; goto done; + } + } + + ret = TRUE; + + done: + if (result) *result = 0; + HeapFree( GetProcessHeap(), 0, (void *)paths.Source ); + HeapFree( GetProcessHeap(), 0, (void *)paths.Target ); + return ret; } @@ -1527,3 +1586,22 @@ UINT WINAPI SetupCopyErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR diskname, w32error, debugstr_w(sourcefile), debugstr_w(sourcepath) ,debugstr_w(targetpath)); return DPROMPT_SKIPFILE; } + +/*********************************************************************** + * pSetupGetQueueFlags (SETUPAPI.@) + */ +DWORD WINAPI pSetupGetQueueFlags( HSPFILEQ handle ) +{ + struct file_queue *queue = handle; + return queue->flags; +} + +/*********************************************************************** + * pSetupSetQueueFlags (SETUPAPI.@) + */ +BOOL WINAPI pSetupSetQueueFlags( HSPFILEQ handle, DWORD flags ) +{ + struct file_queue *queue = handle; + queue->flags = flags; + return TRUE; +} diff --git a/dlls/setupapi/setupapi.spec b/dlls/setupapi/setupapi.spec index 006f1fc501d..d6a6b6e6331 100644 --- a/dlls/setupapi/setupapi.spec +++ b/dlls/setupapi/setupapi.spec @@ -545,13 +545,13 @@ @ stdcall pSetupGetField(ptr long) @ stdcall pSetupGetGlobalFlags() @ stub pSetupGetOsLoaderDriveAndPath -@ stub pSetupGetQueueFlags +@ stdcall pSetupGetQueueFlags(ptr) @ stub pSetupGetVersionDatum @ stub pSetupGuidFromString @ stub pSetupIsGuidNull @ stub pSetupMakeSurePathExists @ stdcall pSetupSetGlobalFlags(long) -@ stub pSetupSetQueueFlags +@ stdcall pSetupSetQueueFlags(ptr long) @ stub pSetupSetSystemSourceFlags @ stub pSetupStringFromGuid @ stdcall pSetupStringTableAddString(ptr wstr long) StringTableAddString diff --git a/dlls/shell32/shlexec.c b/dlls/shell32/shlexec.c index 6e38dbd958b..5b2ee4e8041 100644 --- a/dlls/shell32/shlexec.c +++ b/dlls/shell32/shlexec.c @@ -654,6 +654,8 @@ UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpOperation, &filetypelen) == ERROR_SUCCESS) { filetypelen /= sizeof(WCHAR); + if (filetypelen == sizeof(filetype)/sizeof(WCHAR)) + filetypelen--; filetype[filetypelen] = '\0'; TRACE("File type: %s\n", debugstr_w(filetype)); } diff --git a/dlls/user32/msg16.c b/dlls/user32/msg16.c index 3193a605e08..421f3389b37 100644 --- a/dlls/user32/msg16.c +++ b/dlls/user32/msg16.c @@ -164,7 +164,7 @@ BOOL16 WINAPI PeekMessage32_16( MSG32_16 *msg16, HWND16 hwnd16, HWND hwnd = WIN_Handle32( hwnd16 ); if(USER16_AlertableWait) - MsgWaitForMultipleObjectsEx( 0, NULL, 1, 0, MWMO_ALERTABLE ); + MsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, MWMO_ALERTABLE ); if (!PeekMessageA( &msg, hwnd, first, last, flags )) return FALSE; msg16->msg.time = msg.time; diff --git a/include/Makefile.in b/include/Makefile.in index 7dc0cc39842..ef46edb95e2 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -19,6 +19,7 @@ IDL_H_SRCS = \ hlink.idl \ htiframe.idl \ iads.idl \ + icftypes.idl \ indexsrv.idl \ mediaobj.idl \ mimeinfo.idl \ @@ -28,6 +29,7 @@ IDL_H_SRCS = \ mshtml.idl \ msxml.idl \ msxml2.idl \ + netfw.idl \ oaidl.idl \ objidl.idl \ objsafe.idl \ diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h index 7d53a978405..38b36253dcf 100644 --- a/include/ddk/wdm.h +++ b/include/ddk/wdm.h @@ -865,6 +865,7 @@ PVOID WINAPI ExAllocatePoolWithQuota(POOL_TYPE,SIZE_T); PVOID WINAPI ExAllocatePoolWithTag(POOL_TYPE,SIZE_T,ULONG); PVOID WINAPI ExAllocatePoolWithQuotaTag(POOL_TYPE,SIZE_T,ULONG); void WINAPI ExFreePool(PVOID); +void WINAPI ExFreePoolWithTag(PVOID,ULONG); NTSTATUS WINAPI IoCreateDevice(DRIVER_OBJECT*,ULONG,UNICODE_STRING*,DEVICE_TYPE,ULONG,BOOLEAN,DEVICE_OBJECT**); NTSTATUS WINAPI IoCreateSymbolicLink(UNICODE_STRING*,UNICODE_STRING*); @@ -873,6 +874,12 @@ NTSTATUS WINAPI IoDeleteSymbolicLink(UNICODE_STRING*); PEPROCESS WINAPI IoGetCurrentProcess(void); PKTHREAD WINAPI KeGetCurrentThread(void); +void WINAPI KeQuerySystemTime(LARGE_INTEGER*); +void WINAPI KeQueryTickCount(LARGE_INTEGER*); +ULONG WINAPI KeQueryTimeIncrement(void); + +LPVOID WINAPI MmAllocateNonCachedMemory(SIZE_T); +void WINAPI MmFreeNonCachedMemory(PVOID,SIZE_T); #define PsGetCurrentProcess() IoGetCurrentProcess() #define PsGetCurrentThread() ((PETHREAD)KeGetCurrentThread()) diff --git a/include/icftypes.idl b/include/icftypes.idl new file mode 100644 index 00000000000..9cc0b6ad13b --- /dev/null +++ b/include/icftypes.idl @@ -0,0 +1,69 @@ +/* + * Types for the ICF api + * + * Copyright 2007 Jeff Latimer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should 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 + * + */ + +import "wtypes.idl"; + +typedef enum NET_FW_PROFILE_TYPE_ +{ + NET_FW_PROFILE_DOMAIN, + NET_FW_PROFILE_STANDARD, + NET_FW_PROFILE_CURRENT, + NET_FW_PROFILE_TYPE_MAX +} NET_FW_PROFILE_TYPE; + +typedef enum NET_FW_IP_VERSION_ +{ + NET_FW_IP_VERSION_V4, + NET_FW_IP_VERSION_V6, + NET_FW_IP_VERSION_ANY, + NET_FW_IP_VERSION_MAX +} NET_FW_IP_VERSION; + +typedef enum NET_FW_POLICY_TYPE_ +{ + NET_FW_POLICY_GROUP, + NET_FW_POLICY_LOCAL, + NET_FW_POLICY_EFFECTIVE, + NET_FW_POLICY_TYPE_MAX +} NET_FW_POLICY_TYPE; + +typedef enum NET_FW_SCOPE_ +{ + NET_FW_SCOPE_ALL, + NET_FW_SCOPE_LOCAL_SUBNET, + NET_FW_SCOPE_CUSTOM, + NET_FW_SCOPE_MAX +} NET_FW_SCOPE; + +typedef enum NET_FW_SERVICE_TYPE_ +{ + NET_FW_SERVICE_FILE_AND_PRINT, + NET_FW_SERVICE_UPNP, + NET_FW_SERVICE_REMOTE_DESKTOP, + NET_FW_SERVICE_NONE, + NET_FW_SERVICE_TYPE_MAX +} NET_FW_SERVICE_TYPE; + +typedef enum NET_FW_IP_PROTOCOL_ +{ + NET_FW_IP_PROTOCOL_TCP = 6, + NET_FW_IP_PROTOCOL_UDP = 17 +} NET_FW_IP_PROTOCOL; diff --git a/include/netfw.idl b/include/netfw.idl new file mode 100644 index 00000000000..9158f8d7f41 --- /dev/null +++ b/include/netfw.idl @@ -0,0 +1,470 @@ +/* + * Copyright 2007 Jeff Latimer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should 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 + * + ***************************************************************************** + * + * The firewall management interface + * + */ + +import "icftypes.idl"; +import "oaidl.idl"; + +[ + object, + uuid(A6207B2E-7CDD-426A-951E-5E1CBC5AFEAD), + dual +] +interface INetFwIcmpSettings : IDispatch +{ + [id(1), propget] + HRESULT AllowOutboundDestinationUnreachable([out, retval] VARIANT_BOOL* allow); + + [id(1), propput] + HRESULT AllowOutboundDestinationUnreachable( [in] VARIANT_BOOL allow ); + + [id(2), propget] + HRESULT AllowRedirect( [out, retval] VARIANT_BOOL* allow ); + + [id(2), propput] + HRESULT AllowRedirect( [in] VARIANT_BOOL allow ); + + [id(3), propget] + HRESULT AllowInboundEchoRequest( [out, retval] VARIANT_BOOL* allow ); + + [id(3), propput] + HRESULT AllowInboundEchoRequest( [in] VARIANT_BOOL allow ); + + [id(4), propget] + HRESULT AllowOutboundTimeExceeded( [out, retval] VARIANT_BOOL* allow ); + + [id(4), propput] + HRESULT AllowOutboundTimeExceeded( [in] VARIANT_BOOL allow ); + + [id(5), propget] + HRESULT AllowOutboundParameterProblem( [out, retval] VARIANT_BOOL* allow ); + + [id(5), propput] + HRESULT AllowOutboundParameterProblem( [in] VARIANT_BOOL allow ); + + [id(6), propget] + HRESULT AllowOutboundSourceQuench( [out, retval] VARIANT_BOOL* allow ); + + [id(6), propput] + HRESULT AllowOutboundSourceQuench( [in] VARIANT_BOOL allow ); + + [id(7), propget] + HRESULT AllowInboundRouterRequest( [out, retval] VARIANT_BOOL* allow ); + + [id(7), propput] + HRESULT AllowInboundRouterRequest( [in] VARIANT_BOOL allow ); + + [id(8), propget] + HRESULT AllowInboundTimestampRequest( [out, retval] VARIANT_BOOL* allow ); + + [id(8), propput] + HRESULT AllowInboundTimestampRequest( [in] VARIANT_BOOL allow ); + + [id(9), propget] + HRESULT AllowInboundMaskRequest( [out, retval] VARIANT_BOOL* allow ); + + [id(9), propput] + HRESULT AllowInboundMaskRequest( [in] VARIANT_BOOL allow ); + + [id(10), propget] + HRESULT AllowOutboundPacketTooBig( [out, retval] VARIANT_BOOL* allow ); + + [id(10), propput] + HRESULT AllowOutboundPacketTooBig( [in] VARIANT_BOOL allow ); +} + +[ + object, + uuid(E0483BA0-47FF-4D9C-A6D6-7741D0B195F7), + dual +] +interface INetFwOpenPort : IDispatch +{ + [id(1), propget] + HRESULT Name( [out, retval] BSTR* name ); + + [id(1), propput] + HRESULT Name( [in] BSTR name ); + + [id(2), propget] + HRESULT IpVersion( [out, retval] NET_FW_IP_VERSION* ipVersion ); + + [id(2), propput] + HRESULT IpVersion( [in] NET_FW_IP_VERSION ipVersion ); + + [id(3), propget] + HRESULT Protocol( [out, retval] NET_FW_IP_PROTOCOL* ipProtocol ); + + [id(3), propput] + HRESULT Protocol( [in] NET_FW_IP_PROTOCOL ipProtocol ); + + [id(4), propget] + HRESULT Port( [out, retval] LONG* portNumber ); + + [id(4), propput] + HRESULT Port( [in] LONG portNumber ); + + [id(5), propget] + HRESULT Scope( [out, retval] NET_FW_SCOPE* scope ); + + [id(5), propput] + HRESULT Scope( [in] NET_FW_SCOPE scope ); + + [id(6), propget] + HRESULT RemoteAddresses( [out, retval] BSTR* remoteAddrs ); + + [id(6), propput] + HRESULT RemoteAddresses( [in] BSTR remoteAddrs ); + + [id(7), propget] + HRESULT Enabled( [out, retval] VARIANT_BOOL* enabled ); + + [id(7), propput] + HRESULT Enabled( [in] VARIANT_BOOL enabled ); + + [id(8), propget] + HRESULT BuiltIn( [out, retval] VARIANT_BOOL* builtIn ); +} + +[ + object, + uuid(C0E9D7FA-E07E-430A-B19A-090CE82D92E2), + dual +] +interface INetFwOpenPorts : IDispatch +{ + [id(1), propget] + HRESULT Count( [out, retval] long* count ); + + [id(2)] + HRESULT Add( [in] INetFwOpenPort* port ); + + [id(3)] + HRESULT Remove( [in] LONG portNumber, [in] NET_FW_IP_PROTOCOL ipProtocol ); + + [id(4)] + HRESULT Item( [in] LONG portNumber, [in] NET_FW_IP_PROTOCOL ipProtocol, + [out, retval] INetFwOpenPort** openPort ); + + [id(DISPID_NEWENUM), propget, restricted] + HRESULT _NewEnum( [out, retval] IUnknown** newEnum ); +} + +[ + object, + uuid(79FD57C8-908E-4A36-9888-D5B3F0A444CF), + dual +] +interface INetFwService : IDispatch +{ + [id(1), propget] + HRESULT Name( [out, retval] BSTR* name ); + + [id(2), propget] + HRESULT Type( [out, retval] NET_FW_SERVICE_TYPE* type ); + + [id(3), propget] + HRESULT Customized( [out, retval] VARIANT_BOOL* customized ); + + [id(4), propget] + HRESULT IpVersion( [out, retval] NET_FW_IP_VERSION* ipVersion ); + + [id(4), propput] + HRESULT IpVersion( [in] NET_FW_IP_VERSION ipVersion ); + + [id(5), propget] + HRESULT Scope( [out, retval] NET_FW_SCOPE* scope ); + + [id(5), propput] + HRESULT Scope( [in] NET_FW_SCOPE scope ); + + [id(6), propget] + HRESULT RemoteAddresses( [out, retval] BSTR* remoteAddrs ); + + [id(6), propput] + HRESULT RemoteAddresses( [in] BSTR remoteAddrs ); + + [id(7), propget] + HRESULT Enabled( [out, retval] VARIANT_BOOL* enabled ); + + [id(7), propput] + HRESULT Enabled( [in] VARIANT_BOOL enabled ); + + [id(8), propget] + HRESULT GloballyOpenPorts( [out, retval] INetFwOpenPorts** openPorts ); +} + +[ + object, + uuid(79649BB4-903E-421B-94C9-79848E79F6EE), + dual +] +interface INetFwServices : IDispatch +{ + [id(1), propget] + HRESULT Count( [out, retval] long* count ); + + [id(2)] + HRESULT Item( [in] NET_FW_SERVICE_TYPE svcType, + [out, retval] INetFwService** service ); + + [id(DISPID_NEWENUM), propget, restricted] + HRESULT _NewEnum( [out, retval] IUnknown** newEnum ); +} + +[ + object, + uuid(B5E64FFA-C2C5-444E-A301-FB5E00018050), + dual +] +interface INetFwAuthorizedApplication : IDispatch +{ + [id(1), propget] + HRESULT Name( [out, retval] BSTR* name ); + + [id(1), propput] + HRESULT Name( [in] BSTR name ); + + [id(2), propget] + HRESULT ProcessImageFileName( [out, retval] BSTR* imageFileName ); + + [id(2), propput] + HRESULT ProcessImageFileName( [in] BSTR imageFileName ); + + [id(3), propget] + HRESULT IpVersion( [out, retval] NET_FW_IP_VERSION* ipVersion ); + + [id(3), propput] + HRESULT IpVersion( [in] NET_FW_IP_VERSION ipVersion ); + + [id(4), propget] + HRESULT Scope( [out, retval] NET_FW_SCOPE* scope ); + + [id(4), propput] + HRESULT Scope( [in] NET_FW_SCOPE scope ); + + [id(5), propget] + HRESULT RemoteAddresses( [out, retval] BSTR* remoteAddrs ); + + [id(5), propput] + HRESULT RemoteAddresses( [in] BSTR remoteAddrs ); + + [id(6), propget] + HRESULT Enabled( [out, retval] VARIANT_BOOL* enabled ); + + [id(6), propput] + HRESULT Enabled( [in] VARIANT_BOOL enabled ); +} + +[ + object, + uuid(D4BECDDF-6F73-4A83-B832-9C66874CD20E), + dual +] +interface INetFwRemoteAdminSettings : IDispatch +{ + [id(1), propget] + HRESULT IpVersion( [out, retval] NET_FW_IP_VERSION* ipVersion ); + + [id(1), propput] + HRESULT IpVersion( [in] NET_FW_IP_VERSION ipVersion ); + + [id(2), propget] + HRESULT Scope( [out, retval] NET_FW_SCOPE* scope ); + + [id(2), propput] + HRESULT Scope( [in] NET_FW_SCOPE scope ); + + [id(3), propget] + HRESULT RemoteAddresses( [out, retval] BSTR* remoteAddrs ); + + [id(3), propput] + HRESULT RemoteAddresses( [in] BSTR remoteAddrs ); + + [id(4), propget] + HRESULT Enabled( [out, retval] VARIANT_BOOL* enabled ); + + [id(4), propput] + HRESULT Enabled( [in] VARIANT_BOOL enabled ); +} + + +[ + object, + uuid(644EFD52-CCF9-486C-97A2-39F352570B30), + dual +] +interface INetFwAuthorizedApplications : IDispatch +{ + [id(1), propget] + HRESULT Count( [out, retval] long* count ); + + [id(2)] + HRESULT Add( [in] INetFwAuthorizedApplication* app ); + + [id(3)] + HRESULT Remove( [in] BSTR imageFileName ); + + [id(4)] + HRESULT Item( [in] BSTR imageFileName, + [out, retval] INetFwAuthorizedApplication** app ); + + [id(DISPID_NEWENUM), propget, restricted] + HRESULT _NewEnum( [out, retval] IUnknown** newEnum ); +} + +[ + object, + uuid(174A0DDA-E9F9-449D-993B-21AB667CA456), + dual +] +interface INetFwProfile : IDispatch +{ + [id(1), propget] + HRESULT Type( [out, retval] NET_FW_PROFILE_TYPE* type ); + + [id(2), propget] + HRESULT FirewallEnabled( [out, retval] VARIANT_BOOL* enabled ); + + [id(2), propput] + HRESULT FirewallEnabled( [in] VARIANT_BOOL enabled ); + + [id(3), propget] + HRESULT ExceptionsNotAllowed( [out, retval] VARIANT_BOOL* notAllowed ); + + [id(3), propput] + HRESULT ExceptionsNotAllowed( [in] VARIANT_BOOL notAllowed ); + + [id(4), propget] + HRESULT NotificationsDisabled( [out, retval] VARIANT_BOOL* disabled ); + + [id(4), propput] + HRESULT NotificationsDisabled( [in] VARIANT_BOOL disabled ); + + [id(5), propget] + HRESULT UnicastResponsesToMulticastBroadcastDisabled( [out, retval] VARIANT_BOOL* disabled ); + + [id(5), propput] + HRESULT UnicastResponsesToMulticastBroadcastDisabled( [in] VARIANT_BOOL disabled ); + + [id(6), propget] + HRESULT RemoteAdminSettings( [out, retval] INetFwRemoteAdminSettings** remoteAdminSettings ); + + [id(7), propget] + HRESULT IcmpSettings( [out, retval] INetFwIcmpSettings** icmpSettings ); + + [id(8), propget] + HRESULT GloballyOpenPorts( [out, retval] INetFwOpenPorts** openPorts ); + + [id(9), propget] + HRESULT Services( [out, retval] INetFwServices** services ); + + [id(10), propget] + HRESULT AuthorizedApplications( [out, retval] INetFwAuthorizedApplications** apps ); +} + +[ + object, + uuid(D46D2478-9AC9-4008-9DC7-5563CE5536CC), + dual +] +interface INetFwPolicy : IDispatch +{ + [id(1), propget] + HRESULT CurrentProfile( [out, retval] INetFwProfile** profile ); + + [id(2)] + HRESULT GetProfileByType( [in] NET_FW_PROFILE_TYPE profileType, + [out, retval] INetFwProfile** profile ); +} + +[ + object, + uuid(F7898AF5-CAC4-4632-A2EC-DA06E5111AF2), + dual +] +interface INetFwMgr : IDispatch +{ + [id(1), propget] + HRESULT LocalPolicy( [out, retval] INetFwPolicy** localPolicy ); + + [id(2), propget] + HRESULT CurrentProfileType( [out, retval] NET_FW_PROFILE_TYPE* profileType ); + + [id(3)] + HRESULT RestoreDefaults(); + + [id(4)] + HRESULT IsPortAllowed( [in] BSTR imageFileName, [in] NET_FW_IP_VERSION ipVersion, + [in] LONG portNumber, [in] BSTR localAddress, + [in] NET_FW_IP_PROTOCOL ipProtocol, [out] VARIANT* allowed, + [out] VARIANT* restricted ); + + [id(5)] + HRESULT IsIcmpTypeAllowed( [in] NET_FW_IP_VERSION ipVersion, [in] BSTR localAddress, + [in] BYTE type, [out] VARIANT* allowed, + [out] VARIANT* restricted ); +} + +[ + uuid(DB4F3345-3EF8-45ED-B976-25A6D3B81B71), + version(1.0) +] +library NetFwPublicTypeLib +{ + importlib("stdole2.tlb"); + interface INetFwRemoteAdminSettings; + interface INetFwIcmpSettings; + interface INetFwOpenPort; + interface INetFwOpenPorts; + interface INetFwService; + interface INetFwServices; + interface INetFwAuthorizedApplication; + interface INetFwAuthorizedApplications; + interface INetFwProfile; + interface INetFwPolicy; + interface INetFwMgr; + + [ + uuid(0CA545C6-37AD-4A6C-BF92-9F7610067EF5) + ] + coclass NetFwOpenPort + { + [default] interface INetFwOpenPort; + } + + [ + uuid(EC9846B3-2762-4A6B-A214-6ACB603462D2) + ] + coclass NetFwAuthorizedApplication + { + [default] interface INetFwAuthorizedApplication; + } + + [ + uuid(304CE942-6E39-40D8-943A-B913C40C9CD4) + ] + coclass NetFwMgr + { + [default] interface INetFwMgr; + } +} diff --git a/include/setupapi.h b/include/setupapi.h index 475ad7581a5..243463927c7 100644 --- a/include/setupapi.h +++ b/include/setupapi.h @@ -437,6 +437,13 @@ DECL_WINELIB_SETUPAPI_TYPE_AW(PSP_ORIGINAL_FILE_INFO) #define SPOST_URL 2 #define SPOST_MAX 3 +#define SPQ_SCAN_FILE_PRESENCE 0x00000001 +#define SPQ_SCAN_FILE_VALIDITY 0x00000002 +#define SPQ_SCAN_USE_CALLBACK 0x00000004 +#define SPQ_SCAN_USE_CALLBACKEX 0x00000008 +#define SPQ_SCAN_INFORM_USER 0x00000010 +#define SPQ_SCAN_PRUNE_COPY_QUEUE 0x00000020 + #define FLG_ADDREG_DELREG_BIT 0x00008000 #define FLG_ADDREG_BINVALUETYPE 0x00000001 #define FLG_ADDREG_NOCLOBBER 0x00000002 diff --git a/include/winternl.h b/include/winternl.h index fa3696f5988..8b650a9972b 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -1731,9 +1731,10 @@ NTSTATUS WINAPIV DbgPrint(LPCSTR fmt, ...); NTSTATUS WINAPIV DbgPrintEx(ULONG iComponentId, ULONG Level, LPCSTR fmt, ...); NTSTATUS WINAPI LdrAccessResource(HMODULE,const IMAGE_RESOURCE_DATA_ENTRY*,void**,PULONG); +NTSTATUS WINAPI LdrAddRefDll(ULONG,HMODULE); NTSTATUS WINAPI LdrFindResourceDirectory_U(HMODULE,const LDR_RESOURCE_INFO*,ULONG,const IMAGE_RESOURCE_DIRECTORY**); NTSTATUS WINAPI LdrFindResource_U(HMODULE,const LDR_RESOURCE_INFO*,ULONG,const IMAGE_RESOURCE_DATA_ENTRY**); -NTSTATUS WINAPI LdrGetDllHandle(ULONG, ULONG, const UNICODE_STRING*, HMODULE*); +NTSTATUS WINAPI LdrGetDllHandle(LPCWSTR, ULONG, const UNICODE_STRING*, HMODULE*); NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE, const ANSI_STRING*, ULONG, void**); void WINAPI LdrInitializeThunk(ULONG,ULONG,ULONG,ULONG); NTSTATUS WINAPI LdrLoadDll(LPCWSTR, DWORD, const UNICODE_STRING*, HMODULE*); diff --git a/programs/Makefile.in b/programs/Makefile.in index e5f0d2e617f..aae377ed5de 100644 --- a/programs/Makefile.in +++ b/programs/Makefile.in @@ -35,6 +35,7 @@ SUBDIRS = \ winecfg \ wineconsole \ winedbg \ + winedevice \ winefile \ winemenubuilder \ winemine \ @@ -75,6 +76,7 @@ INSTALLSUBDIRS = \ winecfg \ wineconsole \ winedbg \ + winedevice \ winefile \ winemenubuilder \ winemine \ diff --git a/programs/winedevice/Makefile.in b/programs/winedevice/Makefile.in new file mode 100644 index 00000000000..7effe56c639 --- /dev/null +++ b/programs/winedevice/Makefile.in @@ -0,0 +1,14 @@ +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +MODULE = winedevice.exe +APPMODE = -mwindows -municode +IMPORTS = advapi32 ntoskrnl.exe kernel32 ntdll + +C_SRCS = \ + device.c + +@MAKE_PROG_RULES@ + +@DEPENDENCIES@ # everything below this line is overwritten by make depend diff --git a/programs/winedevice/device.c b/programs/winedevice/device.c new file mode 100644 index 00000000000..226ba6b791b --- /dev/null +++ b/programs/winedevice/device.c @@ -0,0 +1,237 @@ +/* + * Service process to load a kernel driver + * + * Copyright 2007 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winternl.h" +#include "winreg.h" +#include "winnls.h" +#include "winsvc.h" +#include "ddk/wdm.h" +#include "wine/unicode.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winedevice); +WINE_DECLARE_DEBUG_CHANNEL(relay); + +extern NTSTATUS wine_ntoskrnl_main_loop( HANDLE stop_event ); + +static WCHAR *driver_name; +static SERVICE_STATUS_HANDLE service_handle; +static HKEY driver_hkey; +static HANDLE stop_event; +static DRIVER_OBJECT driver_obj; +static DRIVER_EXTENSION driver_extension; + +/* find the LDR_MODULE corresponding to the driver module */ +static LDR_MODULE *find_ldr_module( HMODULE module ) +{ + LIST_ENTRY *entry, *list = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList; + + for (entry = list->Flink; entry != list; entry = entry->Flink) + { + LDR_MODULE *ldr = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList); + if (ldr->BaseAddress == module) return ldr; + if (ldr->BaseAddress > (void *)module) break; + } + return NULL; +} + +/* call the driver init entry point */ +static NTSTATUS init_driver( HMODULE module, UNICODE_STRING *keyname ) +{ + unsigned int i; + NTSTATUS status; + const IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module ); + + if (!nt->OptionalHeader.AddressOfEntryPoint) return STATUS_SUCCESS; + + driver_obj.Size = sizeof(driver_obj); + driver_obj.DriverSection = find_ldr_module( module ); + driver_obj.DriverInit = (PDRIVER_INITIALIZE)((char *)module + nt->OptionalHeader.AddressOfEntryPoint); + driver_obj.DriverExtension = &driver_extension; + + driver_extension.DriverObject = &driver_obj; + driver_extension.ServiceKeyName = *keyname; + + if (WINE_TRACE_ON(relay)) + WINE_DPRINTF( "%04x:Call driver init %p (obj=%p,str=%s)\n", GetCurrentThreadId(), + driver_obj.DriverInit, &driver_obj, wine_dbgstr_w(keyname->Buffer) ); + + status = driver_obj.DriverInit( &driver_obj, keyname ); + + if (WINE_TRACE_ON(relay)) + WINE_DPRINTF( "%04x:Ret driver init %p (obj=%p,str=%s) retval=%08x\n", GetCurrentThreadId(), + driver_obj.DriverInit, &driver_obj, wine_dbgstr_w(keyname->Buffer), status ); + + WINE_TRACE( "init done for %s obj %p\n", wine_dbgstr_w(driver_name), &driver_obj ); + WINE_TRACE( "- DriverInit = %p\n", driver_obj.DriverInit ); + WINE_TRACE( "- DriverStartIo = %p\n", driver_obj.DriverStartIo ); + WINE_TRACE( "- DriverUnload = %p\n", driver_obj.DriverUnload ); + for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) + WINE_TRACE( "- MajorFunction[%d] = %p\n", i, driver_obj.MajorFunction[i] ); + + return status; +} + +/* load the .sys module for a device driver */ +static BOOL load_driver(void) +{ + static const WCHAR ntprefixW[] = {'\\','?','?','\\',0}; + static const WCHAR ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0}; + static const WCHAR servicesW[] = {'\\','R','e','g','i','s','t','r','y', + '\\','M','a','c','h','i','n','e', + '\\','S','y','s','t','e','m', + '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t', + '\\','S','e','r','v','i','c','e','s','\\',0}; + + UNICODE_STRING keypath; + HMODULE module; + LPWSTR path = NULL, str; + DWORD type, size; + + str = HeapAlloc( GetProcessHeap(), 0, sizeof(servicesW) + strlenW(driver_name)*sizeof(WCHAR) ); + lstrcpyW( str, servicesW ); + lstrcatW( str, driver_name ); + + if (RegOpenKeyW( HKEY_LOCAL_MACHINE, str + 18 /* skip \registry\machine */, &driver_hkey )) + { + WINE_ERR( "cannot open key %s, err=%u\n", wine_dbgstr_w(str), GetLastError() ); + return FALSE; + } + RtlInitUnicodeString( &keypath, str ); + + /* read the executable path from memory */ + size = 0; + if (RegQueryValueExW( driver_hkey, ImagePathW, NULL, &type, NULL, &size )) return FALSE; + + str = HeapAlloc( GetProcessHeap(), 0, size ); + if (!RegQueryValueExW( driver_hkey, ImagePathW, NULL, &type, (LPBYTE)str, &size )) + { + size = ExpandEnvironmentStringsW(str,NULL,0); + path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR)); + ExpandEnvironmentStringsW(str,path,size); + } + HeapFree( GetProcessHeap(), 0, str ); + if (!path) return FALSE; + + /* make sure msvcrt is loaded to resolve the ntoskrnl.exe forwards */ + LoadLibraryA( "msvcrt.dll" ); + + /* GameGuard uses an NT-style path name */ + str = path; + if (!strncmpW( path, ntprefixW, 4 )) str += 4; + + WINE_TRACE( "loading driver %s\n", wine_dbgstr_w(str) ); + + module = LoadLibraryW( str ); + HeapFree( GetProcessHeap(), 0, path ); + if (!module) return FALSE; + + init_driver( module, &keypath ); + return TRUE; +} + +static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_data, LPVOID context ) +{ + SERVICE_STATUS status; + + status.dwServiceType = SERVICE_WIN32; + status.dwControlsAccepted = SERVICE_ACCEPT_STOP; + status.dwWin32ExitCode = 0; + status.dwServiceSpecificExitCode = 0; + status.dwCheckPoint = 0; + status.dwWaitHint = 0; + + switch(ctrl) + { + case SERVICE_CONTROL_STOP: + case SERVICE_CONTROL_SHUTDOWN: + WINE_TRACE( "shutting down %s\n", wine_dbgstr_w(driver_name) ); + status.dwCurrentState = SERVICE_STOP_PENDING; + status.dwControlsAccepted = 0; + SetServiceStatus( service_handle, &status ); + SetEvent( stop_event ); + return NO_ERROR; + default: + WINE_FIXME( "got service ctrl %x for %s\n", ctrl, wine_dbgstr_w(driver_name) ); + status.dwCurrentState = SERVICE_RUNNING; + SetServiceStatus( service_handle, &status ); + return NO_ERROR; + } +} + +static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv ) +{ + SERVICE_STATUS status; + + WINE_TRACE( "starting service %s\n", wine_dbgstr_w(driver_name) ); + + stop_event = CreateEventW( NULL, TRUE, FALSE, NULL ); + + service_handle = RegisterServiceCtrlHandlerExW( driver_name, service_handler, NULL ); + + status.dwServiceType = SERVICE_WIN32; + status.dwCurrentState = SERVICE_START_PENDING; + status.dwControlsAccepted = 0; + status.dwWin32ExitCode = 0; + status.dwServiceSpecificExitCode = 0; + status.dwCheckPoint = 0; + status.dwWaitHint = 10000; + SetServiceStatus( service_handle, &status ); + + if (load_driver()) + { + status.dwCurrentState = SERVICE_RUNNING; + status.dwControlsAccepted = SERVICE_ACCEPT_STOP; + SetServiceStatus( service_handle, &status ); + + wine_ntoskrnl_main_loop( stop_event ); + } + else WINE_ERR( "driver %s failed to load\n", wine_dbgstr_w(driver_name) ); + + status.dwCurrentState = SERVICE_STOPPED; + status.dwControlsAccepted = 0; + SetServiceStatus( service_handle, &status ); + WINE_TRACE( "service %s stopped\n", wine_dbgstr_w(driver_name) ); +} + +int wmain( int argc, WCHAR *argv[] ) +{ + SERVICE_TABLE_ENTRYW service_table[2]; + + if (!(driver_name = argv[1])) + { + WINE_ERR( "missing device name, winedevice isn't supposed to be run manually\n" ); + return 1; + } + + service_table[0].lpServiceName = argv[1]; + service_table[0].lpServiceProc = ServiceMain; + service_table[1].lpServiceName = NULL; + service_table[1].lpServiceProc = NULL; + + StartServiceCtrlDispatcherW( service_table ); + return 0; +} diff --git a/server/token.c b/server/token.c index 8bbe29e6bab..9472cf52018 100644 --- a/server/token.c +++ b/server/token.c @@ -575,8 +575,11 @@ struct token *token_create_admin( void ) static const SID_IDENTIFIER_AUTHORITY nt_authority = { SECURITY_NT_AUTHORITY }; static const unsigned int alias_admins_subauth[] = { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS }; static const unsigned int alias_users_subauth[] = { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS }; + /* on Windows, this value changes every time the user logs on */ + static const unsigned int logon_subauth[] = { SECURITY_LOGON_IDS_RID, 0, 1 /* FIXME: should be randomly generated when tokens are inherited by new processes */ }; PSID alias_admins_sid; PSID alias_users_sid; + PSID logon_sid; /* note: should be the owner specified in the token */ ACL *default_dacl = create_default_dacl( &interactive_sid ); @@ -584,8 +587,10 @@ struct token *token_create_admin( void ) alias_admins_subauth ); alias_users_sid = security_sid_alloc( &nt_authority, sizeof(alias_users_subauth)/sizeof(alias_users_subauth[0]), alias_users_subauth ); + logon_sid = security_sid_alloc( &nt_authority, sizeof(logon_subauth)/sizeof(logon_subauth[0]), + logon_subauth ); - if (alias_admins_sid && alias_users_sid && default_dacl) + if (alias_admins_sid && alias_users_sid && logon_sid && default_dacl) { const LUID_AND_ATTRIBUTES admin_privs[] = { @@ -620,6 +625,7 @@ struct token *token_create_admin( void ) { security_authenticated_user_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY }, { alias_admins_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY|SE_GROUP_OWNER }, { alias_users_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY }, + { logon_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY|SE_GROUP_LOGON_ID }, }; static const TOKEN_SOURCE admin_source = {"SeMgr", {0, 0}}; /* note: we just set the user sid to be the interactive builtin sid - @@ -632,6 +638,7 @@ struct token *token_create_admin( void ) assert( token->primary_group ); } + free( logon_sid ); free( alias_admins_sid ); free( alias_users_sid ); free( default_dacl ); -- 2.11.4.GIT