Implementation PersistentZoneIdentifer object without any writing and reading zone information. OS Windows uses NTFS alternative data stream Zone.Identifer to write and read zone information. Also due to lack of reading zone information some test cases fails.
From: Mike Kozelkov augenzi@etersoft.ru
--- dlls/urlmon/Makefile.in | 3 +- dlls/urlmon/urlmon_main.c | 3 + dlls/urlmon/urlmon_main.h | 1 + dlls/urlmon/urlmon_urlmon.idl | 7 + dlls/urlmon/zone_id.c | 271 ++++++++++++++++++++++++++++++++++ include/urlmon.idl | 18 +++ 6 files changed, 302 insertions(+), 1 deletion(-) create mode 100644 dlls/urlmon/zone_id.c
diff --git a/dlls/urlmon/Makefile.in b/dlls/urlmon/Makefile.in index ba6f1db87ad..1a2f73d4c36 100644 --- a/dlls/urlmon/Makefile.in +++ b/dlls/urlmon/Makefile.in @@ -26,7 +26,8 @@ SOURCES = \ urlmon.rc \ urlmon_main.c \ urlmon_urlmon.idl \ - usrmarshal.c + usrmarshal.c \ + zone_id.c
dlldata_EXTRADEFS = -DENTRY_PREFIX=URLMON_ -DPROXY_DELEGATION -DWINE_REGISTER_DLL \ -DPROXY_CLSID_IS="{0x79EAC9F1,0xBAF9,0x11CE,{0x8C,0x82,0x00,0xAA,0x00,0x4B,0xA9,0x0B}}" diff --git a/dlls/urlmon/urlmon_main.c b/dlls/urlmon/urlmon_main.c index c5a8fdcffa2..806a893d7d1 100644 --- a/dlls/urlmon/urlmon_main.c +++ b/dlls/urlmon/urlmon_main.c @@ -351,6 +351,8 @@ static const IClassFactoryVtbl ClassFactoryVtbl = CF_LockServer };
+static ClassFactory PersistentZoneIdentifierCF = + { { &ClassFactoryVtbl }, PersistentZoneIdentifier_Construct}; static ClassFactory FileProtocolCF = { { &ClassFactoryVtbl }, FileProtocol_Construct}; static ClassFactory FtpProtocolCF = @@ -383,6 +385,7 @@ struct object_creation_info
static const struct object_creation_info object_creation[] = { + { &CLSID_PersistentZoneIdentifier, &PersistentZoneIdentifierCF.IClassFactory_iface, NULL }, { &CLSID_FileProtocol, &FileProtocolCF.IClassFactory_iface, L"file" }, { &CLSID_FtpProtocol, &FtpProtocolCF.IClassFactory_iface, L"ftp" }, { &CLSID_GopherProtocol, &GopherProtocolCF.IClassFactory_iface, L"gopher" }, diff --git a/dlls/urlmon/urlmon_main.h b/dlls/urlmon/urlmon_main.h index 81b0d629f53..ceb3e09b761 100644 --- a/dlls/urlmon/urlmon_main.h +++ b/dlls/urlmon/urlmon_main.h @@ -34,6 +34,7 @@ #include "wine/list.h"
extern HINSTANCE hProxyDll; +extern HRESULT PersistentZoneIdentifier_Construct(IUnknown *pUnkOuter, LPVOID *ppobj); extern HRESULT SecManagerImpl_Construct(IUnknown *pUnkOuter, LPVOID *ppobj); extern HRESULT ZoneMgrImpl_Construct(IUnknown *pUnkOuter, LPVOID *ppobj); extern HRESULT StdURLMoniker_Construct(IUnknown *pUnkOuter, LPVOID *ppobj); diff --git a/dlls/urlmon/urlmon_urlmon.idl b/dlls/urlmon/urlmon_urlmon.idl index c25bd8f34ae..d557708c6ca 100644 --- a/dlls/urlmon/urlmon_urlmon.idl +++ b/dlls/urlmon/urlmon_urlmon.idl @@ -111,3 +111,10 @@ coclass DeCompMimeFilter { interface IInternetProtocol; interface IInternetProto uuid(df2fce13-25ec-45bb-9d4c-cecd47c2430c) ] coclass CUri { interface IUri; } + +[ + helpstring("Persistent Zone Identifier"), + threading(both), + uuid(0968e258-16c7-4dba-aa86-462dd61e31a3) +] +coclass PersistentZoneIdentifier { interface IPersistFile; interface IZoneIdentifier; } diff --git a/dlls/urlmon/zone_id.c b/dlls/urlmon/zone_id.c new file mode 100644 index 00000000000..2d289e3dc3a --- /dev/null +++ b/dlls/urlmon/zone_id.c @@ -0,0 +1,271 @@ +#include "urlmon_main.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(urlmon); + +typedef struct { + IUnknown IUnknown_inner; + IPersistFile IPersistFile_iface; + IZoneIdentifier IZoneIdentifier_iface; + + IUnknown *outer; + + LONG ref; +} PersistentZoneIdentifier; + +static inline PersistentZoneIdentifier *impl_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, PersistentZoneIdentifier, IUnknown_inner); +} + +static inline PersistentZoneIdentifier *impl_from_IPersistFile(IPersistFile *iface) +{ + return CONTAINING_RECORD(iface, PersistentZoneIdentifier, IPersistFile_iface); +} + +static inline PersistentZoneIdentifier *impl_from_IZoneIdentifier(IZoneIdentifier *iface) +{ + return CONTAINING_RECORD(iface, PersistentZoneIdentifier, IZoneIdentifier_iface); +} + +static HRESULT WINAPI PZIUnk_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) +{ + PersistentZoneIdentifier *This = impl_from_IUnknown(iface); + + *ppv = NULL; + + if (IsEqualGUID(&IID_IUnknown, riid)) + { + TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); + *ppv = &This->IUnknown_inner; + } else if (IsEqualGUID(&IID_IPersist, riid)) + { + TRACE("(%p)->(IID_IPersist %p)\n", This, ppv); + *ppv = &This->IPersistFile_iface; + } else if (IsEqualGUID(&IID_IPersistFile, riid)) + { + TRACE("(%p)->(IID_IPersistFile %p)\n", This, ppv); + *ppv = &This->IPersistFile_iface; + } else if (IsEqualGUID(&IID_IZoneIdentifier, riid)) + { + TRACE("(%p)->(IID_IZoneIdentifier %p)\n", This, ppv); + *ppv = &This->IZoneIdentifier_iface; + } + + if (*ppv) + { + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; + } + + WARN("not supported interface %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI PZIUnk_AddRef(IUnknown *iface) +{ + PersistentZoneIdentifier *This = impl_from_IUnknown(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + return ref; +} + +static ULONG WINAPI PZIUnk_Release(IUnknown *iface) +{ + PersistentZoneIdentifier *This = impl_from_IUnknown(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + if (!ref) { URLMON_UnlockModule(); } + + return ref; +} + +static const IUnknownVtbl PZIUnkVtbl = { + PZIUnk_QueryInterface, + PZIUnk_AddRef, + PZIUnk_Release +}; + +static HRESULT WINAPI PZIPersistFile_QueryInterface(IPersistFile *iface, REFIID riid, void **ppv) +{ + PersistentZoneIdentifier *This = impl_from_IPersistFile(iface); + + TRACE("(%p, %s %p)\n", This, debugstr_guid(riid), ppv); + + return IUnknown_QueryInterface(This->outer, riid, ppv); +} + +static ULONG WINAPI PZIPersistFile_AddRef(IPersistFile *iface) +{ + PersistentZoneIdentifier *This = impl_from_IPersistFile(iface); + + TRACE("(%p)\n", This); + + return IUnknown_AddRef(This->outer); +} + +static ULONG WINAPI PZIPersistFile_Release(IPersistFile *iface) +{ + PersistentZoneIdentifier *This = impl_from_IPersistFile(iface); + + TRACE("(%p)\n", This); + + return IUnknown_Release(This->outer); +} + +static HRESULT WINAPI PZIPersistFile_GetClassID(IPersistFile *iface, CLSID *clsid) +{ + PersistentZoneIdentifier *This = impl_from_IPersistFile(iface); + + FIXME("(%p, %p) not implemented\n", This, clsid); + + return E_NOTIMPL; +} + +static HRESULT WINAPI PZIPersistFile_GetCurFile(IPersistFile *iface, LPOLESTR *file_name) +{ + PersistentZoneIdentifier *This = impl_from_IPersistFile(iface); + + FIXME("(%p, %p) not implemented\n", This, file_name); + + return E_NOTIMPL; +} + +static HRESULT WINAPI PZIPersistFile_IsDirty(IPersistFile *iface) +{ + PersistentZoneIdentifier *This = impl_from_IPersistFile(iface); + + FIXME("(%p) not implemented\n", This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI PZIPersistFile_Load(IPersistFile *iface, LPCOLESTR file_name, DWORD mode) +{ + PersistentZoneIdentifier *This = impl_from_IPersistFile(iface); + + FIXME("(%p, %s, 0x%08lx) not implemented\n", This, debugstr_w(file_name), mode); + + return E_NOTIMPL; +} + +static HRESULT WINAPI PZIPersistFile_Save(IPersistFile *iface, LPCOLESTR file_name, BOOL remember) +{ + PersistentZoneIdentifier *This = impl_from_IPersistFile(iface); + + FIXME("(%p, %s, %d) not implemented\n", This, debugstr_w(file_name), remember); + + return E_NOTIMPL; +} + +static HRESULT WINAPI PZIPersistFile_SaveCompleted(IPersistFile* iface, LPCOLESTR pszFileName) +{ + PersistentZoneIdentifier *This = impl_from_IPersistFile(iface); + + FIXME("(%p, %p) not implemented\n", This, pszFileName); + + return E_NOTIMPL; +} + +static const IPersistFileVtbl PZIPersistFileVtbl = { + PZIPersistFile_QueryInterface, + PZIPersistFile_AddRef, + PZIPersistFile_Release, + PZIPersistFile_GetClassID, + PZIPersistFile_IsDirty, + PZIPersistFile_Load, + PZIPersistFile_Save, + PZIPersistFile_SaveCompleted, + PZIPersistFile_GetCurFile +}; + +static HRESULT WINAPI PZIZoneId_QueryInterface(IZoneIdentifier *iface, REFIID riid, void **ppv) +{ + PersistentZoneIdentifier *This = impl_from_IZoneIdentifier(iface); + + TRACE("(%p, %s %p)\n", This, debugstr_guid(riid), ppv); + + return IUnknown_QueryInterface(This->outer, riid, ppv); +} + +static ULONG WINAPI PZIZoneId_AddRef(IZoneIdentifier *iface) +{ + PersistentZoneIdentifier *This = impl_from_IZoneIdentifier(iface); + + TRACE("(%p)\n", This); + + return IUnknown_AddRef(This->outer); +} + +static ULONG WINAPI PZIZoneId_Release(IZoneIdentifier *iface) +{ + PersistentZoneIdentifier *This = impl_from_IZoneIdentifier(iface); + + TRACE("(%p)\n", This); + + return IUnknown_Release(This->outer); +} + +static HRESULT WINAPI PZIZoneId_GetId(IZoneIdentifier* iface, DWORD* pdwZone) +{ + PersistentZoneIdentifier *This = impl_from_IZoneIdentifier(iface); + + FIXME("(%p, %p) not implemented\n", This, pdwZone); + + return E_NOTIMPL; +} + +static HRESULT WINAPI PZIZoneId_Remove(IZoneIdentifier* iface) +{ + PersistentZoneIdentifier *This = impl_from_IZoneIdentifier(iface); + + FIXME("(%p) not implemented\n", This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI PZIZoneId_SetId(IZoneIdentifier* iface, DWORD dwZone) +{ + PersistentZoneIdentifier *This = impl_from_IZoneIdentifier(iface); + + FIXME("(%p, 0x%08lx) not implemented\n", This, dwZone); + + return E_NOTIMPL; +} + +static const IZoneIdentifierVtbl PZIZoneIdVtbl = { + PZIZoneId_QueryInterface, + PZIZoneId_AddRef, + PZIZoneId_Release, + PZIZoneId_GetId, + PZIZoneId_SetId, + PZIZoneId_Remove +}; + +HRESULT PersistentZoneIdentifier_Construct(IUnknown *outer, LPVOID *ppobj) +{ + + PersistentZoneIdentifier *ret; + + TRACE("(%p %p)\n", outer, ppobj); + + URLMON_LockModule(); + + ret = malloc(sizeof(PersistentZoneIdentifier)); + + ret->IUnknown_inner.lpVtbl = &PZIUnkVtbl; + ret->IPersistFile_iface.lpVtbl = &PZIPersistFileVtbl; + ret->IZoneIdentifier_iface.lpVtbl = &PZIZoneIdVtbl; + + ret->ref = 1; + ret->outer = outer ? outer : &ret->IUnknown_inner; + + *ppobj = &ret->IUnknown_inner; + + return S_OK; +} diff --git a/include/urlmon.idl b/include/urlmon.idl index 0aab6588658..04b6462d03a 100644 --- a/include/urlmon.idl +++ b/include/urlmon.idl @@ -1299,6 +1299,23 @@ interface IInternetHostSecurityManager : IUnknown [in] DWORD dwReserved); }
+/***************************************************************************** + * IZoneIdentifier interface + */ +[ + object, + uuid(cd45f185-1b21-48e2-967b-ead743a8914e), + pointer_default(unique) +] +interface IZoneIdentifier : IUnknown +{ + HRESULT GetId( + [out] DWORD *pdwZone); + HRESULT SetId( + [in] DWORD dwZone); + HRESULT Remove(); +}; + cpp_quote("#define URLACTION_MIN 0x00001000") cpp_quote("#define URLACTION_DOWNLOAD_MIN 0x00001000") cpp_quote("#define URLACTION_DOWNLOAD_SIGNED_ACTIVEX 0x00001001") @@ -2148,6 +2165,7 @@ cpp_quote("#define UAS_EXACTLEGACY 0x1000")
cpp_quote("EXTERN_C const GUID GUID_CUSTOM_CONFIRMOBJECTSAFETY;")
+cpp_quote("DEFINE_GUID(CLSID_PersistentZoneIdentifier, 0x0968e258, 0x16c7, 0x4dba, 0xaa, 0x86, 0x46, 0x2d, 0xd6, 0x1e, 0x31, 0xa3);") cpp_quote("DEFINE_GUID(CLSID_InternetSecurityManager, 0x7b8a2d94, 0x0ac9, 0x11d1, 0x89, 0x6c, 0x00, 0xc0, 0x4f, 0xB6, 0xbf, 0xc4);") cpp_quote("DEFINE_GUID(CLSID_InternetZoneManager, 0x7B8A2D95, 0x0AC9, 0x11D1, 0x89, 0x6C, 0x00, 0xC0, 0x4F, 0xB6, 0xBF, 0xC4);") cpp_quote("DEFINE_GUID(IID_IAsyncMoniker, 0x79EAC9D3, 0xBAF9, 0x11CE, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B);")
From: Mike Kozelkov augenzi@etersoft.ru
--- dlls/urlmon/tests/Makefile.in | 3 +- dlls/urlmon/tests/zone_id.c | 424 ++++++++++++++++++++++++++++++++++ 2 files changed, 426 insertions(+), 1 deletion(-) create mode 100644 dlls/urlmon/tests/zone_id.c
diff --git a/dlls/urlmon/tests/Makefile.in b/dlls/urlmon/tests/Makefile.in index 797a3434e1f..ed3cacd02fd 100644 --- a/dlls/urlmon/tests/Makefile.in +++ b/dlls/urlmon/tests/Makefile.in @@ -8,4 +8,5 @@ SOURCES = \ sec_mgr.c \ stream.c \ uri.c \ - url.c + url.c \ + zone_id.c diff --git a/dlls/urlmon/tests/zone_id.c b/dlls/urlmon/tests/zone_id.c new file mode 100644 index 00000000000..967a1b4f227 --- /dev/null +++ b/dlls/urlmon/tests/zone_id.c @@ -0,0 +1,424 @@ +#define COBJMACROS +#define CONST_VTABLE + +#include <wine/test.h> + +#include "winbase.h" +#include "urlmon.h" + +#define UNINIT_TEST(str) "uninitialized: " str +#define ZONE_TEST(str) "zone_identifier: " str +#define FILE_TEST(str) "persist_file: " str + +#define URLZONE_CUSTOM1 URLZONE_UNTRUSTED + 1 +#define URLZONE_CUSTOM2 URLZONE_USER_MAX + 1 + +#define TMP_PATH_LEN 2 * MAX_PATH + +typedef struct _zone_id_op_test { + URLZONE id; + HRESULT hres; +} zone_id_op_test; + +typedef struct _zone_id_test { + zone_id_op_test set; + zone_id_op_test get; +} zone_id_test; + +static const zone_id_test zone_id_tests[] = { + { { URLZONE_INVALID, E_ACCESSDENIED }, { URLZONE_UNTRUSTED, E_ACCESSDENIED } }, + { { URLZONE_LOCAL_MACHINE, S_OK }, { URLZONE_LOCAL_MACHINE, S_OK } }, + { { URLZONE_INTRANET, S_OK }, { URLZONE_INTRANET, S_OK } }, + { { URLZONE_TRUSTED, S_OK }, { URLZONE_TRUSTED, S_OK } }, + { { URLZONE_INTERNET, S_OK }, { URLZONE_INTERNET, S_OK } }, + { { URLZONE_UNTRUSTED, S_OK }, { URLZONE_UNTRUSTED, S_OK } }, + { { URLZONE_CUSTOM1, E_ACCESSDENIED }, { URLZONE_UNTRUSTED, E_ACCESSDENIED } }, + { { URLZONE_USER_MIN, E_ACCESSDENIED }, { URLZONE_UNTRUSTED, E_ACCESSDENIED } }, + { { URLZONE_USER_MAX, E_ACCESSDENIED }, { URLZONE_UNTRUSTED, E_ACCESSDENIED } }, + { { URLZONE_CUSTOM2, E_ACCESSDENIED }, { URLZONE_UNTRUSTED, E_ACCESSDENIED } } +}; + +typedef struct _get_cur_file_test { + LPCWSTR name; + HRESULT hres; +} get_cur_file_test; + +typedef struct load_file_test { + LPCWSTR name; + DWORD mode; + HRESULT hres; +} load_file_test; + +typedef struct _save_file_test { + LPCWSTR name; + BOOL remember; + HRESULT hres; +} save_file_test; + + +typedef struct _persist_file_test { + zone_id_op_test set; + save_file_test save; + HRESULT is_dirty_save; + get_cur_file_test cur_file; + HRESULT is_dirty_before_load; + load_file_test load; + HRESULT is_dirty_after_load; + zone_id_op_test get; +} persist_file_test; + +/* The test cases sequence shouldn't be changed as some test cases may depend on the behaviour of + * operations in previous test cases */ +static const persist_file_test persist_file_tests[] = { + { + { URLZONE_UNTRUSTED, S_OK }, + { NULL, FALSE, S_FALSE }, + S_OK, + { L"*", S_FALSE }, + S_OK, + { NULL, 0, E_FAIL }, + S_OK, + { URLZONE_UNTRUSTED, 0x80070490 }, + }, + /* Save shouldn't set current file + * GetCurFile should return default file name prompt */ + { + { URLZONE_INTERNET, S_OK }, + { L"00000000-0000-0000-0000-000000000000", FALSE, S_OK }, + S_OK, + { L"*", S_FALSE }, + S_OK, + { L"00000000-0000-0000-0000-000000000000", STGM_READWRITE | STGM_SHARE_DENY_NONE, S_OK }, + S_OK, + { URLZONE_INTERNET, S_OK }, + }, + /* Save should set current file */ + { + { URLZONE_LOCAL_MACHINE, S_OK }, + { L"00000000-0000-0000-0000-000000000000", TRUE, S_OK }, + S_FALSE, + { L"00000000-0000-0000-0000-000000000000", S_OK }, + S_OK, + { L"00000000-0000-0000-0000-000000000000", STGM_READWRITE | STGM_SHARE_DENY_NONE, S_OK }, + S_FALSE, + { URLZONE_LOCAL_MACHINE, S_OK }, + }, + /* Save should use already set current file to save object state, + * Save shouldn't change current file */ + { + { URLZONE_INTRANET, S_OK }, + { NULL, TRUE, S_OK }, + S_FALSE, + { L"00000000-0000-0000-0000-000000000000", S_OK }, + S_OK, + { L"00000000-0000-0000-0000-000000000000", STGM_READWRITE | STGM_SHARE_DENY_NONE, S_OK }, + S_FALSE, + { URLZONE_INTRANET, S_OK }, + }, + /* Save should use already set current file to save object state */ + { + { URLZONE_TRUSTED, S_OK }, + { NULL, FALSE, S_OK }, + S_FALSE, + { L"00000000-0000-0000-0000-000000000000", S_OK }, + S_OK, + { L"00000000-0000-0000-0000-000000000000", STGM_READWRITE | STGM_SHARE_DENY_NONE, S_OK }, + S_FALSE, + { URLZONE_TRUSTED, S_OK } + }, + /* Save should use given file name to save object state, + * Save shouldn't change current file */ + { + { URLZONE_INTERNET, S_OK }, + { L"11111111-1111-1111-1111-111111111111", FALSE, S_OK }, + S_OK, + { L"00000000-0000-0000-0000-000000000000", S_OK }, + S_OK, + { L"11111111-1111-1111-1111-111111111111", STGM_READWRITE | STGM_SHARE_DENY_NONE, S_OK }, + S_OK, + { URLZONE_INTERNET, S_OK } + }, + /* Load should fail due to invalid argument */ + { + { URLZONE_LOCAL_MACHINE, S_OK }, + { L"00000000-0000-0000-0000-000000000000", TRUE, S_OK }, + S_FALSE, + { L"00000000-0000-0000-0000-000000000000", S_OK }, + S_OK, + { NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, E_FAIL }, + S_OK, + { URLZONE_UNTRUSTED, 0x80070490 }, + }, + /* Load should get object state with restricted access mode */ + { + { URLZONE_LOCAL_MACHINE, S_OK }, + { L"00000000-0000-0000-0000-000000000000", TRUE, S_OK }, + S_FALSE, + { L"00000000-0000-0000-0000-000000000000", S_OK }, + S_OK, + { L"00000000-0000-0000-0000-000000000000", STGM_READ | STGM_SHARE_EXCLUSIVE, S_OK }, + S_FALSE, + { URLZONE_LOCAL_MACHINE, S_OK }, + }, + +}; + + +static void test_Uninitialized(void) +{ + const zone_id_op_test get = { URLZONE_UNTRUSTED, HRESULT_FROM_WIN32(ERROR_NOT_FOUND) }; + const zone_id_op_test set = { URLZONE_INTERNET, S_OK }; + const get_cur_file_test get_cur_file = { L"*", S_FALSE }; + const load_file_test load = { NULL, STGM_READ, E_FAIL }; + const save_file_test save = { NULL, FALSE, S_FALSE }; + IUnknown *unk; + IZoneIdentifier *zone_id; + IPersistFile *persist_file; + HRESULT hres; + DWORD zone; + CLSID clsid; + LPWSTR file_name; + + hres = CoCreateInstance(&CLSID_PersistentZoneIdentifier, NULL, + CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&unk); + ok(hres == S_OK, UNINIT_TEST("failed to obtain IUnknown iface: 0x%08lx\n"), hres); + + hres = IUnknown_QueryInterface(unk, &IID_IZoneIdentifier, (void**)&zone_id); + ok(hres == S_OK, UNINIT_TEST("failed to obtain IZoneIdentifier iface: 0x%08lx\n"), hres); + + hres = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&persist_file); + ok(hres == S_OK, UNINIT_TEST("failed to obtain IPersistFile iface: 0x%08lx\n"), hres); + + hres = IZoneIdentifier_GetId(zone_id, &zone); + ok(hres == get.hres, + UNINIT_TEST("unexpected get zone id result: 0x%08lx, expected result: 0x%08lx\n"), + hres, get.hres); + ok(zone == get.id, + UNINIT_TEST("unexpected default zone: 0x%08lx, expected zone: 0x%08x\n"), zone, get.id); + + hres = IPersistFile_GetClassID(persist_file, &clsid); + ok(hres == S_OK, + UNINIT_TEST("unexpected get class id result: 0x%08lx, expected result: 0x%08lx\n"), + hres, S_OK); + ok(IsEqualCLSID(&clsid, &CLSID_PersistentZoneIdentifier), + UNINIT_TEST("unexpected class id: %s, expected class id: %s\n"), + debugstr_guid(&clsid), debugstr_guid(&CLSID_PersistentZoneIdentifier)); + + hres = IPersistFile_GetCurFile(persist_file, &file_name); + ok(hres == get_cur_file.hres, + UNINIT_TEST("unexpected get current file result: 0x%08lx, expected result: 0x%08lx\n"), + hres, get_cur_file.hres); + ok(!lstrcmpW(file_name, get_cur_file.name), + UNINIT_TEST("unexpected current file name: %s, expected file name: %s\n"), + debugstr_w(file_name), debugstr_w(get_cur_file.name)); + if (hres == S_OK || hres == S_FALSE) { CoTaskMemFree(file_name); } + + hres = IPersistFile_IsDirty(persist_file); + ok(hres == S_FALSE, + UNINIT_TEST("unexpected change object state: 0x%08lx, expected state: 0x%08lx\n"), hres, S_OK); + + hres = IZoneIdentifier_SetId(zone_id, set.id); + ok(hres == set.hres, + UNINIT_TEST("unexpected set zone id result: 0x%08lx, expected result: 0x%08lx\n"), + hres, set.hres); + + hres = IPersistFile_IsDirty(persist_file); + ok(hres == S_OK, + UNINIT_TEST("unexpected change object state after set zone: 0x%08lx, expected state: 0x%08lx\n"), + hres, S_OK); + + hres = IPersistFile_Save(persist_file, save.name, save.remember); + ok(hres == save.hres, + UNINIT_TEST("unexpected save result: 0x%08lx, expected result: 0x%08lx\n"), hres, save.hres); + + hres = IPersistFile_Load(persist_file, load.name, load.mode); + ok(hres == load.hres, + UNINIT_TEST("unexpected load result: 0x%08lx, expected result: 0x%08lx\n"), hres, load.hres); +} + +static void test_IZoneIdentifier(void) +{ + const zone_id_op_test get_removed = { URLZONE_UNTRUSTED, HRESULT_FROM_WIN32(ERROR_NOT_FOUND)}; + IUnknown *unk; + IZoneIdentifier *zone_id; + zone_id_op_test set; + zone_id_op_test get; + HRESULT hres; + DWORD i; + DWORD zone; + + hres = CoCreateInstance(&CLSID_PersistentZoneIdentifier, NULL, + CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&unk); + ok(hres == S_OK, ZONE_TEST("failed to obtain IUnknown iface: 0x%08lx\n"), hres); + + hres = IUnknown_QueryInterface(unk, &IID_IZoneIdentifier, (void**)&zone_id); + ok(hres == S_OK, ZONE_TEST("failed to obtain IZoneIdentifier iface: 0x%08lx\n"), hres); + + for(i = 0; i < ARRAY_SIZE(zone_id_tests); ++i) { + set = zone_id_tests[i].set; + get = zone_id_tests[i].get; + + hres = IZoneIdentifier_SetId(zone_id, set.id); + ok(hres == set.hres, + ZONE_TEST("unexpected set zone id result: 0x%08lx, expected result: 0x%08lx\n"), + hres, set.hres); + + hres = IZoneIdentifier_GetId(zone_id, &zone); + ok(hres == get.hres, + ZONE_TEST("unexpected get zone id result: 0x%08lx, expected result: 0x%08lx\n"), + hres, get.hres); + ok(zone == get.id, + ZONE_TEST("unexpected zone id: 0x%08lx, expected zone: 0x%08x\n"), zone, get.id); + } + + hres = IZoneIdentifier_Remove(zone_id); + ok(hres == S_OK, + ZONE_TEST("unexpected remove zone id result: 0x%08lx, expected result: 0x%08lx\n"), + hres, S_OK); + + hres = IZoneIdentifier_GetId(zone_id, &zone); + ok(hres == get_removed.hres, + ZONE_TEST("unexpected get zone id result after remove: 0x%08lx, expected result: 0x%08lx\n"), + hres, get_removed.hres); + ok(zone == get_removed.id, + ZONE_TEST("unexpected zone id after remove: 0x%08lx, expected zone: 0x%08x\n"), + zone, get_removed.id); +} + +static void test_IPersistFile(void) +{ + IUnknown *unk; + IZoneIdentifier *zone_id_save; + IZoneIdentifier *zone_id_load; + IPersistFile *persist_file_save; + IPersistFile *persist_file_load; + HRESULT hres; + WCHAR tmp_dir[TMP_PATH_LEN]; + WCHAR tmp_file_path[TMP_PATH_LEN]; + WCHAR *file_path; + DWORD zone; + LPWSTR file_name; + DWORD i; + + hres = CoCreateInstance(&CLSID_PersistentZoneIdentifier, NULL, + CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&unk); + ok(hres == S_OK, FILE_TEST("failed to obtain IUnknown save iface: 0x%08lx\n"), hres); + + hres = IUnknown_QueryInterface(unk, &IID_IZoneIdentifier, (void**)&zone_id_save); + ok(hres == S_OK, FILE_TEST("failed to obtain IZoneIdentifier save iface: 0x%08lx\n"), hres); + + hres = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&persist_file_save); + ok(hres == S_OK, FILE_TEST("failed to obtain IPersistFile save iface: 0x%08lx\n"), hres); + + hres = CoCreateInstance(&CLSID_PersistentZoneIdentifier, NULL, + CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&unk); + ok(hres == S_OK, FILE_TEST("failed to obtain IUnknown load iface: 0x%08lx\n"), hres); + + hres = IUnknown_QueryInterface(unk, &IID_IZoneIdentifier, (void**)&zone_id_load); + ok(hres == S_OK, FILE_TEST("failed to obtain IZoneIdentifier load iface: 0x%08lx\n"), hres); + + hres = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&persist_file_load); + ok(hres == S_OK, FILE_TEST("failed to obtain IPersistFile load iface: 0x%08lx\n"), hres); + + hres = IZoneIdentifier_Remove(zone_id_save); + ok(hres == S_OK, + FILE_TEST("unexpected remove zone id result: 0x%08lx, expected result: 0x%08lx\n"), + hres, S_OK); + + if (!GetTempPathW(sizeof(tmp_dir), tmp_dir)) { + skip("Cannot get temporary directory path\n"); + return; + } + + file_name = NULL; + for (i = 0; i < ARRAY_SIZE(persist_file_tests); ++i) { + persist_file_test test = persist_file_tests[i]; + hres = IZoneIdentifier_SetId(zone_id_save, test.set.id); + ok(hres == test.set.hres, + FILE_TEST("unexpected set zone id result: 0x%08lx, expected result: 0x%08lx\n"), + hres, test.set.hres); + + if (test.save.name) + { + wsprintfW(tmp_file_path, L"%s%s", tmp_dir, test.save.name); + file_path = tmp_file_path; + } else { file_path = (WCHAR *)test.save.name; } + + hres = IPersistFile_Save(persist_file_save, file_path, test.save.remember); + ok(hres == test.save.hres, + FILE_TEST("unexpected save result: 0x%08lx, expected result: 0x%08lx\n"), + hres, test.save.hres); + + hres = IPersistFile_IsDirty(persist_file_save); + ok(hres == test.is_dirty_save, + FILE_TEST("unexpected change object state after save: 0x%08lx, expected state: 0x%08lx\n"), + hres, test.is_dirty_save); + + if (test.cur_file.hres != S_FALSE) + { + wsprintfW(tmp_file_path, L"%s%s", tmp_dir, test.cur_file.name); + file_path = tmp_file_path; + } else { file_path = (WCHAR *)test.cur_file.name; } + + hres = IPersistFile_GetCurFile(persist_file_save, &file_name); + ok(hres == test.cur_file.hres, + FILE_TEST("unexpected get current file result: 0x%08lx, expected result: 0x%08lx\n"), + hres, test.cur_file.hres); + ok(!lstrcmpW(file_name, file_path), + FILE_TEST("unexpected current file name: %s, expected file name: %s\n"), + debugstr_w(file_name), debugstr_w(file_path)); + if (hres == S_OK || hres == S_FALSE) { CoTaskMemFree(file_name); } + + hres = IZoneIdentifier_Remove(zone_id_load); + ok(hres == S_OK, + FILE_TEST("unexpected remove zone id result: 0x%08lx, expected result: 0x%08lx\n"), + hres, S_OK); + + hres = IPersistFile_IsDirty(persist_file_load); + ok(hres == test.is_dirty_before_load, + FILE_TEST("unexpected change object state before load: 0x%08lx, expected state: 0x%08lx\n"), + hres, test.is_dirty_before_load); + + if (test.load.name) + { + wsprintfW(tmp_file_path, L"%s%s", tmp_dir, test.load.name); + file_path = tmp_file_path; + } else { file_path = (WCHAR *)test.load.name; } + + hres = IPersistFile_Load(persist_file_load, file_path, test.load.mode); + ok(hres == test.load.hres, + FILE_TEST("unexpected load result: 0x%08lx, expected result: 0x%08lx\n"), + hres, test.load.hres); + + todo_wine + { + hres = IPersistFile_IsDirty(persist_file_load); + ok(hres == test.is_dirty_after_load, + FILE_TEST("unexpected change object state after load: 0x%08lx, expected state: 0x%08lx\n"), + hres, test.is_dirty_after_load); + + hres = IZoneIdentifier_GetId(zone_id_load, &zone); + ok(hres == test.get.hres, + FILE_TEST("unexpected get zone id result after load: 0x%08lx, expected result: 0x%08lx\n"), + hres, test.get.hres); + ok(zone == test.get.id, + FILE_TEST("unexpected zone id after load: 0x%08lx, expected zone: 0x%08x\n"), + zone, test.get.id); + } + } + +} + + +START_TEST(zone_id) +{ + + CoInitialize(NULL); + + test_Uninitialized(); + test_IZoneIdentifier(); + test_IPersistFile(); + + CoUninitialize(); + +}
From: Mike Kozelkov augenzi@etersoft.ru
--- dlls/urlmon/zone_id.c | 149 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 131 insertions(+), 18 deletions(-)
diff --git a/dlls/urlmon/zone_id.c b/dlls/urlmon/zone_id.c index 2d289e3dc3a..ecf68fc84e8 100644 --- a/dlls/urlmon/zone_id.c +++ b/dlls/urlmon/zone_id.c @@ -9,6 +9,12 @@ typedef struct { IPersistFile IPersistFile_iface; IZoneIdentifier IZoneIdentifier_iface;
+ BOOL is_dirty; + LPWSTR file_name; + + URLZONE zone; + BOOL is_zone_removed; + IUnknown *outer;
LONG ref; @@ -122,54 +128,118 @@ static HRESULT WINAPI PZIPersistFile_GetClassID(IPersistFile *iface, CLSID *clsi { PersistentZoneIdentifier *This = impl_from_IPersistFile(iface);
- FIXME("(%p, %p) not implemented\n", This, clsid); + TRACE("(%p, %p)\n", This, clsid); + + *clsid = CLSID_PersistentZoneIdentifier; + + return S_OK; +} + +static HRESULT alloc_and_copy(WCHAR** dest, const WCHAR* src) +{ + WCHAR* res; + DWORD required_size; + + if (!dest || !src) { return E_FAIL; } + + required_size = (lstrlenW(src) + 1) * sizeof(WCHAR); + res = CoTaskMemAlloc(required_size); + if (!res) { return E_OUTOFMEMORY; } + + if (lstrcpyW(res, src) != res) + { + CoTaskMemFree(res); + return E_FAIL; + } + + *dest = res;
- return E_NOTIMPL; + return S_OK; }
static HRESULT WINAPI PZIPersistFile_GetCurFile(IPersistFile *iface, LPOLESTR *file_name) { PersistentZoneIdentifier *This = impl_from_IPersistFile(iface); + WCHAR default_file_name[] = { L'*', 0}; + WCHAR *res_file_name; + HRESULT hres; + + TRACE("(%p, %p)\n", This, file_name); + + res_file_name = This->file_name ? This->file_name : default_file_name;
- FIXME("(%p, %p) not implemented\n", This, file_name); + hres = alloc_and_copy(file_name, res_file_name); + if (hres != S_OK) { *file_name = NULL; } + else { hres = res_file_name == default_file_name ? S_FALSE : hres; }
- return E_NOTIMPL; + return hres; }
static HRESULT WINAPI PZIPersistFile_IsDirty(IPersistFile *iface) { PersistentZoneIdentifier *This = impl_from_IPersistFile(iface);
- FIXME("(%p) not implemented\n", This); + TRACE("(%p)\n", This);
- return E_NOTIMPL; + return This->is_dirty ? S_OK : S_FALSE; }
static HRESULT WINAPI PZIPersistFile_Load(IPersistFile *iface, LPCOLESTR file_name, DWORD mode) { PersistentZoneIdentifier *This = impl_from_IPersistFile(iface);
- FIXME("(%p, %s, 0x%08lx) not implemented\n", This, debugstr_w(file_name), mode); + FIXME("(%p, %s, 0x%08lx) semi-stub\n", iface, debugstr_w(file_name), mode); + + if (!file_name) { return E_FAIL; } + + /* FIXME: Read zone information from Zone.Identifier NTFS alternate data stream */ + This->zone = URLZONE_INTERNET; + This->is_dirty = TRUE;
- return E_NOTIMPL; + return S_OK; }
static HRESULT WINAPI PZIPersistFile_Save(IPersistFile *iface, LPCOLESTR file_name, BOOL remember) { PersistentZoneIdentifier *This = impl_from_IPersistFile(iface); + WCHAR *new_file_name; + HRESULT hres; + + FIXME("(%p, %s, %d) semi-stub\n", iface, debugstr_w(file_name), remember); + + if (!file_name) + { + if (!This->file_name) { return S_FALSE; } + file_name = This->file_name; + remember = FALSE; + } + + /* FIXME: Write zone information to Zone.Identifier NTFS alternate data stream */
- FIXME("(%p, %s, %d) not implemented\n", This, debugstr_w(file_name), remember); + if (!lstrcmpW(This->file_name, file_name)) { This->is_dirty = FALSE; }
- return E_NOTIMPL; + if (remember) + { + hres = alloc_and_copy(&new_file_name, file_name); + if (hres != S_OK) { return hres; } + + if (This->file_name) { CoTaskMemFree(This->file_name); } + This->file_name = new_file_name; + This->is_dirty = FALSE; + } + + return S_OK; }
static HRESULT WINAPI PZIPersistFile_SaveCompleted(IPersistFile* iface, LPCOLESTR pszFileName) { PersistentZoneIdentifier *This = impl_from_IPersistFile(iface);
- FIXME("(%p, %p) not implemented\n", This, pszFileName); + FIXME("(%p, %p) semi-stub \n", This, pszFileName); + + /* FIXME: Add a notification to the object that it can write to its file */
- return E_NOTIMPL; + return S_OK; }
static const IPersistFileVtbl PZIPersistFileVtbl = { @@ -211,31 +281,68 @@ static ULONG WINAPI PZIZoneId_Release(IZoneIdentifier *iface) return IUnknown_Release(This->outer); }
+ +static BOOL is_trusted_zone(URLZONE zone) +{ + switch (zone) + { + case URLZONE_LOCAL_MACHINE: + case URLZONE_INTRANET: + case URLZONE_TRUSTED: + case URLZONE_INTERNET: + case URLZONE_UNTRUSTED: + return TRUE; + default: + return FALSE; + } +} + + static HRESULT WINAPI PZIZoneId_GetId(IZoneIdentifier* iface, DWORD* pdwZone) { PersistentZoneIdentifier *This = impl_from_IZoneIdentifier(iface);
- FIXME("(%p, %p) not implemented\n", This, pdwZone); + TRACE("(%p, %p)\n", This, pdwZone);
- return E_NOTIMPL; + if (This->is_zone_removed) + { + *pdwZone = URLZONE_UNTRUSTED; + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + } else if (!is_trusted_zone(This->zone)) + { + *pdwZone = URLZONE_UNTRUSTED; + return E_ACCESSDENIED; + } else + { + *pdwZone = This->zone; + return S_OK; + } }
static HRESULT WINAPI PZIZoneId_Remove(IZoneIdentifier* iface) { PersistentZoneIdentifier *This = impl_from_IZoneIdentifier(iface);
- FIXME("(%p) not implemented\n", This); + TRACE("(%p)\n", This); + + This->zone = URLZONE_LOCAL_MACHINE; + This->is_zone_removed = TRUE; + This->is_dirty = TRUE;
- return E_NOTIMPL; + return S_OK; }
static HRESULT WINAPI PZIZoneId_SetId(IZoneIdentifier* iface, DWORD dwZone) { PersistentZoneIdentifier *This = impl_from_IZoneIdentifier(iface);
- FIXME("(%p, 0x%08lx) not implemented\n", This, dwZone); + TRACE("(%p, 0x%08lx)\n", This, dwZone);
- return E_NOTIMPL; + This->zone = dwZone; + This->is_dirty = TRUE; + This->is_zone_removed = FALSE; + + return is_trusted_zone(This->zone) ? S_OK : E_ACCESSDENIED; }
static const IZoneIdentifierVtbl PZIZoneIdVtbl = { @@ -262,6 +369,12 @@ HRESULT PersistentZoneIdentifier_Construct(IUnknown *outer, LPVOID *ppobj) ret->IPersistFile_iface.lpVtbl = &PZIPersistFileVtbl; ret->IZoneIdentifier_iface.lpVtbl = &PZIZoneIdVtbl;
+ ret->file_name = NULL; + ret->is_dirty = FALSE; + + ret->zone = URLZONE_INVALID; + ret->is_zone_removed = TRUE; + ret->ref = 1; ret->outer = outer ? outer : &ret->IUnknown_inner;