urlmon: Added BindToObject implementation.

This commit is contained in:
Jacek Caban 2007-12-30 17:45:00 +01:00 committed by Alexandre Julliard
parent a16ae2e8f2
commit 85f472b37d
4 changed files with 228 additions and 32 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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);
}
/******************************************************************************

View File

@ -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);