⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 binding.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * Copyright 2005-2007 Jacek Caban for CodeWeavers
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdarg.h>

#define COBJMACROS
#define NONAMELESSUNION
#define NONAMELESSSTRUCT

#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "ole2.h"
#include "urlmon.h"
#include "urlmon_main.h"

#include "wine/debug.h"
#include "wine/unicode.h"

WINE_DEFAULT_DEBUG_CHANNEL(urlmon);

typedef struct Binding Binding;

struct _task_header_t;

typedef void (*task_proc_t)(Binding*, struct _task_header_t*);

typedef struct _task_header_t {
    task_proc_t proc;
    struct _task_header_t *next;
} task_header_t;

typedef struct {
    const IHttpNegotiate2Vtbl *lpHttpNegotiate2Vtbl;

    LONG ref;

    IHttpNegotiate *http_negotiate;
    IHttpNegotiate2 *http_negotiate2;
} HttpNegotiate2Wrapper;

typedef struct {
    const IStreamVtbl *lpStreamVtbl;

    LONG ref;

    IInternetProtocol *protocol;

    BYTE buf[1024*8];
    DWORD buf_size;
    BOOL init_buf;
    HRESULT hres;
} ProtocolStream;

typedef enum {
    BEFORE_DOWNLOAD,
    DOWNLOADING,
    END_DOWNLOAD
} download_state_t;

struct Binding {
    const IBindingVtbl               *lpBindingVtbl;
    const IInternetProtocolSinkVtbl  *lpInternetProtocolSinkVtbl;
    const IInternetBindInfoVtbl      *lpInternetBindInfoVtbl;
    const IServiceProviderVtbl       *lpServiceProviderVtbl;

    LONG ref;

    IBindStatusCallback *callback;
    IInternetProtocol *protocol;
    IServiceProvider *service_provider;
    ProtocolStream *stream;
    HttpNegotiate2Wrapper *httpneg2_wrapper;

    BINDINFO bindinfo;
    DWORD bindf;
    LPWSTR mime;
    LPWSTR url;
    BOOL report_mime;
    DWORD continue_call;
    BOOL request_locked;
    download_state_t download_state;

    DWORD apartment_thread;
    HWND notif_hwnd;

    STGMEDIUM stgmed;

    task_header_t *task_queue_head, *task_queue_tail;
    CRITICAL_SECTION section;
};

#define BINDING(x)   ((IBinding*)               &(x)->lpBindingVtbl)
#define PROTSINK(x)  ((IInternetProtocolSink*)  &(x)->lpInternetProtocolSinkVtbl)
#define BINDINF(x)   ((IInternetBindInfo*)      &(x)->lpInternetBindInfoVtbl)
#define SERVPROV(x)  ((IServiceProvider*)       &(x)->lpServiceProviderVtbl)

#define STREAM(x) ((IStream*) &(x)->lpStreamVtbl)
#define HTTPNEG2(x) ((IHttpNegotiate2*) &(x)->lpHttpNegotiate2Vtbl)

#define WM_MK_CONTINUE   (WM_USER+101)

static void push_task(Binding *binding, task_header_t *task, task_proc_t proc)
{
    task->proc = proc;
    task->next = NULL;

    EnterCriticalSection(&binding->section);

    if(binding->task_queue_tail)
        binding->task_queue_tail->next = task;
    else
        binding->task_queue_tail = binding->task_queue_head = task;

    LeaveCriticalSection(&binding->section);
}

static task_header_t *pop_task(Binding *binding)
{
    task_header_t *ret;

    EnterCriticalSection(&binding->section);

    ret = binding->task_queue_head;
    if(ret) {
        binding->task_queue_head = ret->next;
        if(!binding->task_queue_head)
            binding->task_queue_tail = NULL;
    }

    LeaveCriticalSection(&binding->section);

    return ret;
}

static void fill_stream_buffer(ProtocolStream *This)
{
    DWORD read = 0;

    if(sizeof(This->buf) == This->buf_size)
        return;

    This->hres = IInternetProtocol_Read(This->protocol, This->buf+This->buf_size,
            sizeof(This->buf)-This->buf_size, &read);
    This->buf_size += read;
    if(read > 0)
        This->init_buf = TRUE;
}

static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    if(msg == WM_MK_CONTINUE) {
        Binding *binding = (Binding*)lParam;
        task_header_t *task;

        while((task = pop_task(binding))) {
            binding->continue_call++;
            task->proc(binding, task);
            binding->continue_call--;
        }

        IBinding_Release(BINDING(binding));
        return 0;
    }

    return DefWindowProcW(hwnd, msg, wParam, lParam);
}

static HWND get_notif_hwnd(void)
{
    static ATOM wnd_class = 0;
    HWND hwnd;

    static const WCHAR wszURLMonikerNotificationWindow[] =
        {'U','R','L',' ','M','o','n','i','k','e','r',' ',
         'N','o','t','i','f','i','c','a','t','i','o','n',' ','W','i','n','d','o','w',0};

    if(!wnd_class) {
        static WNDCLASSEXW wndclass = {
            sizeof(wndclass), 0,
            notif_wnd_proc, 0, 0,
            NULL, NULL, NULL, NULL, NULL,
            wszURLMonikerNotificationWindow,
            NULL        
        };

        wndclass.hInstance = URLMON_hInstance;

        wnd_class = RegisterClassExW(&wndclass);
        if (!wnd_class && GetLastError() == ERROR_CLASS_ALREADY_EXISTS)
            wnd_class = 1;
    }

    hwnd = CreateWindowExW(0, wszURLMonikerNotificationWindow,
                           wszURLMonikerNotificationWindow, 0, 0, 0, 0, 0, HWND_MESSAGE,
                           NULL, URLMON_hInstance, NULL);

    TRACE("hwnd = %p\n", hwnd);

    return hwnd;
}

static void dump_BINDINFO(BINDINFO *bi)
{
    static const char * const BINDINFOF_str[] = {
        "#0",
        "BINDINFOF_URLENCODESTGMEDDATA",
        "BINDINFOF_URLENCODEDEXTRAINFO"
    };

    static const char * const BINDVERB_str[] = {
        "BINDVERB_GET",
        "BINDVERB_POST",
        "BINDVERB_PUT",
        "BINDVERB_CUSTOM"
    };

    TRACE("\n"
            "BINDINFO = {\n"
            "    %d, %s,\n"
            "    {%d, %p, %p},\n"
            "    %s,\n"
            "    %s,\n"
            "    %s,\n"
            "    %d, %08x, %d, %d\n"
            "    {%d %p %x},\n"
            "    %s\n"
            "    %p, %d\n"
            "}\n",

            bi->cbSize, debugstr_w(bi->szExtraInfo),
            bi->stgmedData.tymed, bi->stgmedData.u.hGlobal, bi->stgmedData.pUnkForRelease,
            bi->grfBindInfoF > BINDINFOF_URLENCODEDEXTRAINFO
                ? "unknown" : BINDINFOF_str[bi->grfBindInfoF],
            bi->dwBindVerb > BINDVERB_CUSTOM
                ? "unknown" : BINDVERB_str[bi->dwBindVerb],
            debugstr_w(bi->szCustomVerb),
            bi->cbstgmedData, bi->dwOptions, bi->dwOptionsFlags, bi->dwCodePage,
            bi->securityAttributes.nLength,
            bi->securityAttributes.lpSecurityDescriptor,
            bi->securityAttributes.bInheritHandle,
            debugstr_guid(&bi->iid),
            bi->pUnk, bi->dwReserved
            );
}

#define HTTPNEG2_THIS(iface) DEFINE_THIS(HttpNegotiate2Wrapper, HttpNegotiate2, iface)

static HRESULT WINAPI HttpNegotiate2Wrapper_QueryInterface(IHttpNegotiate2 *iface,
                                                          REFIID riid, void **ppv)
{
    HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface);

    *ppv = NULL;

    if(IsEqualGUID(&IID_IUnknown, riid)) {
        TRACE("(IID_IUnknown %p)\n", ppv);
        *ppv = HTTPNEG2(This);
    }else if(IsEqualGUID(&IID_IHttpNegotiate, riid)) {
        TRACE("(IID_IHttpNegotiate %p)\n", ppv);
        *ppv = HTTPNEG2(This);
    }else if(IsEqualGUID(&IID_IHttpNegotiate2, riid)) {
        TRACE("(IID_IHttpNegotiate2 %p)\n", ppv);
        *ppv = HTTPNEG2(This);
    }

    if(*ppv) {
        IHttpNegotiate2_AddRef(HTTPNEG2(This));
        return S_OK;
    }

    WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
    return E_NOINTERFACE;
}

static ULONG WINAPI HttpNegotiate2Wrapper_AddRef(IHttpNegotiate2 *iface)
{
    HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface);
    LONG ref = InterlockedIncrement(&This->ref);

    TRACE("(%p) ref=%d\n", This, ref);

    return ref;
}

static ULONG WINAPI HttpNegotiate2Wrapper_Release(IHttpNegotiate2 *iface)
{
    HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface);
    LONG ref = InterlockedDecrement(&This->ref);

    TRACE("(%p) ref=%d\n", This, ref);

    if(!ref) {
        if (This->http_negotiate)
            IHttpNegotiate_Release(This->http_negotiate);
        if (This->http_negotiate2)
            IHttpNegotiate2_Release(This->http_negotiate2);
        HeapFree(GetProcessHeap(), 0, This);

        URLMON_UnlockModule();
    }

    return ref;
}

static HRESULT WINAPI HttpNegotiate2Wrapper_BeginningTransaction(IHttpNegotiate2 *iface,
        LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
{
    HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface);

    TRACE("(%p)->(%s %s %d %p)\n", This, debugstr_w(szURL), debugstr_w(szHeaders), dwReserved,
          pszAdditionalHeaders);

    if(This->http_negotiate)
        return IHttpNegotiate_BeginningTransaction(This->http_negotiate, szURL, szHeaders,
                                                   dwReserved, pszAdditionalHeaders);

    *pszAdditionalHeaders = NULL;
    return S_OK;
}

