urlmon: Added BindToObject implementation.
This commit is contained in:
parent
a16ae2e8f2
commit
85f472b37d
|
@ -17,11 +17,14 @@
|
|||
*/
|
||||
|
||||
#include "urlmon_main.h"
|
||||
#include "winreg.h"
|
||||
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
|
||||
|
||||
static WCHAR cbinding_contextW[] = {'C','B','i','n','d','i','n','g',' ','C','o','n','t','e','x','t',0};
|
||||
static WCHAR bscb_holderW[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
|
||||
|
||||
typedef struct Binding Binding;
|
||||
|
||||
|
@ -53,8 +56,9 @@ typedef enum {
|
|||
END_DOWNLOAD
|
||||
} download_state_t;
|
||||
|
||||
#define BINDING_LOCKED 0x0001
|
||||
#define BINDING_STOPPED 0x0002
|
||||
#define BINDING_LOCKED 0x0001
|
||||
#define BINDING_STOPPED 0x0002
|
||||
#define BINDING_OBJAVAIL 0x0004
|
||||
|
||||
struct Binding {
|
||||
const IBindingVtbl *lpBindingVtbl;
|
||||
|
@ -71,14 +75,19 @@ struct Binding {
|
|||
|
||||
BINDINFO bindinfo;
|
||||
DWORD bindf;
|
||||
BOOL to_object;
|
||||
LPWSTR mime;
|
||||
UINT clipboard_format;
|
||||
LPWSTR url;
|
||||
IID iid;
|
||||
BOOL report_mime;
|
||||
DWORD continue_call;
|
||||
DWORD state;
|
||||
HRESULT hres;
|
||||
download_state_t download_state;
|
||||
IUnknown *obj;
|
||||
IMoniker *mon;
|
||||
IBindCtx *bctx;
|
||||
|
||||
DWORD apartment_thread;
|
||||
HWND notif_hwnd;
|
||||
|
@ -329,6 +338,128 @@ static void stop_binding(Binding *binding, HRESULT hres, LPCWSTR str)
|
|||
}
|
||||
}
|
||||
|
||||
static LPWSTR get_mime_clsid(LPCWSTR mime, CLSID *clsid)
|
||||
{
|
||||
LPWSTR key_name, ret;
|
||||
DWORD res, type, size;
|
||||
HKEY hkey;
|
||||
int len;
|
||||
HRESULT hres;
|
||||
|
||||
static const WCHAR mime_keyW[] =
|
||||
{'M','I','M','E','\\','D','a','t','a','b','a','s','e','\\',
|
||||
'C','o','n','t','e','n','t',' ','T','y','p','e','\\'};
|
||||
static const WCHAR clsidW[] = {'C','L','S','I','D',0};
|
||||
|
||||
len = strlenW(mime)+1;
|
||||
key_name = heap_alloc(sizeof(mime_keyW) + len*sizeof(WCHAR));
|
||||
memcpy(key_name, mime_keyW, sizeof(mime_keyW));
|
||||
strcpyW(key_name + sizeof(mime_keyW)/sizeof(WCHAR), mime);
|
||||
|
||||
res = RegOpenKeyW(HKEY_CLASSES_ROOT, key_name, &hkey);
|
||||
heap_free(key_name);
|
||||
if(res != ERROR_SUCCESS) {
|
||||
WARN("Could not open MIME key: %x\n", res);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = 50*sizeof(WCHAR);
|
||||
ret = heap_alloc(size);
|
||||
res = RegQueryValueExW(hkey, clsidW, NULL, &type, (LPBYTE)ret, &size);
|
||||
RegCloseKey(hkey);
|
||||
if(res != ERROR_SUCCESS) {
|
||||
WARN("Could not get CLSID: %08x\n", res);
|
||||
heap_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hres = CLSIDFromString(ret, clsid);
|
||||
if(FAILED(hres)) {
|
||||
WARN("Could not parse CLSID: %08x\n", hres);
|
||||
heap_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void load_doc_mon(Binding *binding, IPersistMoniker *persist)
|
||||
{
|
||||
IBindCtx *bctx;
|
||||
HRESULT hres;
|
||||
|
||||
hres = CreateAsyncBindCtxEx(binding->bctx, 0, NULL, NULL, &bctx, 0);
|
||||
if(FAILED(hres)) {
|
||||
WARN("CreateAsyncBindCtxEx failed: %08x\n", hres);
|
||||
return;
|
||||
}
|
||||
|
||||
IBindCtx_RevokeObjectParam(bctx, bscb_holderW);
|
||||
IBindCtx_RegisterObjectParam(bctx, cbinding_contextW, (IUnknown*)BINDING(binding));
|
||||
|
||||
hres = IPersistMoniker_Load(persist, binding->download_state == END_DOWNLOAD, binding->mon, bctx, 0x12);
|
||||
IBindCtx_RevokeObjectParam(bctx, cbinding_contextW);
|
||||
IBindCtx_Release(bctx);
|
||||
if(FAILED(hres))
|
||||
FIXME("Load failed: %08x\n", hres);
|
||||
}
|
||||
|
||||
static void create_object(Binding *binding)
|
||||
{
|
||||
IPersistMoniker *persist;
|
||||
LPWSTR clsid_str;
|
||||
CLSID clsid;
|
||||
HRESULT hres;
|
||||
|
||||
if(!binding->mime) {
|
||||
FIXME("MIME unavailable\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!(clsid_str = get_mime_clsid(binding->mime, &clsid))) {
|
||||
FIXME("Could not find object for MIME %s\n", debugstr_w(binding->mime));
|
||||
return;
|
||||
}
|
||||
|
||||
IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_CLASSIDAVAILABLE, clsid_str);
|
||||
|
||||
IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_BEGINSYNCOPERATION, NULL);
|
||||
|
||||
hres = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
|
||||
&binding->iid, (void**)&binding->obj);
|
||||
if(FAILED(hres))
|
||||
FIXME("CoCreateInstance failed: %08x\n", hres);
|
||||
|
||||
binding->state |= BINDING_OBJAVAIL;
|
||||
|
||||
hres = IUnknown_QueryInterface(binding->obj, &IID_IPersistMoniker, (void**)&persist);
|
||||
if(SUCCEEDED(hres)) {
|
||||
IMonikerProp *prop;
|
||||
|
||||
hres = IPersistMoniker_QueryInterface(persist, &IID_IMonikerProp, (void**)&prop);
|
||||
if(SUCCEEDED(hres)) {
|
||||
IMonikerProp_PutProperty(prop, MIMETYPEPROP, binding->mime);
|
||||
IMonikerProp_PutProperty(prop, CLASSIDPROP, clsid_str);
|
||||
IMonikerProp_Release(prop);
|
||||
}
|
||||
|
||||
load_doc_mon(binding, persist);
|
||||
|
||||
IPersistMoniker_Release(persist);
|
||||
}else {
|
||||
FIXME("Could not get IPersistMoniker: %08x\n", hres);
|
||||
/* FIXME: Try query IPersistFile */
|
||||
}
|
||||
|
||||
heap_free(clsid_str);
|
||||
|
||||
IBindStatusCallback_OnObjectAvailable(binding->callback, &binding->iid, binding->obj);
|
||||
|
||||
IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_ENDSYNCOPERATION, NULL);
|
||||
|
||||
stop_binding(binding, S_OK, NULL);
|
||||
}
|
||||
|
||||
#define STREAM_THIS(iface) DEFINE_THIS(ProtocolStream, Stream, iface)
|
||||
|
||||
static HRESULT WINAPI ProtocolStream_QueryInterface(IStream *iface,
|
||||
|
@ -597,6 +728,8 @@ static ULONG WINAPI Binding_Release(IBinding *iface)
|
|||
if(!ref) {
|
||||
if (This->notif_hwnd)
|
||||
DestroyWindow( This->notif_hwnd );
|
||||
if(This->mon)
|
||||
IMoniker_Release(This->mon);
|
||||
if(This->callback)
|
||||
IBindStatusCallback_Release(This->callback);
|
||||
if(This->protocol)
|
||||
|
@ -605,6 +738,10 @@ static ULONG WINAPI Binding_Release(IBinding *iface)
|
|||
IServiceProvider_Release(This->service_provider);
|
||||
if(This->stream)
|
||||
IStream_Release(STREAM(This->stream));
|
||||
if(This->obj)
|
||||
IUnknown_Release(This->obj);
|
||||
if(This->bctx)
|
||||
IBindCtx_Release(This->bctx);
|
||||
|
||||
ReleaseBindInfo(&This->bindinfo);
|
||||
This->section.DebugInfo->Spare[0] = 0;
|
||||
|
@ -857,7 +994,7 @@ static void report_data(Binding *This, DWORD bscf, ULONG progress, ULONG progres
|
|||
return;
|
||||
|
||||
if(GetCurrentThreadId() != This->apartment_thread)
|
||||
FIXME("called from worked hread\n");
|
||||
FIXME("called from worker thread\n");
|
||||
|
||||
if(This->report_mime)
|
||||
mime_available(This, NULL, TRUE);
|
||||
|
@ -880,18 +1017,23 @@ static void report_data(Binding *This, DWORD bscf, ULONG progress, ULONG progres
|
|||
BINDSTATUS_DOWNLOADINGDATA, This->url);
|
||||
}
|
||||
|
||||
if(!(This->state & BINDING_LOCKED)) {
|
||||
HRESULT hres = IInternetProtocol_LockRequest(This->protocol, 0);
|
||||
if(SUCCEEDED(hres))
|
||||
This->state |= BINDING_LOCKED;
|
||||
if(This->to_object) {
|
||||
if(!(This->state & BINDING_OBJAVAIL))
|
||||
create_object(This);
|
||||
}else {
|
||||
if(!(This->state & BINDING_LOCKED)) {
|
||||
HRESULT hres = IInternetProtocol_LockRequest(This->protocol, 0);
|
||||
if(SUCCEEDED(hres))
|
||||
This->state |= BINDING_LOCKED;
|
||||
}
|
||||
|
||||
formatetc.cfFormat = This->clipboard_format;
|
||||
IBindStatusCallback_OnDataAvailable(This->callback, bscf, progress,
|
||||
&formatetc, &This->stgmed);
|
||||
|
||||
if(This->download_state == END_DOWNLOAD)
|
||||
stop_binding(This, S_OK, NULL);
|
||||
}
|
||||
|
||||
formatetc.cfFormat = This->clipboard_format;
|
||||
IBindStatusCallback_OnDataAvailable(This->callback, bscf, progress,
|
||||
&formatetc, &This->stgmed);
|
||||
|
||||
if(This->download_state == END_DOWNLOAD)
|
||||
stop_binding(This, S_OK, NULL);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
|
@ -1135,9 +1277,7 @@ static HRESULT get_callback(IBindCtx *pbc, IBindStatusCallback **callback)
|
|||
IUnknown *unk;
|
||||
HRESULT hres;
|
||||
|
||||
static WCHAR wszBSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
|
||||
|
||||
hres = IBindCtx_GetObjectParam(pbc, wszBSCBHolder, &unk);
|
||||
hres = IBindCtx_GetObjectParam(pbc, bscb_holderW, &unk);
|
||||
if(SUCCEEDED(hres)) {
|
||||
hres = IUnknown_QueryInterface(unk, &IID_IBindStatusCallback, (void**)callback);
|
||||
IUnknown_Release(unk);
|
||||
|
@ -1180,12 +1320,13 @@ static BOOL is_urlmon_protocol(LPCWSTR url)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static HRESULT Binding_Create(Binding *binding_ctx, LPCWSTR url, IBindCtx *pbc, REFIID riid, Binding **binding)
|
||||
static HRESULT Binding_Create(IMoniker *mon, Binding *binding_ctx, LPCWSTR url, IBindCtx *pbc,
|
||||
BOOL to_obj, REFIID riid, Binding **binding)
|
||||
{
|
||||
Binding *ret;
|
||||
HRESULT hres;
|
||||
|
||||
if(!IsEqualGUID(&IID_IStream, riid)) {
|
||||
if(!to_obj && !IsEqualGUID(&IID_IStream, riid)) {
|
||||
FIXME("Unsupported riid %s\n", debugstr_guid(riid));
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
@ -1201,11 +1342,23 @@ static HRESULT Binding_Create(Binding *binding_ctx, LPCWSTR url, IBindCtx *pbc,
|
|||
|
||||
ret->ref = 1;
|
||||
|
||||
ret->to_object = to_obj;
|
||||
ret->iid = *riid;
|
||||
ret->apartment_thread = GetCurrentThreadId();
|
||||
ret->notif_hwnd = get_notif_hwnd();
|
||||
ret->report_mime = !binding_ctx;
|
||||
ret->download_state = BEFORE_DOWNLOAD;
|
||||
|
||||
if(to_obj) {
|
||||
IBindCtx_AddRef(pbc);
|
||||
ret->bctx = pbc;
|
||||
}
|
||||
|
||||
if(mon) {
|
||||
IMoniker_AddRef(mon);
|
||||
ret->mon = mon;
|
||||
}
|
||||
|
||||
ret->bindinfo.cbSize = sizeof(BINDINFO);
|
||||
|
||||
InitializeCriticalSection(&ret->section);
|
||||
|
@ -1240,9 +1393,12 @@ static HRESULT Binding_Create(Binding *binding_ctx, LPCWSTR url, IBindCtx *pbc,
|
|||
return hres;
|
||||
}
|
||||
|
||||
TRACE("bindf %08x\n", ret->bindf);
|
||||
dump_BINDINFO(&ret->bindinfo);
|
||||
|
||||
ret->bindf |= BINDF_FROMURLMON;
|
||||
if(to_obj)
|
||||
ret->bindinfo.dwOptions |= 0x100000;
|
||||
|
||||
if(!is_urlmon_protocol(url))
|
||||
ret->bindf |= BINDF_NEEDFILE;
|
||||
|
@ -1256,7 +1412,6 @@ static HRESULT Binding_Create(Binding *binding_ctx, LPCWSTR url, IBindCtx *pbc,
|
|||
}else {
|
||||
ret->stream = create_stream(ret->protocol);
|
||||
}
|
||||
|
||||
ret->stgmed.tymed = TYMED_ISTREAM;
|
||||
ret->stgmed.u.pstm = STREAM(ret->stream);
|
||||
ret->stgmed.pUnkForRelease = (IUnknown*)BINDING(ret); /* NOTE: Windows uses other IUnknown */
|
||||
|
@ -1265,13 +1420,14 @@ static HRESULT Binding_Create(Binding *binding_ctx, LPCWSTR url, IBindCtx *pbc,
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT start_binding(Binding *binding_ctx, LPCWSTR url, IBindCtx *pbc, REFIID riid, Binding **ret)
|
||||
static HRESULT start_binding(IMoniker *mon, Binding *binding_ctx, LPCWSTR url, IBindCtx *pbc,
|
||||
BOOL to_obj, REFIID riid, Binding **ret)
|
||||
{
|
||||
Binding *binding = NULL;
|
||||
HRESULT hres;
|
||||
MSG msg;
|
||||
|
||||
hres = Binding_Create(binding_ctx, url, pbc, riid, &binding);
|
||||
hres = Binding_Create(mon, binding_ctx, url, pbc, to_obj, riid, &binding);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
|
@ -1322,7 +1478,7 @@ HRESULT bind_to_storage(LPCWSTR url, IBindCtx *pbc, REFIID riid, void **ppv)
|
|||
|
||||
binding_ctx = get_bctx_binding(pbc);
|
||||
|
||||
hres = start_binding(binding_ctx, url, pbc, riid, &binding);
|
||||
hres = start_binding(NULL, binding_ctx, url, pbc, FALSE, riid, &binding);
|
||||
if(binding_ctx)
|
||||
IBinding_Release(BINDING(binding_ctx));
|
||||
if(FAILED(hres))
|
||||
|
@ -1346,3 +1502,29 @@ HRESULT bind_to_storage(LPCWSTR url, IBindCtx *pbc, REFIID riid, void **ppv)
|
|||
|
||||
return hres;
|
||||
}
|
||||
|
||||
HRESULT bind_to_object(IMoniker *mon, LPCWSTR url, IBindCtx *pbc, REFIID riid, void **ppv)
|
||||
{
|
||||
Binding *binding;
|
||||
HRESULT hres;
|
||||
|
||||
*ppv = NULL;
|
||||
|
||||
hres = start_binding(mon, NULL, url, pbc, TRUE, riid, &binding);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
if(binding->hres != S_OK) {
|
||||
hres = SUCCEEDED(binding->hres) ? S_OK : binding->hres;
|
||||
}else if(binding->bindf & BINDF_ASYNCHRONOUS) {
|
||||
hres = MK_S_ASYNCHRONOUS;
|
||||
}else {
|
||||
*ppv = binding->obj;
|
||||
IUnknown_AddRef(binding->obj);
|
||||
hres = S_OK;
|
||||
}
|
||||
|
||||
IBinding_Release(BINDING(binding));
|
||||
|
||||
return hres;
|
||||
}
|
||||
|
|
|
@ -1698,7 +1698,7 @@ static void test_BindToObject(int protocol, BOOL emul)
|
|||
trace( "Network unreachable, skipping tests\n" );
|
||||
return;
|
||||
}
|
||||
todo_wine ok(SUCCEEDED(hres), "IMoniker_BindToObject failed with error 0x%08x\n", hres);
|
||||
ok(SUCCEEDED(hres), "IMoniker_BindToObject failed with error 0x%08x\n", hres);
|
||||
/* no point testing the calls if binding didn't even work */
|
||||
if (!SUCCEEDED(hres)) return;
|
||||
|
||||
|
@ -1750,7 +1750,10 @@ static void test_BindToObject(int protocol, BOOL emul)
|
|||
CHECK_CALLED(OnProgress_BEGINDOWNLOADDATA);
|
||||
if(test_protocol == HTTP_TEST)
|
||||
CLEAR_CALLED(OnProgress_DOWNLOADINGDATA);
|
||||
CHECK_CALLED(OnProgress_ENDDOWNLOADDATA);
|
||||
if(test_protocol == HTTP_TEST && urls[test_protocol] != SHORT_RESPONSE_URL)
|
||||
todo_wine CHECK_CALLED(OnProgress_ENDDOWNLOADDATA);
|
||||
else
|
||||
CHECK_CALLED(OnProgress_ENDDOWNLOADDATA);
|
||||
CHECK_CALLED(OnProgress_CLASSIDAVAILABLE);
|
||||
CHECK_CALLED(OnProgress_BEGINSYNCOPERATION);
|
||||
CHECK_CALLED(OnProgress_ENDSYNCOPERATION);
|
||||
|
@ -1758,8 +1761,13 @@ static void test_BindToObject(int protocol, BOOL emul)
|
|||
CHECK_CALLED(OnStopBinding);
|
||||
}
|
||||
|
||||
ok(IMoniker_Release(mon) == 0, "mon should be destroyed here\n");
|
||||
ok(IBindCtx_Release(bctx) == 0, "bctx should be destroyed here\n");
|
||||
if(test_protocol != HTTP_TEST || emul || urls[test_protocol] == SHORT_RESPONSE_URL) {
|
||||
ok(IMoniker_Release(mon) == 0, "mon should be destroyed here\n");
|
||||
ok(IBindCtx_Release(bctx) == 0, "bctx should be destroyed here\n");
|
||||
}else todo_wine {
|
||||
ok(IMoniker_Release(mon) == 0, "mon should be destroyed here\n");
|
||||
ok(IBindCtx_Release(bctx) == 0, "bctx should be destroyed here\n");
|
||||
}
|
||||
|
||||
if(test_protocol == HTTP_TEST)
|
||||
http_is_first = FALSE;
|
||||
|
|
|
@ -473,16 +473,21 @@ static HRESULT WINAPI URLMonikerImpl_BindToObject(IMoniker* iface,
|
|||
IBindCtx* pbc,
|
||||
IMoniker* pmkToLeft,
|
||||
REFIID riid,
|
||||
VOID** ppvResult)
|
||||
VOID** ppv)
|
||||
{
|
||||
URLMonikerImpl *This = (URLMonikerImpl *)iface;
|
||||
IRunningObjectTable *obj_tbl;
|
||||
HRESULT hres;
|
||||
|
||||
*ppvResult=0;
|
||||
TRACE("(%p)->(%p,%p,%s,%p): stub\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppv);
|
||||
|
||||
FIXME("(%p)->(%p,%p,%s,%p): stub\n",This,pbc,pmkToLeft,debugstr_guid(riid),
|
||||
ppvResult);
|
||||
hres = IBindCtx_GetRunningObjectTable(pbc, &obj_tbl);
|
||||
if(SUCCEEDED(hres)) {
|
||||
FIXME("use running object table\n");
|
||||
IRunningObjectTable_Release(obj_tbl);
|
||||
}
|
||||
|
||||
return E_NOTIMPL;
|
||||
return bind_to_object(iface, This->URLName, pbc, riid, ppv);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
|
|
@ -69,6 +69,7 @@ IInternetProtocolInfo *get_protocol_info(LPCWSTR url);
|
|||
HRESULT get_protocol_handler(LPCWSTR url, CLSID *clsid, IClassFactory **ret);
|
||||
|
||||
HRESULT bind_to_storage(LPCWSTR url, IBindCtx *pbc, REFIID riid, void **ppv);
|
||||
HRESULT bind_to_object(IMoniker *mon, LPCWSTR url, IBindCtx *pbc, REFIID riid, void **ppv);
|
||||
|
||||
HRESULT create_binding_protocol(LPCWSTR url, BOOL from_urlmon, IInternetProtocol **protocol);
|
||||
void set_binding_sink(IInternetProtocol *bind_protocol, IInternetProtocolSink *sink);
|
||||
|
|
Loading…
Reference in New Issue