Signed-off-by: Zebediah Figura z.figura12@gmail.com --- "pbc" is a bit of an unfortunate choice in a function that includes "bind context", "bind status callback", and "browse context".
dlls/hlink/link.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-)
diff --git a/dlls/hlink/link.c b/dlls/hlink/link.c index 25ee45d7c7..db7f0c3932 100644 --- a/dlls/hlink/link.c +++ b/dlls/hlink/link.c @@ -472,32 +472,33 @@ static HRESULT WINAPI IHlink_fnGetMiscStatus(IHlink* iface, DWORD* pdwStatus) return E_NOTIMPL; }
-static HRESULT WINAPI IHlink_fnNavigate(IHlink* iface, DWORD grfHLNF, LPBC pbc, - IBindStatusCallback *pbsc, IHlinkBrowseContext *phbc) +static HRESULT WINAPI IHlink_fnNavigate(IHlink *iface, DWORD flags, IBindCtx *user_bind_ctx, + IBindStatusCallback *bind_callback, IHlinkBrowseContext *browse_ctx) { - HlinkImpl *This = impl_from_IHlink(iface); + HlinkImpl *This = impl_from_IHlink(iface); IMoniker *mon = NULL; HRESULT r;
- FIXME("Semi-Stub:(%p)->(%i %p %p %p)\n", This, grfHLNF, pbc, pbsc, phbc); + TRACE("hlink %p, flags %#x, user_bind_ctx %p, bind_callback %p, browse_ctx %p.\n", + This, flags, user_bind_ctx, bind_callback, browse_ctx);
r = __GetMoniker(This, &mon, HLINKGETREF_ABSOLUTE); TRACE("Moniker %p\n", mon);
if (SUCCEEDED(r)) { - IBindCtx *bcxt = NULL; + IBindCtx *bind_ctx = NULL; IUnknown *unk = NULL; IHlinkTarget *target;
- if (phbc) + if (browse_ctx) { - r = IHlinkBrowseContext_GetObject(phbc, mon, TRUE, &unk); + r = IHlinkBrowseContext_GetObject(browse_ctx, mon, TRUE, &unk); if (r != S_OK) { - CreateBindCtx(0, &bcxt); - RegisterBindStatusCallback(bcxt, pbsc, NULL, 0); - r = IMoniker_BindToObject(mon, bcxt, NULL, &IID_IUnknown, (void**)&unk); + CreateBindCtx(0, &bind_ctx); + RegisterBindStatusCallback(bind_ctx, bind_callback, NULL, 0); + r = IMoniker_BindToObject(mon, bind_ctx, NULL, &IID_IUnknown, (void**)&unk); } if (r == S_OK) { @@ -506,13 +507,13 @@ static HRESULT WINAPI IHlink_fnNavigate(IHlink* iface, DWORD grfHLNF, LPBC pbc, } if (r == S_OK) { - if (bcxt) IHlinkTarget_SetBrowseContext(target, phbc); - r = IHlinkTarget_Navigate(target, grfHLNF, This->Location); + if (bind_ctx) IHlinkTarget_SetBrowseContext(target, browse_ctx); + r = IHlinkTarget_Navigate(target, flags, This->Location); IHlinkTarget_Release(target); }
- RevokeBindStatusCallback(bcxt, pbsc); - if (bcxt) IBindCtx_Release(bcxt); + RevokeBindStatusCallback(bind_ctx, bind_callback); + if (bind_ctx) IBindCtx_Release(bind_ctx); } else {
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=44423 Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/hlink/link.c | 184 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 182 insertions(+), 2 deletions(-)
diff --git a/dlls/hlink/link.c b/dlls/hlink/link.c index db7f0c3932..e3de7646ef 100644 --- a/dlls/hlink/link.c +++ b/dlls/hlink/link.c @@ -52,6 +52,12 @@ typedef struct IHlinkSite *Site; DWORD SiteData; BOOL absolute; + + IBindStatusCallback IBindStatusCallback_iface; + IBindStatusCallback *bind_callback; + IBindCtx *async_bind_ctx; + DWORD async_flags; + IHlinkBrowseContext *async_browse_ctx; } HlinkImpl;
static inline HlinkImpl *impl_from_IHlink(IHlink *iface) @@ -482,6 +488,9 @@ static HRESULT WINAPI IHlink_fnNavigate(IHlink *iface, DWORD flags, IBindCtx *us TRACE("hlink %p, flags %#x, user_bind_ctx %p, bind_callback %p, browse_ctx %p.\n", This, flags, user_bind_ctx, bind_callback, browse_ctx);
+ if (This->async_bind_ctx) + return E_UNEXPECTED; + r = __GetMoniker(This, &mon, HLINKGETREF_ABSOLUTE); TRACE("Moniker %p\n", mon);
@@ -497,8 +506,19 @@ static HRESULT WINAPI IHlink_fnNavigate(IHlink *iface, DWORD flags, IBindCtx *us if (r != S_OK) { CreateBindCtx(0, &bind_ctx); - RegisterBindStatusCallback(bind_ctx, bind_callback, NULL, 0); + RegisterBindStatusCallback(bind_ctx, &This->IBindStatusCallback_iface, NULL, 0); + This->bind_callback = bind_callback; r = IMoniker_BindToObject(mon, bind_ctx, NULL, &IID_IUnknown, (void**)&unk); + if (r == MK_S_ASYNCHRONOUS) + { + This->async_bind_ctx = bind_ctx; + This->async_flags = flags; + if (bind_callback) + IBindStatusCallback_AddRef(bind_callback); + IHlinkBrowseContext_AddRef(This->async_browse_ctx = browse_ctx); + IMoniker_Release(mon); + return r; + } } if (r == S_OK) { @@ -512,7 +532,7 @@ static HRESULT WINAPI IHlink_fnNavigate(IHlink *iface, DWORD flags, IBindCtx *us IHlinkTarget_Release(target); }
- RevokeBindStatusCallback(bind_ctx, bind_callback); + RevokeBindStatusCallback(bind_ctx, &This->IBindStatusCallback_iface); if (bind_ctx) IBindCtx_Release(bind_ctx); } else @@ -949,6 +969,165 @@ static const IPersistStreamVtbl psvt = IPersistStream_fnGetSizeMax, };
+static HlinkImpl *impl_from_IBindStatusCallback(IBindStatusCallback *iface) +{ + return CONTAINING_RECORD(iface, HlinkImpl, IBindStatusCallback_iface); +} + +static HRESULT WINAPI bind_callback_QueryInterface(IBindStatusCallback *iface, REFIID iid, void **out) +{ + if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IBindStatusCallback)) + { + IBindStatusCallback_AddRef(*out = iface); + return S_OK; + } + + WARN("No interface for %s.\n", debugstr_guid(iid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI bind_callback_AddRef(IBindStatusCallback *iface) +{ + HlinkImpl *hlink = impl_from_IBindStatusCallback(iface); + return IHlink_AddRef(&hlink->IHlink_iface); +} + +static ULONG WINAPI bind_callback_Release(IBindStatusCallback *iface) +{ + HlinkImpl *hlink = impl_from_IBindStatusCallback(iface); + return IHlink_Release(&hlink->IHlink_iface); +} + +static HRESULT WINAPI bind_callback_OnStartBinding(IBindStatusCallback *iface, + DWORD reserved, IBinding *binding) +{ + HlinkImpl *hlink = impl_from_IBindStatusCallback(iface); + + TRACE("hlink %p, reserved %#x, binding %p.\n", hlink, reserved, binding); + + if (hlink->bind_callback) + return IBindStatusCallback_OnStartBinding(hlink->bind_callback, reserved, binding); + return S_OK; +} + +static HRESULT WINAPI bind_callback_GetPriority(IBindStatusCallback *iface, LONG *priority) +{ + FIXME("iface %p, priority %p, stub!\n", iface, priority); + return E_NOTIMPL; +} + +static HRESULT WINAPI bind_callback_OnLowResource(IBindStatusCallback *iface, DWORD reserved) +{ + HlinkImpl *hlink = impl_from_IBindStatusCallback(iface); + + TRACE("hlink %p, reserved %#x.\n", hlink, reserved); + + if (hlink->bind_callback) + return IBindStatusCallback_OnLowResource(hlink->bind_callback, reserved); + return S_OK; +} + +static HRESULT WINAPI bind_callback_OnProgress(IBindStatusCallback *iface, + ULONG progress, ULONG max, ULONG status, const WCHAR *text) +{ + HlinkImpl *hlink = impl_from_IBindStatusCallback(iface); + + TRACE("hlink %p, progress %u, max %u, status %u, text %s.\n", + hlink, progress, max, status, debugstr_w(text)); + + if (hlink->bind_callback) + return IBindStatusCallback_OnProgress(hlink->bind_callback, progress, max, status, text); + return S_OK; +} + +static HRESULT WINAPI bind_callback_OnStopBinding(IBindStatusCallback *iface, + HRESULT hr, const WCHAR *error) +{ + HlinkImpl *hlink = impl_from_IBindStatusCallback(iface); + + TRACE("hlink %p, hr %#x, error %s.\n", hlink, hr, debugstr_w(error)); + + if (hlink->bind_callback) + IBindStatusCallback_OnStopBinding(hlink->bind_callback, hr, error); + + if (hlink->async_bind_ctx) + { + if (hlink->bind_callback) + IBindStatusCallback_Release(hlink->bind_callback); + RevokeBindStatusCallback(hlink->async_bind_ctx, iface); + IBindCtx_Release(hlink->async_bind_ctx); + IHlinkBrowseContext_Release(hlink->async_browse_ctx); + hlink->async_bind_ctx = NULL; + } + return S_OK; +} + +static HRESULT WINAPI bind_callback_GetBindInfo(IBindStatusCallback *iface, + DWORD *bind_flags, BINDINFO *bind_info) +{ + HlinkImpl *hlink = impl_from_IBindStatusCallback(iface); + + TRACE("hlink %p, bind_flags %p, bind_info %p.\n", hlink, bind_flags, bind_info); + + if (hlink->bind_callback) + return IBindStatusCallback_GetBindInfo(hlink->bind_callback, bind_flags, bind_info); + return S_OK; +} + +static HRESULT WINAPI bind_callback_OnDataAvailable(IBindStatusCallback *iface, + DWORD flags, DWORD size, FORMATETC *formatetc, STGMEDIUM *stgmed) +{ + FIXME("iface %p, flags %#x, size %d, formatetc %p, stgmed %p, stub!\n", + iface, flags, size, formatetc, stgmed); + return E_NOTIMPL; +} + +static HRESULT WINAPI bind_callback_OnObjectAvailable(IBindStatusCallback *iface, + REFIID iid, IUnknown *unk) +{ + HlinkImpl *hlink = impl_from_IBindStatusCallback(iface); + IHlinkTarget *target; + HRESULT hr; + + TRACE("hlink %p, iid %s, unk %p.\n", hlink, debugstr_guid(iid), unk); + + if (hlink->bind_callback) + IBindStatusCallback_OnObjectAvailable(hlink->bind_callback, iid, unk); + + if (hlink->async_bind_ctx) + { + hr = IUnknown_QueryInterface(unk, &IID_IHlinkTarget, (void **)&target); + if (FAILED(hr)) + return hr; + + IHlinkTarget_SetBrowseContext(target, hlink->async_browse_ctx); + hr = IHlinkTarget_Navigate(target, hlink->async_flags, hlink->Location); + IHlinkTarget_Release(target); + + if (hlink->Site) + IHlinkSite_OnNavigationComplete(hlink->Site, hlink->SiteData, 0, hr, NULL); + + return hr; + } + + return S_OK; +} + +static const IBindStatusCallbackVtbl bind_callback_vtbl = +{ + bind_callback_QueryInterface, + bind_callback_AddRef, + bind_callback_Release, + bind_callback_OnStartBinding, + bind_callback_GetPriority, + bind_callback_OnLowResource, + bind_callback_OnProgress, + bind_callback_OnStopBinding, + bind_callback_GetBindInfo, + bind_callback_OnDataAvailable, + bind_callback_OnObjectAvailable, +}; + HRESULT HLink_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv) { HlinkImpl * hl; @@ -967,6 +1146,7 @@ HRESULT HLink_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv) hl->IHlink_iface.lpVtbl = &hlvt; hl->IPersistStream_iface.lpVtbl = &psvt; hl->IDataObject_iface.lpVtbl = &dovt; + hl->IBindStatusCallback_iface.lpVtbl = &bind_callback_vtbl;
*ppv = hl; return S_OK;
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/hlink/tests/hlink.c | 247 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 231 insertions(+), 16 deletions(-)
diff --git a/dlls/hlink/tests/hlink.c b/dlls/hlink/tests/hlink.c index 52b5c57f9e..ccbbd889d5 100644 --- a/dlls/hlink/tests/hlink.c +++ b/dlls/hlink/tests/hlink.c @@ -81,9 +81,16 @@ DEFINE_EXPECT(HT_GetFriendlyName);
DEFINE_EXPECT(HLF_UpdateHlink);
+DEFINE_EXPECT(BindStatusCallback_GetBindInfo); +DEFINE_EXPECT(BindStatusCallback_OnObjectAvailable); +DEFINE_EXPECT(BindStatusCallback_OnStartBinding); +DEFINE_EXPECT(BindStatusCallback_OnStopBinding); + DEFINE_GUID(CLSID_IdentityUnmarshal,0x0000001b,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); DEFINE_GUID(IID_IHlinkHistory,0x79eac9c8,0xbaf9,0x11ce,0x8c,0x82,0x00,0xaa,0x00,0x4b,0xa9,0x0b);
+static IHlinkTarget HlinkTarget; + static const WCHAR winehq_urlW[] = {'h','t','t','p',':','/','/','t','e','s','t','.','w','i','n','e','h','q','.','o','r','g', '/','t','e','s','t','s','/','h','e','l','l','o','.','h','t','m','l',0}; @@ -757,21 +764,25 @@ static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *ifa return E_NOINTERFACE; }
+static LONG bind_callback_refs = 1; + static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface) { - return 2; + return ++bind_callback_refs; }
static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface) { - return 1; + return --bind_callback_refs; }
-static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface, DWORD dwReserved, - IBinding *pib) +static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface, + DWORD reserved, IBinding *binding) { - ok(0, "unexpected call\n"); - return E_NOTIMPL; + CHECK_EXPECT(BindStatusCallback_OnStartBinding); + + ok(!binding, "binding = %p\n", binding); + return S_OK; }
static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority) @@ -793,15 +804,20 @@ static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, return E_NOTIMPL; }
-static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError) +static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface, HRESULT hr, const WCHAR *error) { - ok(0, "unexpected call\n"); - return E_NOTIMPL; + CHECK_EXPECT(BindStatusCallback_OnStopBinding); + + ok(hr == S_OK, "got hr %#x\n", hr); + ok(!error, "got error %s\n", wine_dbgstr_w(error)); + + return 0xdeadbeef; }
-static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo) +static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface, DWORD *bind_flags, BINDINFO *bind_info) { - ok(0, "unexpected call\n"); + CHECK_EXPECT(BindStatusCallback_GetBindInfo); + return E_NOTIMPL; }
@@ -812,10 +828,14 @@ static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *if return E_NOTIMPL; }
-static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown *punk) +static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface, REFIID iid, IUnknown *out) { - ok(0, "unexpected call\n"); - return E_NOTIMPL; + CHECK_EXPECT(BindStatusCallback_OnObjectAvailable); + + ok(IsEqualGUID(iid, &IID_IUnknown), "iid = %s\n", wine_dbgstr_guid(iid)); + ok(out == (IUnknown *)&HlinkTarget, "out = %p\n", out); + + return 0xdeadbeef; }
static IBindStatusCallbackVtbl BindStatusCallbackVtbl = { @@ -853,14 +873,16 @@ static HRESULT WINAPI HlinkBrowseContext_QueryInterface( return E_NOINTERFACE; }
+static LONG browse_ctx_refs = 1; + static ULONG WINAPI HlinkBrowseContext_AddRef(IHlinkBrowseContext *iface) { - return 2; + return ++browse_ctx_refs; }
static ULONG WINAPI HlinkBrowseContext_Release(IHlinkBrowseContext *iface) { - return 1; + return --browse_ctx_refs; }
static HRESULT WINAPI HlinkBrowseContext_Register(IHlinkBrowseContext *iface, @@ -1125,9 +1147,16 @@ static HRESULT WINAPI Moniker_GetSizeMax(IMoniker *iface, ULARGE_INTEGER *pcbSiz return E_NOTIMPL; }
+static BOOL async_bind; +static IBindStatusCallback *async_bind_callback; + static HRESULT WINAPI Moniker_BindToObject(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft, REFIID riid, void **ppv) { + static WCHAR bscb_holderW[] = {'_','B','S','C','B','_','H','o','l','d','e','r','_',0}; + IUnknown *bind_callback_holder; + HRESULT hr; + CHECK_EXPECT(BindToObject);
ok(pbc != _bctx, "pbc != _bctx\n"); @@ -1136,6 +1165,17 @@ static HRESULT WINAPI Moniker_BindToObject(IMoniker *iface, IBindCtx *pbc, IMoni ok(ppv != NULL, "ppv == NULL\n"); ok(*ppv == NULL, "*ppv = %p\n", *ppv);
+ if (async_bind) + { + hr = IBindCtx_GetObjectParam(pbc, bscb_holderW, &bind_callback_holder); + ok(hr == S_OK, "Failed to get IBindStatusCallback holder, hr %#x.\n", hr); + hr = IUnknown_QueryInterface(bind_callback_holder, &IID_IBindStatusCallback, + (void **)&async_bind_callback); + ok(hr == S_OK, "Failed to get IBindStatusCallback interface, hr %#x.\n", hr); + IUnknown_Release(bind_callback_holder); + return MK_S_ASYNCHRONOUS; + } + *ppv = &HlinkTarget; return S_OK; } @@ -2188,6 +2228,8 @@ static void test_StdHlink(void)
static void test_Hlink_Navigate(void) { + BINDINFO bind_info = {sizeof(BINDINFO)}; + DWORD bind_flags; IHlink *hlink; IBindCtx *pbc; HRESULT hres; @@ -2301,6 +2343,179 @@ if (0) { /* these currently open a browser window on wine */ else skip("interactive IHlink_Navigate tests\n");
+ /* test binding callback */ + SET_EXPECT(IsSystemMoniker); + SET_EXPECT(GetDisplayName); + SET_EXPECT(BindStatusCallback_GetBindInfo); + SET_EXPECT(HBC_GetObject); + SET_EXPECT(Reduce); + SET_EXPECT(BindToObject); + SET_EXPECT(BindStatusCallback_OnStartBinding); + SET_EXPECT(BindStatusCallback_OnObjectAvailable); + SET_EXPECT(HT_QueryInterface_IHlinkTarget); + SET_EXPECT(HT_GetBrowseContext); + SET_EXPECT(HT_SetBrowseContext); + SET_EXPECT(HBC_QueryInterface_IHlinkHistory); + SET_EXPECT(HT_Navigate); + SET_EXPECT(HT_GetFriendlyName); + SET_EXPECT(BindStatusCallback_OnStopBinding); + hres = IHlink_Navigate(hlink, 0, pbc, &BindStatusCallback, &HlinkBrowseContext); + ok(hres == S_OK, "Navigate failed: %#x\n", hres); + CHECK_CALLED(IsSystemMoniker); + CHECK_CALLED(GetDisplayName); + CHECK_CALLED(HBC_GetObject); +todo_wine + CHECK_CALLED(BindStatusCallback_GetBindInfo); +todo_wine + CHECK_CALLED(Reduce); + CHECK_CALLED(BindToObject); +todo_wine { + CHECK_CALLED(BindStatusCallback_OnStartBinding); + CHECK_CALLED(BindStatusCallback_OnObjectAvailable); +} + CHECK_CALLED(HT_QueryInterface_IHlinkTarget); +todo_wine + CHECK_CALLED(HT_GetBrowseContext); + CHECK_CALLED(HT_SetBrowseContext); +todo_wine + CHECK_CALLED(HBC_QueryInterface_IHlinkHistory); + CHECK_CALLED(HT_Navigate); +todo_wine + CHECK_CALLED(HT_GetFriendlyName); +todo_wine + CHECK_CALLED(BindStatusCallback_OnStopBinding); + + ok(bind_callback_refs == 1, "Got unexpected refcount %d.\n", bind_callback_refs); + ok(browse_ctx_refs == 1, "Got unexpected refcount %d.\n", browse_ctx_refs); + + /* test asynchronous binding */ + async_bind = TRUE; + SET_EXPECT(IsSystemMoniker); + SET_EXPECT(GetDisplayName); + SET_EXPECT(HBC_GetObject); + SET_EXPECT(Reduce); + SET_EXPECT(BindToObject); + hres = IHlink_Navigate(hlink, 0, pbc, NULL, &HlinkBrowseContext); + ok(hres == MK_S_ASYNCHRONOUS, "Navigate failed: %#x\n", hres); + CHECK_CALLED(IsSystemMoniker); + CHECK_CALLED(GetDisplayName); + CHECK_CALLED(HBC_GetObject); +todo_wine + CHECK_CALLED(Reduce); + CHECK_CALLED(BindToObject); + + ok(browse_ctx_refs > 1, "Got unexpected refcount %d.\n", browse_ctx_refs); + + hres = IHlink_Navigate(hlink, 0, pbc, NULL, &HlinkBrowseContext); + ok(hres == E_UNEXPECTED, "Got hr %#x.\n", hres); + + hres = IBindStatusCallback_GetBindInfo(async_bind_callback, &bind_flags, &bind_info); + ok(hres == S_OK, "Got hr %#x.\n", hres); + + hres = IBindStatusCallback_OnStartBinding(async_bind_callback, 0, NULL); + ok(hres == S_OK, "Got hr %#x.\n", hres); + + SET_EXPECT(HT_QueryInterface_IHlinkTarget); + SET_EXPECT(HT_GetBrowseContext); + SET_EXPECT(HT_SetBrowseContext); + SET_EXPECT(HBC_QueryInterface_IHlinkHistory); + SET_EXPECT(HT_Navigate); + SET_EXPECT(HT_GetFriendlyName); + hres = IBindStatusCallback_OnObjectAvailable(async_bind_callback, &IID_IUnknown, + (IUnknown *)&HlinkTarget); + ok(hres == S_OK, "Got hr %#x.\n", hres); + CHECK_CALLED(HT_QueryInterface_IHlinkTarget); +todo_wine + CHECK_CALLED(HT_GetBrowseContext); + CHECK_CALLED(HT_SetBrowseContext); +todo_wine + CHECK_CALLED(HBC_QueryInterface_IHlinkHistory); + CHECK_CALLED(HT_Navigate); +todo_wine + CHECK_CALLED(HT_GetFriendlyName); + + hres = IHlink_Navigate(hlink, 0, pbc, NULL, &HlinkBrowseContext); + ok(hres == E_UNEXPECTED, "Got hr %#x.\n", hres); + + ok(browse_ctx_refs > 1, "Got unexpected refcount %d.\n", browse_ctx_refs); + + hres = IBindStatusCallback_OnStopBinding(async_bind_callback, S_OK, NULL); + ok(hres == S_OK, "Got hr %#x.\n", hres); + + ok(browse_ctx_refs == 1, "Got unexpected refcount %d.\n", browse_ctx_refs); + + IBindStatusCallback_Release(async_bind_callback); + + SET_EXPECT(IsSystemMoniker); + SET_EXPECT(GetDisplayName); + SET_EXPECT(BindStatusCallback_GetBindInfo); + SET_EXPECT(HBC_GetObject); + SET_EXPECT(Reduce); + SET_EXPECT(BindToObject); + hres = IHlink_Navigate(hlink, 0, pbc, &BindStatusCallback, &HlinkBrowseContext); + ok(hres == MK_S_ASYNCHRONOUS, "Navigate failed: %#x\n", hres); + CHECK_CALLED(IsSystemMoniker); + CHECK_CALLED(GetDisplayName); +todo_wine + CHECK_CALLED(BindStatusCallback_GetBindInfo); + CHECK_CALLED(HBC_GetObject); +todo_wine + CHECK_CALLED(Reduce); + CHECK_CALLED(BindToObject); + + ok(bind_callback_refs > 1, "Got unexpected refcount %d.\n", bind_callback_refs); + ok(browse_ctx_refs > 1, "Got unexpected refcount %d.\n", browse_ctx_refs); + + hres = IHlink_Navigate(hlink, 0, pbc, NULL, &HlinkBrowseContext); + ok(hres == E_UNEXPECTED, "Got hr %#x.\n", hres); + + SET_EXPECT(BindStatusCallback_GetBindInfo); + hres = IBindStatusCallback_GetBindInfo(async_bind_callback, &bind_flags, &bind_info); + ok(hres == E_NOTIMPL, "Got hr %#x.\n", hres); + CHECK_CALLED(BindStatusCallback_GetBindInfo); + + SET_EXPECT(BindStatusCallback_OnStartBinding); + hres = IBindStatusCallback_OnStartBinding(async_bind_callback, 0, NULL); + ok(hres == S_OK, "Got hr %#x.\n", hres); + CHECK_CALLED(BindStatusCallback_OnStartBinding); + + SET_EXPECT(BindStatusCallback_OnObjectAvailable); + SET_EXPECT(HT_QueryInterface_IHlinkTarget); + SET_EXPECT(HT_GetBrowseContext); + SET_EXPECT(HT_SetBrowseContext); + SET_EXPECT(HBC_QueryInterface_IHlinkHistory); + SET_EXPECT(HT_Navigate); + SET_EXPECT(HT_GetFriendlyName); + hres = IBindStatusCallback_OnObjectAvailable(async_bind_callback, &IID_IUnknown, + (IUnknown *)&HlinkTarget); + ok(hres == S_OK, "Got hr %#x.\n", hres); + CHECK_CALLED(BindStatusCallback_OnObjectAvailable); + CHECK_CALLED(HT_QueryInterface_IHlinkTarget); +todo_wine + CHECK_CALLED(HT_GetBrowseContext); + CHECK_CALLED(HT_SetBrowseContext); +todo_wine + CHECK_CALLED(HBC_QueryInterface_IHlinkHistory); + CHECK_CALLED(HT_Navigate); +todo_wine + CHECK_CALLED(HT_GetFriendlyName); + + hres = IHlink_Navigate(hlink, 0, pbc, NULL, &HlinkBrowseContext); + ok(hres == E_UNEXPECTED, "Got hr %#x.\n", hres); + + ok(bind_callback_refs > 1, "Got unexpected refcount %d.\n", bind_callback_refs); + ok(browse_ctx_refs > 1, "Got unexpected refcount %d.\n", browse_ctx_refs); + + SET_EXPECT(BindStatusCallback_OnStopBinding); + hres = IBindStatusCallback_OnStopBinding(async_bind_callback, S_OK, NULL); + ok(hres == S_OK, "Got hr %#x.\n", hres); + CHECK_CALLED(BindStatusCallback_OnStopBinding); + + ok(bind_callback_refs == 1, "Got unexpected refcount %d.\n", bind_callback_refs); + ok(browse_ctx_refs == 1, "Got unexpected refcount %d.\n", browse_ctx_refs); + + IBindStatusCallback_Release(async_bind_callback); + IHlink_Release(hlink); IBindCtx_Release(pbc); _bctx = NULL;