static HRESULT WINAPI HttpNegotiate2Wrapper_OnResponse(IHttpNegotiate2 *iface, DWORD dwResponseCode,
        LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders,
        LPWSTR *pszAdditionalRequestHeaders)
{
    HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface);
    LPWSTR szAdditionalRequestHeaders = NULL;
    HRESULT hres = S_OK;

    TRACE("(%p)->(%d %s %s %p)\n", This, dwResponseCode, debugstr_w(szResponseHeaders),
          debugstr_w(szRequestHeaders), pszAdditionalRequestHeaders);

    /* IHttpNegotiate2_OnResponse expects pszAdditionalHeaders to be non-NULL when it is
     * implemented as part of IBindStatusCallback, but it is NULL when called directly from
     * IProtocol */
    if(!pszAdditionalRequestHeaders)
        pszAdditionalRequestHeaders = &szAdditionalRequestHeaders;

    if(This->http_negotiate)
    {
        hres = IHttpNegotiate_OnResponse(This->http_negotiate, dwResponseCode, szResponseHeaders,
                                         szRequestHeaders, pszAdditionalRequestHeaders);
        if(pszAdditionalRequestHeaders == &szAdditionalRequestHeaders &&
           szAdditionalRequestHeaders)
            CoTaskMemFree(szAdditionalRequestHeaders);
    }
    else
    {
        *pszAdditionalRequestHeaders = NULL;
    }

    return hres;
}

static HRESULT WINAPI HttpNegotiate2Wrapper_GetRootSecurityId(IHttpNegotiate2 *iface,
        BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
{
    HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface);

    TRACE("(%p)->(%p %p %ld)\n", This, pbSecurityId, pcbSecurityId, dwReserved);

    if (This->http_negotiate2)
        return IHttpNegotiate2_GetRootSecurityId(This->http_negotiate2, pbSecurityId,
                                                 pcbSecurityId, dwReserved);

    /* That's all we have to do here */
    return E_FAIL;
}

#undef HTTPNEG2_THIS

static const IHttpNegotiate2Vtbl HttpNegotiate2WrapperVtbl = {
    HttpNegotiate2Wrapper_QueryInterface,
    HttpNegotiate2Wrapper_AddRef,
    HttpNegotiate2Wrapper_Release,
    HttpNegotiate2Wrapper_BeginningTransaction,
    HttpNegotiate2Wrapper_OnResponse,
    HttpNegotiate2Wrapper_GetRootSecurityId
};

static HttpNegotiate2Wrapper *create_httpneg2_wrapper(void)
{
    HttpNegotiate2Wrapper *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(HttpNegotiate2Wrapper));

    ret->lpHttpNegotiate2Vtbl = &HttpNegotiate2WrapperVtbl;
    ret->ref = 1;
    ret->http_negotiate = NULL;
    ret->http_negotiate2 = NULL;

    URLMON_LockModule();

    return ret;
}

#define STREAM_THIS(iface) DEFINE_THIS(ProtocolStream, Stream, iface)

static HRESULT WINAPI ProtocolStream_QueryInterface(IStream *iface,
                                                          REFIID riid, void **ppv)
{
    ProtocolStream *This = STREAM_THIS(iface);

    *ppv = NULL;

    if(IsEqualGUID(&IID_IUnknown, riid)) {
        TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
        *ppv = STREAM(This);
    }else if(IsEqualGUID(&IID_ISequentialStream, riid)) {
        TRACE("(%p)->(IID_ISequentialStream %p)\n", This, ppv);
        *ppv = STREAM(This);
    }else if(IsEqualGUID(&IID_IStream, riid)) {
        TRACE("(%p)->(IID_IStream %p)\n", This, ppv);
        *ppv = STREAM(This);
    }

    if(*ppv) {
        IStream_AddRef(STREAM(This));
        return S_OK;
    }

    WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
    return E_NOINTERFACE;
}

static ULONG WINAPI ProtocolStream_AddRef(IStream *iface)
{
    ProtocolStream *This = STREAM_THIS(iface);
    LONG ref = InterlockedIncrement(&This->ref);

    TRACE("(%p) ref=%d\n", This, ref);

    return ref;
}

static ULONG WINAPI ProtocolStream_Release(IStream *iface)
{
    ProtocolStream *This = STREAM_THIS(iface);
    LONG ref = InterlockedDecrement(&This->ref);

    TRACE("(%p) ref=%d\n", This, ref);

    if(!ref) {
        IInternetProtocol_Release(This->protocol);
        HeapFree(GetProcessHeap(), 0, This);

        URLMON_UnlockModule();
    }

    return ref;
}

static HRESULT WINAPI ProtocolStream_Read(IStream *iface, void *pv,
                                         ULONG cb, ULONG *pcbRead)
{
    ProtocolStream *This = STREAM_THIS(iface);
    DWORD read = 0, pread = 0;

    TRACE("(%p)->(%p %d %p)\n", This, pv, cb, pcbRead);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -