📄 binding.c
字号:
}
if(!This->request_locked) {
HRESULT hres = IInternetProtocol_LockRequest(This->protocol, 0);
This->request_locked = SUCCEEDED(hres);
}
fill_stream_buffer(This->stream);
IBindStatusCallback_OnDataAvailable(This->callback, bscf, This->stream->buf_size,
&formatetc, &This->stgmed);
if(This->stream->hres == S_FALSE) {
This->download_state = END_DOWNLOAD;
IBindStatusCallback_OnStopBinding(This->callback, S_OK, NULL);
}
}
typedef struct {
task_header_t header;
DWORD bscf;
ULONG progress;
ULONG progress_max;
} report_data_task_t;
static void report_data_proc(Binding *binding, task_header_t *t)
{
report_data_task_t *task = (report_data_task_t*)t;
report_data(binding, task->bscf, task->progress, task->progress_max);
HeapFree(GetProcessHeap(), 0, task);
}
static HRESULT WINAPI InternetProtocolSink_ReportData(IInternetProtocolSink *iface,
DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
{
Binding *This = PROTSINK_THIS(iface);
TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
if(GetCurrentThreadId() != This->apartment_thread)
FIXME("called from worked hread\n");
if(This->continue_call) {
report_data_task_t *task = HeapAlloc(GetProcessHeap(), 0, sizeof(report_data_task_t));
task->bscf = grfBSCF;
task->progress = ulProgress;
task->progress_max = ulProgressMax;
push_task(This, &task->header, report_data_proc);
}else {
report_data(This, grfBSCF, ulProgress, ulProgressMax);
}
return S_OK;
}
static void report_result_proc(Binding *binding, task_header_t *t)
{
IInternetProtocol_Terminate(binding->protocol, 0);
if(binding->request_locked) {
IInternetProtocol_UnlockRequest(binding->protocol);
binding->request_locked = FALSE;
}
HeapFree(GetProcessHeap(), 0, t);
}
static HRESULT WINAPI InternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
{
Binding *This = PROTSINK_THIS(iface);
TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
if(GetCurrentThreadId() == This->apartment_thread && !This->continue_call) {
IInternetProtocol_Terminate(This->protocol, 0);
}else {
task_header_t *task = HeapAlloc(GetProcessHeap(), 0, sizeof(task_header_t));
push_task(This, task, report_result_proc);
}
return S_OK;
}
#undef PROTSINK_THIS
static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
InternetProtocolSink_QueryInterface,
InternetProtocolSink_AddRef,
InternetProtocolSink_Release,
InternetProtocolSink_Switch,
InternetProtocolSink_ReportProgress,
InternetProtocolSink_ReportData,
InternetProtocolSink_ReportResult
};
#define BINDINF_THIS(iface) DEFINE_THIS(Binding, InternetBindInfo, iface)
static HRESULT WINAPI InternetBindInfo_QueryInterface(IInternetBindInfo *iface,
REFIID riid, void **ppv)
{
Binding *This = BINDINF_THIS(iface);
return IBinding_QueryInterface(BINDING(This), riid, ppv);
}
static ULONG WINAPI InternetBindInfo_AddRef(IInternetBindInfo *iface)
{
Binding *This = BINDINF_THIS(iface);
return IBinding_AddRef(BINDING(This));
}
static ULONG WINAPI InternetBindInfo_Release(IInternetBindInfo *iface)
{
Binding *This = BINDINF_THIS(iface);
return IBinding_Release(BINDING(This));
}
static HRESULT WINAPI InternetBindInfo_GetBindInfo(IInternetBindInfo *iface,
DWORD *grfBINDF, BINDINFO *pbindinfo)
{
Binding *This = BINDINF_THIS(iface);
TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
*grfBINDF = This->bindf;
memcpy(pbindinfo, &This->bindinfo, sizeof(BINDINFO));
if(pbindinfo->szExtraInfo || pbindinfo->szCustomVerb)
FIXME("copy strings\n");
if(pbindinfo->stgmedData.pUnkForRelease)
IUnknown_AddRef(pbindinfo->stgmedData.pUnkForRelease);
if(pbindinfo->pUnk)
IUnknown_AddRef(pbindinfo->pUnk);
return S_OK;
}
static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface,
ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
{
Binding *This = BINDINF_THIS(iface);
TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
switch(ulStringType) {
case BINDSTRING_ACCEPT_MIMES: {
static const WCHAR wszMimes[] = {'*','/','*',0};
if(!ppwzStr || !pcElFetched)
return E_INVALIDARG;
ppwzStr[0] = CoTaskMemAlloc(sizeof(wszMimes));
memcpy(ppwzStr[0], wszMimes, sizeof(wszMimes));
*pcElFetched = 1;
return S_OK;
}
case BINDSTRING_USER_AGENT: {
IInternetBindInfo *bindinfo = NULL;
HRESULT hres;
hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetBindInfo,
(void**)&bindinfo);
if(FAILED(hres))
return hres;
hres = IInternetBindInfo_GetBindString(bindinfo, ulStringType, ppwzStr,
cEl, pcElFetched);
IInternetBindInfo_Release(bindinfo);
return hres;
}
}
FIXME("not supported string type %d\n", ulStringType);
return E_NOTIMPL;
}
#undef BINDF_THIS
static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
InternetBindInfo_QueryInterface,
InternetBindInfo_AddRef,
InternetBindInfo_Release,
InternetBindInfo_GetBindInfo,
InternetBindInfo_GetBindString
};
#define SERVPROV_THIS(iface) DEFINE_THIS(Binding, ServiceProvider, iface)
static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface,
REFIID riid, void **ppv)
{
Binding *This = SERVPROV_THIS(iface);
return IBinding_QueryInterface(BINDING(This), riid, ppv);
}
static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
{
Binding *This = SERVPROV_THIS(iface);
return IBinding_AddRef(BINDING(This));
}
static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
{
Binding *This = SERVPROV_THIS(iface);
return IBinding_Release(BINDING(This));
}
static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
REFGUID guidService, REFIID riid, void **ppv)
{
Binding *This = SERVPROV_THIS(iface);
HRESULT hres;
TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
if(This->service_provider) {
hres = IServiceProvider_QueryService(This->service_provider, guidService,
riid, ppv);
if(SUCCEEDED(hres))
return hres;
}
if(IsEqualGUID(&IID_IHttpNegotiate, guidService)
|| IsEqualGUID(&IID_IHttpNegotiate2, guidService)) {
if(!This->httpneg2_wrapper) {
WARN("HttpNegotiate2Wrapper expected to be non-NULL\n");
} else {
if(IsEqualGUID(&IID_IHttpNegotiate, guidService))
IBindStatusCallback_QueryInterface(This->callback, riid,
(void **)&This->httpneg2_wrapper->http_negotiate);
else
IBindStatusCallback_QueryInterface(This->callback, riid,
(void **)&This->httpneg2_wrapper->http_negotiate2);
return IHttpNegotiate2_QueryInterface(HTTPNEG2(This->httpneg2_wrapper), riid, ppv);
}
}
WARN("unknown service %s\n", debugstr_guid(guidService));
return E_NOTIMPL;
}
#undef SERVPROV_THIS
static const IServiceProviderVtbl ServiceProviderVtbl = {
ServiceProvider_QueryInterface,
ServiceProvider_AddRef,
ServiceProvider_Release,
ServiceProvider_QueryService
};
static HRESULT get_callback(IBindCtx *pbc, IBindStatusCallback **callback)
{
HRESULT hres;
static WCHAR wszBSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
hres = IBindCtx_GetObjectParam(pbc, wszBSCBHolder, (IUnknown**)callback);
if(FAILED(hres))
return MK_E_SYNTAX;
return S_OK;
}
static HRESULT get_protocol(Binding *This, LPCWSTR url)
{
IClassFactory *cf = NULL;
HRESULT hres;
hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetProtocol,
(void**)&This->protocol);
if(SUCCEEDED(hres))
return S_OK;
if(This->service_provider) {
hres = IServiceProvider_QueryService(This->service_provider, &IID_IInternetProtocol,
&IID_IInternetProtocol, (void**)&This->protocol);
if(SUCCEEDED(hres))
return S_OK;
}
hres = get_protocol_handler(url, NULL, &cf);
if(FAILED(hres))
return hres;
hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&This->protocol);
IClassFactory_Release(cf);
return hres;
}
static BOOL is_urlmon_protocol(LPCWSTR url)
{
static const WCHAR wszCdl[] = {'c','d','l'};
static const WCHAR wszFile[] = {'f','i','l','e'};
static const WCHAR wszFtp[] = {'f','t','p'};
static const WCHAR wszGopher[] = {'g','o','p','h','e','r'};
static const WCHAR wszHttp[] = {'h','t','t','p'};
static const WCHAR wszHttps[] = {'h','t','t','p','s'};
static const WCHAR wszMk[] = {'m','k'};
static const struct {
LPCWSTR scheme;
int len;
} protocol_list[] = {
{wszCdl, sizeof(wszCdl) /sizeof(WCHAR)},
{wszFile, sizeof(wszFile) /sizeof(WCHAR)},
{wszFtp, sizeof(wszFtp) /sizeof(WCHAR)},
{wszGopher, sizeof(wszGopher)/sizeof(WCHAR)},
{wszHttp, sizeof(wszHttp) /sizeof(WCHAR)},
{wszHttps, sizeof(wszHttps) /sizeof(WCHAR)},
{wszMk, sizeof(wszMk) /sizeof(WCHAR)}
};
int i, len = strlenW(url);
for(i=0; i < sizeof(protocol_list)/sizeof(protocol_list[0]); i++) {
if(len >= protocol_list[i].len
&& !memcmp(url, protocol_list[i].scheme, protocol_list[i].len*sizeof(WCHAR)))
return TRUE;
}
return FALSE;
}
static HRESULT Binding_Create(LPCWSTR url, IBindCtx *pbc, REFIID riid, Binding **binding)
{
Binding *ret;
int len;
HRESULT hres;
if(!IsEqualGUID(&IID_IStream, riid)) {
FIXME("Unsupported riid %s\n", debugstr_guid(riid));
return E_NOTIMPL;
}
URLMON_LockModule();
ret = HeapAlloc(GetProcessHeap(), 0, sizeof(Binding));
ret->lpBindingVtbl = &BindingVtbl;
ret->lpInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl;
ret->lpInternetBindInfoVtbl = &InternetBindInfoVtbl;
ret->lpServiceProviderVtbl = &ServiceProviderVtbl;
ret->ref = 1;
ret->callback = NULL;
ret->protocol = NULL;
ret->service_provider = NULL;
ret->stream = NULL;
ret->httpneg2_wrapper = NULL;
ret->mime = NULL;
ret->url = NULL;
ret->apartment_thread = GetCurrentThreadId();
ret->notif_hwnd = get_notif_hwnd();
ret->report_mime = TRUE;
ret->continue_call = 0;
ret->request_locked = FALSE;
ret->download_state = BEFORE_DOWNLOAD;
ret->task_queue_head = ret->task_queue_tail = NULL;
memset(&ret->bindinfo, 0, sizeof(BINDINFO));
ret->bindinfo.cbSize = sizeof(BINDINFO);
ret->bindf = 0;
InitializeCriticalSection(&ret->section);
ret->section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": Binding.section");
hres = get_callback(pbc, &ret->callback);
if(FAILED(hres)) {
WARN("Could not get IBindStatusCallback\n");
IBinding_Release(BINDING(ret));
return hres;
}
IBindStatusCallback_QueryInterface(ret->callback, &IID_IServiceProvider,
(void**)&ret->service_provider);
hres = get_protocol(ret, url);
if(FAILED(hres)) {
WARN("Could not get protocol handler\n");
IBinding_Release(BINDING(ret));
return hres;
}
hres = IBindStatusCallback_GetBindInfo(ret->callback, &ret->bindf, &ret->bindinfo);
if(FAILED(hres)) {
WARN("GetBindInfo failed: %08x\n", hres);
IBinding_Release(BINDING(ret));
return hres;
}
dump_BINDINFO(&ret->bindinfo);
ret->bindf |= BINDF_FROMURLMON;
if(!is_urlmon_protocol(url))
ret->bindf |= BINDF_NEEDFILE;
len = strlenW(url)+1;
ret->url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
memcpy(ret->url, url, len*sizeof(WCHAR));
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 */
ret->httpneg2_wrapper = create_httpneg2_wrapper();
*binding = ret;
return S_OK;
}
HRESULT start_binding(LPCWSTR url, IBindCtx *pbc, REFIID riid, void **ppv)
{
Binding *binding = NULL;
HRESULT hres;
*ppv = NULL;
hres = Binding_Create(url, pbc, riid, &binding);
if(FAILED(hres))
return hres;
hres = IBindStatusCallback_OnStartBinding(binding->callback, 0, BINDING(binding));
if(FAILED(hres)) {
WARN("OnStartBinding failed: %08x\n", hres);
IBindStatusCallback_OnStopBinding(binding->callback, 0x800c0008, NULL);
IBinding_Release(BINDING(binding));
return hres;
}
hres = IInternetProtocol_Start(binding->protocol, url, PROTSINK(binding),
BINDINF(binding), 0, 0);
if(FAILED(hres)) {
WARN("Start failed: %08x\n", hres);
IInternetProtocol_Terminate(binding->protocol, 0);
IBindStatusCallback_OnStopBinding(binding->callback, S_OK, NULL);
IBinding_Release(BINDING(binding));
return hres;
}
if(binding->stream->init_buf) {
if(binding->request_locked)
IInternetProtocol_UnlockRequest(binding->protocol);
IStream_AddRef(STREAM(binding->stream));
*ppv = binding->stream;
hres = S_OK;
}else {
hres = MK_S_ASYNCHRONOUS;
}
IBinding_Release(BINDING(binding));
return hres;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -