- Sync msctf, mshtml and msxml3 with Wine 1.1.29
authorDmitry Chapyshev <dmitry@reactos.org>
Sat, 5 Sep 2009 15:02:49 +0000 (15:02 +0000)
committerDmitry Chapyshev <dmitry@reactos.org>
Sat, 5 Sep 2009 15:02:49 +0000 (15:02 +0000)
svn path=/trunk/; revision=42994

47 files changed:
reactos/dll/win32/msctf/compartmentmgr.c [new file with mode: 0644]
reactos/dll/win32/msctf/context.c
reactos/dll/win32/msctf/documentmgr.c
reactos/dll/win32/msctf/inputprocessor.c
reactos/dll/win32/msctf/msctf.c
reactos/dll/win32/msctf/msctf.rbuild
reactos/dll/win32/msctf/msctf.spec
reactos/dll/win32/msctf/msctf_internal.h
reactos/dll/win32/msctf/range.c
reactos/dll/win32/msctf/textstor_local.idl [new file with mode: 0644]
reactos/dll/win32/msctf/threadmgr.c
reactos/dll/win32/mshtml/dispex.c
reactos/dll/win32/mshtml/htmlcurstyle.c
reactos/dll/win32/mshtml/htmldoc.c
reactos/dll/win32/mshtml/htmlelem.c
reactos/dll/win32/mshtml/htmlelemcol.c
reactos/dll/win32/mshtml/htmlevent.c
reactos/dll/win32/mshtml/htmlinput.c
reactos/dll/win32/mshtml/htmllocation.c
reactos/dll/win32/mshtml/htmlnode.c
reactos/dll/win32/mshtml/htmlstyle.c
reactos/dll/win32/mshtml/htmlstyle.h
reactos/dll/win32/mshtml/htmlwindow.c
reactos/dll/win32/mshtml/mshtml.rbuild
reactos/dll/win32/mshtml/mshtml_private.h
reactos/dll/win32/mshtml/mutation.c
reactos/dll/win32/mshtml/navigate.c
reactos/dll/win32/mshtml/nsembed.c
reactos/dll/win32/mshtml/nsevents.c
reactos/dll/win32/mshtml/nsiface.idl
reactos/dll/win32/mshtml/nsio.c
reactos/dll/win32/mshtml/omnavigator.c
reactos/dll/win32/mshtml/persist.c
reactos/dll/win32/mshtml/script.c
reactos/dll/win32/msxml3/attribute.c
reactos/dll/win32/msxml3/cdata.c
reactos/dll/win32/msxml3/comment.c
reactos/dll/win32/msxml3/dispex.c
reactos/dll/win32/msxml3/docfrag.c
reactos/dll/win32/msxml3/domdoc.c
reactos/dll/win32/msxml3/element.c
reactos/dll/win32/msxml3/entityref.c
reactos/dll/win32/msxml3/msxml_private.h
reactos/dll/win32/msxml3/node.c
reactos/dll/win32/msxml3/pi.c
reactos/dll/win32/msxml3/queryresult.c
reactos/dll/win32/msxml3/text.c

diff --git a/reactos/dll/win32/msctf/compartmentmgr.c b/reactos/dll/win32/msctf/compartmentmgr.c
new file mode 100644 (file)
index 0000000..06a691d
--- /dev/null
@@ -0,0 +1,660 @@
+/*
+ *  ITfCompartmentMgr implementation
+ *
+ *  Copyright 2009 Aric Stewart, 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 "config.h"
+
+#include <stdarg.h>
+
+#define COBJMACROS
+
+#include "wine/debug.h"
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "winuser.h"
+#include "shlwapi.h"
+#include "winerror.h"
+#include "objbase.h"
+#include "oleauto.h"
+#include "olectl.h"
+
+#include "wine/unicode.h"
+#include "wine/list.h"
+
+#include "msctf.h"
+#include "msctf_internal.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msctf);
+
+typedef struct tagCompartmentValue {
+    struct list entry;
+    GUID guid;
+    TfClientId owner;
+    ITfCompartment *compartment;
+} CompartmentValue;
+
+typedef struct tagCompartmentMgr {
+    const ITfCompartmentMgrVtbl *CompartmentMgrVtbl;
+    LONG refCount;
+
+    IUnknown *pUnkOuter;
+
+    struct list values;
+} CompartmentMgr;
+
+typedef struct tagCompartmentEnumGuid {
+    const IEnumGUIDVtbl *Vtbl;
+    LONG refCount;
+
+    struct list *values;
+    struct list *cursor;
+} CompartmentEnumGuid;
+
+
+typedef struct tagCompartmentSink {
+    struct list         entry;
+    union {
+        IUnknown            *pIUnknown;
+        ITfCompartmentEventSink *pITfCompartmentEventSink;
+    } interfaces;
+} CompartmentSink;
+
+typedef struct tagCompartment {
+    const ITfCompartmentVtbl *Vtbl;
+    const ITfSourceVtbl *SourceVtbl;
+    LONG refCount;
+
+    /* Only VT_I4, VT_UNKNOWN and VT_BSTR data types are allowed */
+    VARIANT variant;
+    CompartmentValue *valueData;
+    struct list CompartmentEventSink;
+} Compartment;
+
+static HRESULT CompartmentEnumGuid_Constructor(struct list* values, IEnumGUID **ppOut);
+static HRESULT Compartment_Constructor(CompartmentValue *value, ITfCompartment **ppOut);
+
+static inline Compartment *impl_from_ITfSourceVtbl(ITfSource *iface)
+{
+    return (Compartment *)((char *)iface - FIELD_OFFSET(Compartment,SourceVtbl));
+}
+
+HRESULT CompartmentMgr_Destructor(ITfCompartmentMgr *iface)
+{
+    CompartmentMgr *This = (CompartmentMgr *)iface;
+    struct list *cursor, *cursor2;
+
+    LIST_FOR_EACH_SAFE(cursor, cursor2, &This->values)
+    {
+        CompartmentValue* value = LIST_ENTRY(cursor,CompartmentValue,entry);
+        list_remove(cursor);
+        ITfCompartment_Release(value->compartment);
+        HeapFree(GetProcessHeap(),0,value);
+    }
+
+    HeapFree(GetProcessHeap(),0,This);
+    return S_OK;
+}
+
+/*****************************************************
+ * ITfCompartmentMgr functions
+ *****************************************************/
+static HRESULT WINAPI CompartmentMgr_QueryInterface(ITfCompartmentMgr *iface, REFIID iid, LPVOID *ppvOut)
+{
+    CompartmentMgr *This = (CompartmentMgr *)iface;
+    if (This->pUnkOuter)
+        return IUnknown_QueryInterface(This->pUnkOuter, iid, *ppvOut);
+    else
+    {
+        *ppvOut = NULL;
+
+        if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfCompartmentMgr))
+        {
+            *ppvOut = This;
+        }
+
+        if (*ppvOut)
+        {
+            IUnknown_AddRef(iface);
+            return S_OK;
+        }
+
+        WARN("unsupported interface: %s\n", debugstr_guid(iid));
+        return E_NOINTERFACE;
+    }
+}
+
+static ULONG WINAPI CompartmentMgr_AddRef(ITfCompartmentMgr *iface)
+{
+    CompartmentMgr *This = (CompartmentMgr *)iface;
+    if (This->pUnkOuter)
+        return IUnknown_AddRef(This->pUnkOuter);
+    else
+        return InterlockedIncrement(&This->refCount);
+}
+
+static ULONG WINAPI CompartmentMgr_Release(ITfCompartmentMgr *iface)
+{
+    CompartmentMgr *This = (CompartmentMgr *)iface;
+    if (This->pUnkOuter)
+        return IUnknown_Release(This->pUnkOuter);
+    else
+    {
+        ULONG ret;
+
+        ret = InterlockedDecrement(&This->refCount);
+        if (ret == 0)
+            CompartmentMgr_Destructor(iface);
+        return ret;
+    }
+}
+
+static HRESULT WINAPI CompartmentMgr_GetCompartment(ITfCompartmentMgr *iface,
+        REFGUID rguid, ITfCompartment **ppcomp)
+{
+    CompartmentMgr *This = (CompartmentMgr *)iface;
+    CompartmentValue* value;
+    struct list *cursor;
+    HRESULT hr;
+
+    TRACE("(%p) %s  %p\n",This,debugstr_guid(rguid),ppcomp);
+
+    LIST_FOR_EACH(cursor, &This->values)
+    {
+        value = LIST_ENTRY(cursor,CompartmentValue,entry);
+        if (IsEqualGUID(rguid,&value->guid))
+        {
+            ITfCompartment_AddRef(value->compartment);
+            *ppcomp = value->compartment;
+            return S_OK;
+        }
+    }
+
+    value = HeapAlloc(GetProcessHeap(),0,sizeof(CompartmentValue));
+    value->guid = *rguid;
+    value->owner = 0;
+    hr = Compartment_Constructor(value,&value->compartment);
+    if (SUCCEEDED(hr))
+    {
+        list_add_head(&This->values,&value->entry);
+        ITfCompartment_AddRef(value->compartment);
+        *ppcomp = value->compartment;
+    }
+    else
+    {
+        HeapFree(GetProcessHeap(),0,value);
+        *ppcomp = NULL;
+    }
+    return hr;
+}
+
+static HRESULT WINAPI CompartmentMgr_ClearCompartment(ITfCompartmentMgr *iface,
+    TfClientId tid, REFGUID rguid)
+{
+    struct list *cursor;
+    CompartmentMgr *This = (CompartmentMgr *)iface;
+    TRACE("(%p) %i %s\n",This,tid,debugstr_guid(rguid));
+
+    LIST_FOR_EACH(cursor, &This->values)
+    {
+        CompartmentValue* value = LIST_ENTRY(cursor,CompartmentValue,entry);
+        if (IsEqualGUID(rguid,&value->guid))
+        {
+            if (value->owner && tid != value->owner)
+                return E_UNEXPECTED;
+            list_remove(cursor);
+            ITfCompartment_Release(value->compartment);
+            HeapFree(GetProcessHeap(),0,value);
+            return S_OK;
+        }
+    }
+
+    return CONNECT_E_NOCONNECTION;
+}
+
+static HRESULT WINAPI CompartmentMgr_EnumCompartments(ITfCompartmentMgr *iface,
+ IEnumGUID **ppEnum)
+{
+    CompartmentMgr *This = (CompartmentMgr *)iface;
+    TRACE("(%p) %p\n",This,ppEnum);
+    if (!ppEnum)
+        return E_INVALIDARG;
+    return CompartmentEnumGuid_Constructor(&This->values, ppEnum);
+}
+
+static const ITfCompartmentMgrVtbl CompartmentMgr_CompartmentMgrVtbl =
+{
+    CompartmentMgr_QueryInterface,
+    CompartmentMgr_AddRef,
+    CompartmentMgr_Release,
+
+    CompartmentMgr_GetCompartment,
+    CompartmentMgr_ClearCompartment,
+    CompartmentMgr_EnumCompartments
+};
+
+HRESULT CompartmentMgr_Constructor(IUnknown *pUnkOuter, REFIID riid, IUnknown **ppOut)
+{
+    CompartmentMgr *This;
+
+    if (!ppOut)
+        return E_POINTER;
+
+    if (pUnkOuter && !IsEqualIID (riid, &IID_IUnknown))
+        return CLASS_E_NOAGGREGATION;
+
+    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CompartmentMgr));
+    if (This == NULL)
+        return E_OUTOFMEMORY;
+
+    This->CompartmentMgrVtbl = &CompartmentMgr_CompartmentMgrVtbl;
+    This->pUnkOuter = pUnkOuter;
+    list_init(&This->values);
+
+    if (pUnkOuter)
+    {
+        TRACE("returning %p\n", This);
+        *ppOut = (IUnknown*)This;
+        return S_OK;
+    }
+    else
+    {
+        HRESULT hr;
+        hr = IUnknown_QueryInterface((IUnknown*)This, riid, (LPVOID*)ppOut);
+        if (FAILED(hr))
+            HeapFree(GetProcessHeap(),0,This);
+        return hr;
+    }
+}
+
+/**************************************************
+ * IEnumGUID implementaion for ITfCompartmentMgr::EnumCompartments
+ **************************************************/
+static void CompartmentEnumGuid_Destructor(CompartmentEnumGuid *This)
+{
+    TRACE("destroying %p\n", This);
+    HeapFree(GetProcessHeap(),0,This);
+}
+
+static HRESULT WINAPI CompartmentEnumGuid_QueryInterface(IEnumGUID *iface, REFIID iid, LPVOID *ppvOut)
+{
+    CompartmentEnumGuid *This = (CompartmentEnumGuid *)iface;
+    *ppvOut = NULL;
+
+    if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumGUID))
+    {
+        *ppvOut = This;
+    }
+
+    if (*ppvOut)
+    {
+        IUnknown_AddRef(iface);
+        return S_OK;
+    }
+
+    WARN("unsupported interface: %s\n", debugstr_guid(iid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI CompartmentEnumGuid_AddRef(IEnumGUID *iface)
+{
+    CompartmentEnumGuid *This = (CompartmentEnumGuid*)iface;
+    return InterlockedIncrement(&This->refCount);
+}
+
+static ULONG WINAPI CompartmentEnumGuid_Release(IEnumGUID *iface)
+{
+    CompartmentEnumGuid *This = (CompartmentEnumGuid *)iface;
+    ULONG ret;
+
+    ret = InterlockedDecrement(&This->refCount);
+    if (ret == 0)
+        CompartmentEnumGuid_Destructor(This);
+    return ret;
+}
+
+/*****************************************************
+ * IEnumGuid functions
+ *****************************************************/
+static HRESULT WINAPI CompartmentEnumGuid_Next( LPENUMGUID iface,
+    ULONG celt, GUID *rgelt, ULONG *pceltFetched)
+{
+    CompartmentEnumGuid *This = (CompartmentEnumGuid *)iface;
+    ULONG fetched = 0;
+
+    TRACE("(%p)\n",This);
+
+    if (rgelt == NULL) return E_POINTER;
+
+    while (fetched < celt && This->cursor)
+    {
+        CompartmentValue* value = LIST_ENTRY(This->cursor,CompartmentValue,entry);
+        if (!value)
+            break;
+
+        This->cursor = list_next(This->values,This->cursor);
+        *rgelt = value->guid;
+
+        ++fetched;
+        ++rgelt;
+    }
+
+    if (pceltFetched) *pceltFetched = fetched;
+    return fetched == celt ? S_OK : S_FALSE;
+}
+
+static HRESULT WINAPI CompartmentEnumGuid_Skip( LPENUMGUID iface, ULONG celt)
+{
+    CompartmentEnumGuid *This = (CompartmentEnumGuid *)iface;
+    TRACE("(%p)\n",This);
+
+    This->cursor = list_next(This->values,This->cursor);
+    return S_OK;
+}
+
+static HRESULT WINAPI CompartmentEnumGuid_Reset( LPENUMGUID iface)
+{
+    CompartmentEnumGuid *This = (CompartmentEnumGuid *)iface;
+    TRACE("(%p)\n",This);
+    This->cursor = list_head(This->values);
+    return S_OK;
+}
+
+static HRESULT WINAPI CompartmentEnumGuid_Clone( LPENUMGUID iface,
+    IEnumGUID **ppenum)
+{
+    CompartmentEnumGuid *This = (CompartmentEnumGuid *)iface;
+    HRESULT res;
+
+    TRACE("(%p)\n",This);
+
+    if (ppenum == NULL) return E_POINTER;
+
+    res = CompartmentEnumGuid_Constructor(This->values, ppenum);
+    if (SUCCEEDED(res))
+    {
+        CompartmentEnumGuid *new_This = (CompartmentEnumGuid *)*ppenum;
+        new_This->cursor = This->cursor;
+    }
+    return res;
+}
+
+static const IEnumGUIDVtbl IEnumGUID_Vtbl ={
+    CompartmentEnumGuid_QueryInterface,
+    CompartmentEnumGuid_AddRef,
+    CompartmentEnumGuid_Release,
+
+    CompartmentEnumGuid_Next,
+    CompartmentEnumGuid_Skip,
+    CompartmentEnumGuid_Reset,
+    CompartmentEnumGuid_Clone
+};
+
+static HRESULT CompartmentEnumGuid_Constructor(struct list *values, IEnumGUID **ppOut)
+{
+    CompartmentEnumGuid *This;
+
+    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CompartmentEnumGuid));
+    if (This == NULL)
+        return E_OUTOFMEMORY;
+
+    This->Vtbl= &IEnumGUID_Vtbl;
+    This->refCount = 1;
+
+    This->values = values;
+    This->cursor = list_head(values);
+
+    TRACE("returning %p\n", This);
+    *ppOut = (IEnumGUID*)This;
+    return S_OK;
+}
+
+/**************************************************
+ * ITfCompartment
+ **************************************************/
+static void free_sink(CompartmentSink *sink)
+{
+        IUnknown_Release(sink->interfaces.pIUnknown);
+        HeapFree(GetProcessHeap(),0,sink);
+}
+
+static void Compartment_Destructor(Compartment *This)
+{
+    struct list *cursor, *cursor2;
+    TRACE("destroying %p\n", This);
+    VariantClear(&This->variant);
+    LIST_FOR_EACH_SAFE(cursor, cursor2, &This->CompartmentEventSink)
+    {
+        CompartmentSink* sink = LIST_ENTRY(cursor,CompartmentSink,entry);
+        list_remove(cursor);
+        free_sink(sink);
+    }
+    HeapFree(GetProcessHeap(),0,This);
+}
+
+static HRESULT WINAPI Compartment_QueryInterface(ITfCompartment *iface, REFIID iid, LPVOID *ppvOut)
+{
+    Compartment *This = (Compartment *)iface;
+    *ppvOut = NULL;
+
+    if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfCompartment))
+    {
+        *ppvOut = This;
+    }
+    else if (IsEqualIID(iid, &IID_ITfSource))
+    {
+        *ppvOut = &This->SourceVtbl;
+    }
+
+    if (*ppvOut)
+    {
+        IUnknown_AddRef(iface);
+        return S_OK;
+    }
+
+    WARN("unsupported interface: %s\n", debugstr_guid(iid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI Compartment_AddRef(ITfCompartment *iface)
+{
+    Compartment *This = (Compartment*)iface;
+    return InterlockedIncrement(&This->refCount);
+}
+
+static ULONG WINAPI Compartment_Release(ITfCompartment *iface)
+{
+    Compartment *This = (Compartment *)iface;
+    ULONG ret;
+
+    ret = InterlockedDecrement(&This->refCount);
+    if (ret == 0)
+        Compartment_Destructor(This);
+    return ret;
+}
+
+static HRESULT WINAPI Compartment_SetValue(ITfCompartment *iface,
+    TfClientId tid, const VARIANT *pvarValue)
+{
+    Compartment *This = (Compartment *)iface;
+    struct list *cursor;
+
+    TRACE("(%p) %i %p\n",This,tid,pvarValue);
+
+    if (!pvarValue)
+        return E_INVALIDARG;
+
+    if (!(V_VT(pvarValue) == VT_BSTR || V_VT(pvarValue) == VT_I4 ||
+          V_VT(pvarValue) == VT_UNKNOWN))
+        return E_INVALIDARG;
+
+    if (!This->valueData->owner)
+        This->valueData->owner = tid;
+
+    VariantClear(&This->variant);
+
+    /* Shallow copy of value and type */
+    This->variant = *pvarValue;
+
+    if (V_VT(pvarValue) == VT_BSTR)
+        V_BSTR(&This->variant) = SysAllocStringByteLen((char*)V_BSTR(pvarValue),
+                SysStringByteLen(V_BSTR(pvarValue)));
+    else if (V_VT(pvarValue) == VT_UNKNOWN)
+        IUnknown_AddRef(V_UNKNOWN(&This->variant));
+
+    LIST_FOR_EACH(cursor, &This->CompartmentEventSink)
+    {
+        CompartmentSink* sink = LIST_ENTRY(cursor,CompartmentSink,entry);
+        ITfCompartmentEventSink_OnChange(sink->interfaces.pITfCompartmentEventSink,&This->valueData->guid);
+    }
+
+    return S_OK;
+}
+
+static HRESULT WINAPI Compartment_GetValue(ITfCompartment *iface,
+    VARIANT *pvarValue)
+{
+    Compartment *This = (Compartment *)iface;
+    TRACE("(%p) %p\n",This, pvarValue);
+
+    if (!pvarValue)
+        return E_INVALIDARG;
+
+    VariantInit(pvarValue);
+    if (V_VT(&This->variant) == VT_EMPTY) return S_FALSE;
+    return VariantCopy(pvarValue,&This->variant);
+}
+
+static const ITfCompartmentVtbl ITfCompartment_Vtbl ={
+    Compartment_QueryInterface,
+    Compartment_AddRef,
+    Compartment_Release,
+
+    Compartment_SetValue,
+    Compartment_GetValue
+};
+
+/*****************************************************
+ * ITfSource functions
+ *****************************************************/
+
+static HRESULT WINAPI Source_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut)
+{
+    Compartment *This = impl_from_ITfSourceVtbl(iface);
+    return Compartment_QueryInterface((ITfCompartment *)This, iid, *ppvOut);
+}
+
+static ULONG WINAPI Source_AddRef(ITfSource *iface)
+{
+    Compartment *This = impl_from_ITfSourceVtbl(iface);
+    return Compartment_AddRef((ITfCompartment*)This);
+}
+
+static ULONG WINAPI Source_Release(ITfSource *iface)
+{
+    Compartment *This = impl_from_ITfSourceVtbl(iface);
+    return Compartment_Release((ITfCompartment *)This);
+}
+
+static WINAPI HRESULT CompartmentSource_AdviseSink(ITfSource *iface,
+        REFIID riid, IUnknown *punk, DWORD *pdwCookie)
+{
+    CompartmentSink *cs;
+    Compartment *This = impl_from_ITfSourceVtbl(iface);
+
+    TRACE("(%p) %s %p %p\n",This,debugstr_guid(riid),punk,pdwCookie);
+
+    if (!riid || !punk || !pdwCookie)
+        return E_INVALIDARG;
+
+    if (IsEqualIID(riid, &IID_ITfCompartmentEventSink))
+    {
+        cs = HeapAlloc(GetProcessHeap(),0,sizeof(CompartmentSink));
+        if (!cs)
+            return E_OUTOFMEMORY;
+        if (FAILED(IUnknown_QueryInterface(punk, riid, (LPVOID *)&cs->interfaces.pITfCompartmentEventSink)))
+        {
+            HeapFree(GetProcessHeap(),0,cs);
+            return CONNECT_E_CANNOTCONNECT;
+        }
+        list_add_head(&This->CompartmentEventSink,&cs->entry);
+        *pdwCookie = generate_Cookie(COOKIE_MAGIC_COMPARTMENTSINK , cs);
+    }
+    else
+    {
+        FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid));
+        return E_NOTIMPL;
+    }
+
+    TRACE("cookie %x\n",*pdwCookie);
+
+    return S_OK;
+}
+
+static WINAPI HRESULT CompartmentSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie)
+{
+    CompartmentSink *sink;
+    Compartment *This = impl_from_ITfSourceVtbl(iface);
+
+    TRACE("(%p) %x\n",This,pdwCookie);
+
+    if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_COMPARTMENTSINK)
+        return E_INVALIDARG;
+
+    sink = (CompartmentSink*)remove_Cookie(pdwCookie);
+    if (!sink)
+        return CONNECT_E_NOCONNECTION;
+
+    list_remove(&sink->entry);
+    free_sink(sink);
+
+    return S_OK;
+}
+
+static const ITfSourceVtbl Compartment_SourceVtbl =
+{
+    Source_QueryInterface,
+    Source_AddRef,
+    Source_Release,
+
+    CompartmentSource_AdviseSink,
+    CompartmentSource_UnadviseSink,
+};
+
+static HRESULT Compartment_Constructor(CompartmentValue *valueData, ITfCompartment **ppOut)
+{
+    Compartment *This;
+
+    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(Compartment));
+    if (This == NULL)
+        return E_OUTOFMEMORY;
+
+    This->Vtbl= &ITfCompartment_Vtbl;
+    This->SourceVtbl = &Compartment_SourceVtbl;
+    This->refCount = 1;
+
+    This->valueData = valueData;
+    VariantInit(&This->variant);
+
+    list_init(&This->CompartmentEventSink);
+
+    TRACE("returning %p\n", This);
+    *ppOut = (ITfCompartment*)This;
+    return S_OK;
+}
index 8e14a72..c13235c 100644 (file)
@@ -61,15 +61,20 @@ typedef struct tagContext {
     /* const ITfContextCompositionVtbl *ContextCompositionVtbl; */
     /* const ITfContextOwnerCompositionServicesVtbl *ContextOwnerCompositionServicesVtbl; */
     /* const ITfContextOwnerServicesVtbl *ContextOwnerServicesVtbl; */
-    /* const ITfInsertAtSelectionVtbl *InsertAtSelectionVtbl; */
+    const ITfInsertAtSelectionVtbl *InsertAtSelectionVtbl;
     /* const ITfMouseTrackerVtbl *MouseTrackerVtbl; */
     /* const ITfQueryEmbeddedVtbl *QueryEmbeddedVtbl; */
-    /* const ITfSourceSingleVtbl *SourceSingleVtbl; */
+    const ITfSourceSingleVtbl *SourceSingleVtbl;
     LONG refCount;
     BOOL connected;
 
+    /* Aggregation */
+    ITfCompartmentMgr  *CompartmentMgr;
+
     TfClientId tidOwner;
     TfEditCookie defaultCookie;
+    TS_STATUS documentStatus;
+    ITfDocumentMgr *manager;
 
     ITextStoreACP   *pITextStoreACP;
     ITfContextOwnerCompositionSink *pITfContextOwnerCompositionSink;
@@ -107,6 +112,16 @@ static inline Context *impl_from_ITfSourceVtbl(ITfSource *iface)
     return (Context *)((char *)iface - FIELD_OFFSET(Context,SourceVtbl));
 }
 
+static inline Context *impl_from_ITfInsertAtSelectionVtbl(ITfInsertAtSelection*iface)
+{
+    return (Context *)((char *)iface - FIELD_OFFSET(Context,InsertAtSelectionVtbl));
+}
+
+static inline Context *impl_from_ITfSourceSingleVtbl(ITfSourceSingle* iface)
+{
+    return (Context *)((char *)iface - FIELD_OFFSET(Context,SourceSingleVtbl));
+}
+
 static void free_sink(ContextSink *sink)
 {
         IUnknown_Release(sink->interfaces.pIUnknown);
@@ -169,6 +184,7 @@ static void Context_Destructor(Context *This)
         free_sink(sink);
     }
 
+    CompartmentMgr_Destructor(This->CompartmentMgr);
     HeapFree(GetProcessHeap(),0,This);
 }
 
@@ -185,6 +201,18 @@ static HRESULT WINAPI Context_QueryInterface(ITfContext *iface, REFIID iid, LPVO
     {
         *ppvOut = &This->SourceVtbl;
     }
+    else if (IsEqualIID(iid, &IID_ITfInsertAtSelection))
+    {
+        *ppvOut = &This->InsertAtSelectionVtbl;
+    }
+    else if (IsEqualIID(iid, &IID_ITfCompartmentMgr))
+    {
+        *ppvOut = This->CompartmentMgr;
+    }
+    else if (IsEqualIID(iid, &IID_ITfSourceSingle))
+    {
+        *ppvOut = &This->SourceSingleVtbl;
+    }
 
     if (*ppvOut)
     {
@@ -223,7 +251,6 @@ static HRESULT WINAPI Context_RequestEditSession (ITfContext *iface,
     HRESULT hr;
     Context *This = (Context *)iface;
     DWORD  dwLockFlags = 0x0;
-    TS_STATUS status;
 
     TRACE("(%p) %i %p %x %p\n",This, tid, pes, dwFlags, phrSession);
 
@@ -248,10 +275,10 @@ static HRESULT WINAPI Context_RequestEditSession (ITfContext *iface,
     else if (dwFlags & TF_ES_READ)
         dwLockFlags |= TS_LF_READ;
 
-    /* TODO: cache this */
-    ITextStoreACP_GetStatus(This->pITextStoreACP, &status);
+    if (!This->documentStatus.dwDynamicFlags)
+        ITextStoreACP_GetStatus(This->pITextStoreACP, &This->documentStatus);
 
-    if (((dwFlags & TF_ES_READWRITE) == TF_ES_READWRITE) && (status.dwDynamicFlags & TS_SD_READONLY))
+    if (((dwFlags & TF_ES_READWRITE) == TF_ES_READWRITE) && (This->documentStatus.dwDynamicFlags & TS_SD_READONLY))
     {
         *phrSession = TS_E_READONLY;
         return S_OK;
@@ -263,7 +290,6 @@ static HRESULT WINAPI Context_RequestEditSession (ITfContext *iface,
         return E_INVALIDARG;
     }
 
-
     hr = ITextStoreACP_RequestLock(This->pITextStoreACP, dwLockFlags, phrSession);
 
     return hr;
@@ -341,9 +367,39 @@ static HRESULT WINAPI Context_GetSelection (ITfContext *iface,
 static HRESULT WINAPI Context_SetSelection (ITfContext *iface,
         TfEditCookie ec, ULONG ulCount, const TF_SELECTION *pSelection)
 {
+    TS_SELECTION_ACP *acp;
     Context *This = (Context *)iface;
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+    INT i;
+    HRESULT hr;
+
+    TRACE("(%p) %i %i %p\n",This,ec,ulCount,pSelection);
+
+    if (!This->pITextStoreACP)
+    {
+        FIXME("Context does not have a ITextStoreACP\n");
+        return E_NOTIMPL;
+    }
+
+    if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE)
+        return TF_E_NOLOCK;
+
+    acp = HeapAlloc(GetProcessHeap(), 0, sizeof(TS_SELECTION_ACP) * ulCount);
+    if (!acp)
+        return E_OUTOFMEMORY;
+
+    for (i = 0; i < ulCount; i++)
+        if (FAILED(TF_SELECTION_to_TS_SELECTION_ACP(&pSelection[i], &acp[i])))
+        {
+            TRACE("Selection Conversion Failed\n");
+            HeapFree(GetProcessHeap(), 0 , acp);
+            return E_FAIL;
+        }
+
+    hr = ITextStoreACP_SetSelection(This->pITextStoreACP, ulCount, acp);
+
+    HeapFree(GetProcessHeap(), 0, acp);
+
+    return hr;
 }
 
 static HRESULT WINAPI Context_GetStart (ITfContext *iface,
@@ -419,8 +475,25 @@ static HRESULT WINAPI Context_GetStatus (ITfContext *iface,
         TF_STATUS *pdcs)
 {
     Context *This = (Context *)iface;
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+    TRACE("(%p) %p\n",This,pdcs);
+
+    if (!This->connected)
+        return TF_E_DISCONNECTED;
+
+    if (!pdcs)
+        return E_INVALIDARG;
+
+    if (!This->pITextStoreACP)
+    {
+        FIXME("Context does not have a ITextStoreACP\n");
+        return E_NOTIMPL;
+    }
+
+    ITextStoreACP_GetStatus(This->pITextStoreACP, &This->documentStatus);
+
+    *pdcs = This->documentStatus;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI Context_GetProperty (ITfContext *iface,
@@ -460,8 +533,18 @@ static HRESULT WINAPI Context_GetDocumentMgr (ITfContext *iface,
         ITfDocumentMgr **ppDm)
 {
     Context *This = (Context *)iface;
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+    TRACE("(%p) %p\n",This,ppDm);
+
+    if (!ppDm)
+        return E_INVALIDARG;
+
+    *ppDm = This->manager;
+    if (!This->manager)
+        return S_FALSE;
+
+    ITfDocumentMgr_AddRef(This->manager);
+
+    return S_OK;
 }
 
 static HRESULT WINAPI Context_CreateRangeBackup (ITfContext *iface,
@@ -579,7 +662,130 @@ static const ITfSourceVtbl Context_SourceVtbl =
     ContextSource_UnadviseSink,
 };
 
-HRESULT Context_Constructor(TfClientId tidOwner, IUnknown *punk, ITfContext **ppOut, TfEditCookie *pecTextStore)
+/*****************************************************
+ * ITfInsertAtSelection functions
+ *****************************************************/
+static HRESULT WINAPI InsertAtSelection_QueryInterface(ITfInsertAtSelection *iface, REFIID iid, LPVOID *ppvOut)
+{
+    Context *This = impl_from_ITfInsertAtSelectionVtbl(iface);
+    return Context_QueryInterface((ITfContext *)This, iid, *ppvOut);
+}
+
+static ULONG WINAPI InsertAtSelection_AddRef(ITfInsertAtSelection *iface)
+{
+    Context *This = impl_from_ITfInsertAtSelectionVtbl(iface);
+    return Context_AddRef((ITfContext *)This);
+}
+
+static ULONG WINAPI InsertAtSelection_Release(ITfInsertAtSelection *iface)
+{
+    Context *This = impl_from_ITfInsertAtSelectionVtbl(iface);
+    return Context_Release((ITfContext *)This);
+}
+
+static WINAPI HRESULT InsertAtSelection_InsertTextAtSelection(
+        ITfInsertAtSelection *iface, TfEditCookie ec, DWORD dwFlags,
+        const WCHAR *pchText, LONG cch, ITfRange **ppRange)
+{
+    Context *This = impl_from_ITfInsertAtSelectionVtbl(iface);
+    EditCookie *cookie;
+    LONG acpStart, acpEnd;
+    TS_TEXTCHANGE change;
+    HRESULT hr;
+
+    TRACE("(%p) %i %x %s %p\n",This, ec, dwFlags, debugstr_wn(pchText,cch), ppRange);
+
+    if (!This->connected)
+        return TF_E_DISCONNECTED;
+
+    if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE)
+        return TF_E_NOLOCK;
+
+    cookie = get_Cookie_data(ec);
+
+    if ((cookie->lockType & TS_LF_READWRITE) != TS_LF_READWRITE )
+        return TS_E_READONLY;
+
+    if (!This->pITextStoreACP)
+    {
+        FIXME("Context does not have a ITextStoreACP\n");
+        return E_NOTIMPL;
+    }
+
+    hr = ITextStoreACP_InsertTextAtSelection(This->pITextStoreACP, dwFlags, pchText, cch, &acpStart, &acpEnd, &change);
+    if (SUCCEEDED(hr))
+        Range_Constructor((ITfContext*)This, This->pITextStoreACP, cookie->lockType, change.acpStart, change.acpNewEnd, ppRange);
+
+    return hr;
+}
+
+static WINAPI HRESULT InsertAtSelection_InsertEmbeddedAtSelection(
+        ITfInsertAtSelection *iface, TfEditCookie ec, DWORD dwFlags,
+        IDataObject *pDataObject, ITfRange **ppRange)
+{
+    Context *This = impl_from_ITfInsertAtSelectionVtbl(iface);
+    FIXME("STUB:(%p)\n",This);
+    return E_NOTIMPL;
+}
+
+static const ITfInsertAtSelectionVtbl Context_InsertAtSelectionVtbl =
+{
+    InsertAtSelection_QueryInterface,
+    InsertAtSelection_AddRef,
+    InsertAtSelection_Release,
+
+    InsertAtSelection_InsertTextAtSelection,
+    InsertAtSelection_InsertEmbeddedAtSelection,
+};
+
+/*****************************************************
+ * ITfSourceSingle functions
+ *****************************************************/
+static HRESULT WINAPI SourceSingle_QueryInterface(ITfSourceSingle *iface, REFIID iid, LPVOID *ppvOut)
+{
+    Context *This = impl_from_ITfSourceSingleVtbl(iface);
+    return Context_QueryInterface((ITfContext *)This, iid, *ppvOut);
+}
+
+static ULONG WINAPI SourceSingle_AddRef(ITfSourceSingle *iface)
+{
+    Context *This = impl_from_ITfSourceSingleVtbl(iface);
+    return Context_AddRef((ITfContext *)This);
+}
+
+static ULONG WINAPI SourceSingle_Release(ITfSourceSingle *iface)
+{
+    Context *This = impl_from_ITfSourceSingleVtbl(iface);
+    return Context_Release((ITfContext *)This);
+}
+
+static WINAPI HRESULT SourceSingle_AdviseSingleSink( ITfSourceSingle *iface,
+    TfClientId tid, REFIID riid, IUnknown *punk)
+{
+    Context *This = impl_from_ITfSourceSingleVtbl(iface);
+    FIXME("STUB:(%p) %i %s %p\n",This, tid, debugstr_guid(riid),punk);
+    return E_NOTIMPL;
+}
+
+static WINAPI HRESULT SourceSingle_UnadviseSingleSink( ITfSourceSingle *iface,
+    TfClientId tid, REFIID riid)
+{
+    Context *This = impl_from_ITfSourceSingleVtbl(iface);
+    FIXME("STUB:(%p) %i %s\n",This, tid, debugstr_guid(riid));
+    return E_NOTIMPL;
+}
+
+static const ITfSourceSingleVtbl Context_SourceSingleVtbl =
+{
+    SourceSingle_QueryInterface,
+    SourceSingle_AddRef,
+    SourceSingle_Release,
+
+    SourceSingle_AdviseSingleSink,
+    SourceSingle_UnadviseSingleSink,
+};
+
+HRESULT Context_Constructor(TfClientId tidOwner, IUnknown *punk, ITfDocumentMgr *mgr, ITfContext **ppOut, TfEditCookie *pecTextStore)
 {
     Context *This;
     EditCookie *cookie;
@@ -599,9 +805,14 @@ HRESULT Context_Constructor(TfClientId tidOwner, IUnknown *punk, ITfContext **pp
 
     This->ContextVtbl= &Context_ContextVtbl;
     This->SourceVtbl = &Context_SourceVtbl;
+    This->InsertAtSelectionVtbl = &Context_InsertAtSelectionVtbl;
+    This->SourceSingleVtbl = &Context_SourceSingleVtbl;
     This->refCount = 1;
     This->tidOwner = tidOwner;
     This->connected = FALSE;
+    This->manager = mgr;
+
+    CompartmentMgr_Constructor((IUnknown*)This, &IID_IUnknown, (IUnknown**)&This->CompartmentMgr);
 
     cookie->lockType = TF_ES_READ;
     cookie->pOwningContext = This;
@@ -633,7 +844,7 @@ HRESULT Context_Constructor(TfClientId tidOwner, IUnknown *punk, ITfContext **pp
     return S_OK;
 }
 
-HRESULT Context_Initialize(ITfContext *iface)
+HRESULT Context_Initialize(ITfContext *iface, ITfDocumentMgr *manager)
 {
     Context *This = (Context *)iface;
 
@@ -644,6 +855,7 @@ HRESULT Context_Initialize(ITfContext *iface)
                             (IUnknown*)This->pITextStoreACPSink, TS_AS_ALL_SINKS);
     }
     This->connected = TRUE;
+    This->manager = manager;
     return S_OK;
 }
 
@@ -658,6 +870,7 @@ HRESULT Context_Uninitialize(ITfContext *iface)
             This->pITextStoreACPSink = NULL;
     }
     This->connected = FALSE;
+    This->manager = NULL;
     return S_OK;
 }
 
@@ -739,8 +952,28 @@ static HRESULT WINAPI TextStoreACPSink_OnStatusChange(ITextStoreACPSink *iface,
         DWORD dwFlags)
 {
     TextStoreACPSink *This = (TextStoreACPSink *)iface;
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+    HRESULT hr, hrSession;
+
+    TRACE("(%p) %x\n",This, dwFlags);
+
+    if (!This->pContext)
+    {
+        ERR("No context?\n");
+        return E_FAIL;
+    }
+
+    if (!This->pContext->pITextStoreACP)
+    {
+        FIXME("Context does not have a ITextStoreACP\n");
+        return E_NOTIMPL;
+    }
+
+    hr = ITextStoreACP_RequestLock(This->pContext->pITextStoreACP, TS_LF_READ, &hrSession);
+
+    if(SUCCEEDED(hr) && SUCCEEDED(hrSession))
+        This->pContext->documentStatus.dwDynamicFlags = dwFlags;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI TextStoreACPSink_OnAttrsChange(ITextStoreACPSink *iface,
@@ -756,27 +989,57 @@ static HRESULT WINAPI TextStoreACPSink_OnLockGranted(ITextStoreACPSink *iface,
 {
     TextStoreACPSink *This = (TextStoreACPSink *)iface;
     HRESULT hr;
-    EditCookie *cookie;
+    EditCookie *cookie,*sinkcookie;
     TfEditCookie ec;
+    struct list *cursor;
 
     TRACE("(%p) %x\n",This, dwLockFlags);
 
-    if (!This->pContext || !This->pContext->currentEditSession)
+    if (!This->pContext)
     {
-        ERR("OnLockGranted called on a context without a current edit session\n");
+        ERR("OnLockGranted called without a context\n");
         return E_FAIL;
     }
 
+    if (!This->pContext->currentEditSession)
+    {
+        FIXME("OnLockGranted called for something other than an EditSession\n");
+        return S_OK;
+    }
+
     cookie = HeapAlloc(GetProcessHeap(),0,sizeof(EditCookie));
     if (!cookie)
         return E_OUTOFMEMORY;
 
+    sinkcookie = HeapAlloc(GetProcessHeap(),0,sizeof(EditCookie));
+    if (!sinkcookie)
+        return E_OUTOFMEMORY;
+
     cookie->lockType = dwLockFlags;
     cookie->pOwningContext = This->pContext;
     ec = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE, cookie);
 
     hr = ITfEditSession_DoEditSession(This->pContext->currentEditSession, ec);
 
+    if ((dwLockFlags&TS_LF_READWRITE) == TS_LF_READWRITE)
+    {
+        TfEditCookie sc;
+
+        sinkcookie->lockType = TS_LF_READ;
+        sinkcookie->pOwningContext = This->pContext;
+        sc = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE, sinkcookie);
+
+        /*TODO: implement ITfEditRecord */
+        LIST_FOR_EACH(cursor, &This->pContext->pTextEditSink)
+        {
+            ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
+            ITfTextEditSink_OnEndEdit(sink->interfaces.pITfTextEditSink,
+                                      (ITfContext*) &This->pContext, sc, NULL);
+        }
+        sinkcookie = remove_Cookie(sc);
+    }
+    HeapFree(GetProcessHeap(),0,sinkcookie);
+
     ITfEditSession_Release(This->pContext->currentEditSession);
     This->pContext->currentEditSession = NULL;
 
index 7fd354a..0a25b3d 100644 (file)
@@ -45,10 +45,23 @@ typedef struct tagDocumentMgr {
     const ITfSourceVtbl *SourceVtbl;
     LONG refCount;
 
+    /* Aggregation */
+    ITfCompartmentMgr  *CompartmentMgr;
+
     ITfContext*  contextStack[2]; /* limit of 2 contexts */
     ITfThreadMgrEventSink* ThreadMgrSink;
 } DocumentMgr;
 
+typedef struct tagEnumTfContext {
+    const IEnumTfContextsVtbl *Vtbl;
+    LONG refCount;
+
+    DWORD   index;
+    DocumentMgr *docmgr;
+} EnumTfContext;
+
+static HRESULT EnumTfContext_Constructor(DocumentMgr* mgr, IEnumTfContexts **ppOut);
+
 static inline DocumentMgr *impl_from_ITfSourceVtbl(ITfSource *iface)
 {
     return (DocumentMgr *)((char *)iface - FIELD_OFFSET(DocumentMgr,SourceVtbl));
@@ -56,11 +69,17 @@ static inline DocumentMgr *impl_from_ITfSourceVtbl(ITfSource *iface)
 
 static void DocumentMgr_Destructor(DocumentMgr *This)
 {
+    ITfThreadMgr *tm;
     TRACE("destroying %p\n", This);
+
+    TF_GetThreadMgr(&tm);
+    ThreadMgr_OnDocumentMgrDestruction(tm, (ITfDocumentMgr*)This);
+
     if (This->contextStack[0])
         ITfContext_Release(This->contextStack[0]);
     if (This->contextStack[1])
         ITfContext_Release(This->contextStack[1]);
+    CompartmentMgr_Destructor(This->CompartmentMgr);
     HeapFree(GetProcessHeap(),0,This);
 }
 
@@ -77,6 +96,10 @@ static HRESULT WINAPI DocumentMgr_QueryInterface(ITfDocumentMgr *iface, REFIID i
     {
         *ppvOut = &This->SourceVtbl;
     }
+    else if (IsEqualIID(iid, &IID_ITfCompartmentMgr))
+    {
+        *ppvOut = This->CompartmentMgr;
+    }
 
     if (*ppvOut)
     {
@@ -115,7 +138,7 @@ static HRESULT WINAPI DocumentMgr_CreateContext(ITfDocumentMgr *iface,
 {
     DocumentMgr *This = (DocumentMgr *)iface;
     TRACE("(%p) 0x%x 0x%x %p %p %p\n",This,tidOwner,dwFlags,punk,ppic,pecTextStore);
-    return Context_Constructor(tidOwner, punk, ppic, pecTextStore);
+    return Context_Constructor(tidOwner, punk, iface, ppic, pecTextStore);
 }
 
 static HRESULT WINAPI DocumentMgr_Push(ITfDocumentMgr *iface, ITfContext *pic)
@@ -137,8 +160,8 @@ static HRESULT WINAPI DocumentMgr_Push(ITfDocumentMgr *iface, ITfContext *pic)
     This->contextStack[1] = This->contextStack[0];
     This->contextStack[0] = check;
 
+    Context_Initialize(check, iface);
     ITfThreadMgrEventSink_OnPushContext(This->ThreadMgrSink,check);
-    Context_Initialize(check);
 
     return S_OK;
 }
@@ -225,8 +248,8 @@ static HRESULT WINAPI DocumentMgr_GetBase(ITfDocumentMgr *iface, ITfContext **pp
 static HRESULT WINAPI DocumentMgr_EnumContexts(ITfDocumentMgr *iface, IEnumTfContexts **ppEnum)
 {
     DocumentMgr *This = (DocumentMgr *)iface;
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+    TRACE("(%p) %p\n",This,ppEnum);
+    return EnumTfContext_Constructor(This, ppEnum);
 }
 
 static const ITfDocumentMgrVtbl DocumentMgr_DocumentMgrVtbl =
@@ -303,7 +326,148 @@ HRESULT DocumentMgr_Constructor(ITfThreadMgrEventSink *ThreadMgrSink, ITfDocumen
     This->refCount = 1;
     This->ThreadMgrSink = ThreadMgrSink;
 
+    CompartmentMgr_Constructor((IUnknown*)This, &IID_IUnknown, (IUnknown**)&This->CompartmentMgr);
+
     TRACE("returning %p\n", This);
     *ppOut = (ITfDocumentMgr*)This;
     return S_OK;
 }
+
+/**************************************************
+ * IEnumTfContexts implementaion
+ **************************************************/
+static void EnumTfContext_Destructor(EnumTfContext *This)
+{
+    TRACE("destroying %p\n", This);
+    HeapFree(GetProcessHeap(),0,This);
+}
+
+static HRESULT WINAPI EnumTfContext_QueryInterface(IEnumTfContexts *iface, REFIID iid, LPVOID *ppvOut)
+{
+    EnumTfContext *This = (EnumTfContext *)iface;
+    *ppvOut = NULL;
+
+    if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumTfContexts))
+    {
+        *ppvOut = This;
+    }
+
+    if (*ppvOut)
+    {
+        IUnknown_AddRef(iface);
+        return S_OK;
+    }
+
+    WARN("unsupported interface: %s\n", debugstr_guid(iid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI EnumTfContext_AddRef(IEnumTfContexts *iface)
+{
+    EnumTfContext *This = (EnumTfContext*)iface;
+    return InterlockedIncrement(&This->refCount);
+}
+
+static ULONG WINAPI EnumTfContext_Release(IEnumTfContexts *iface)
+{
+    EnumTfContext *This = (EnumTfContext *)iface;
+    ULONG ret;
+
+    ret = InterlockedDecrement(&This->refCount);
+    if (ret == 0)
+        EnumTfContext_Destructor(This);
+    return ret;
+}
+
+static HRESULT WINAPI EnumTfContext_Next(IEnumTfContexts *iface,
+    ULONG ulCount, ITfContext **rgContext, ULONG *pcFetched)
+{
+    EnumTfContext *This = (EnumTfContext *)iface;
+    ULONG fetched = 0;
+
+    TRACE("(%p)\n",This);
+
+    if (rgContext == NULL) return E_POINTER;
+
+    while (fetched < ulCount)
+    {
+        if (This->index > 1)
+            break;
+
+        if (!This->docmgr->contextStack[This->index])
+            break;
+
+        *rgContext = This->docmgr->contextStack[This->index];
+        ITfContext_AddRef(*rgContext);
+
+        ++This->index;
+        ++fetched;
+        ++rgContext;
+    }
+
+    if (pcFetched) *pcFetched = fetched;
+    return fetched == ulCount ? S_OK : S_FALSE;
+}
+
+static HRESULT WINAPI EnumTfContext_Skip( IEnumTfContexts* iface, ULONG celt)
+{
+    EnumTfContext *This = (EnumTfContext *)iface;
+    TRACE("(%p)\n",This);
+    This->index += celt;
+    return S_OK;
+}
+
+static HRESULT WINAPI EnumTfContext_Reset( IEnumTfContexts* iface)
+{
+    EnumTfContext *This = (EnumTfContext *)iface;
+    TRACE("(%p)\n",This);
+    This->index = 0;
+    return S_OK;
+}
+
+static HRESULT WINAPI EnumTfContext_Clone( IEnumTfContexts *iface,
+    IEnumTfContexts **ppenum)
+{
+    EnumTfContext *This = (EnumTfContext *)iface;
+    HRESULT res;
+
+    TRACE("(%p)\n",This);
+
+    if (ppenum == NULL) return E_POINTER;
+
+    res = EnumTfContext_Constructor(This->docmgr, ppenum);
+    if (SUCCEEDED(res))
+    {
+        EnumTfContext *new_This = (EnumTfContext *)*ppenum;
+        new_This->index = This->index;
+    }
+    return res;
+}
+
+static const IEnumTfContextsVtbl IEnumTfContexts_Vtbl ={
+    EnumTfContext_QueryInterface,
+    EnumTfContext_AddRef,
+    EnumTfContext_Release,
+
+    EnumTfContext_Clone,
+    EnumTfContext_Next,
+    EnumTfContext_Reset,
+    EnumTfContext_Skip
+};
+
+static HRESULT EnumTfContext_Constructor(DocumentMgr *mgr, IEnumTfContexts **ppOut)
+{
+    EnumTfContext *This;
+
+    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(EnumTfContext));
+    if (This == NULL)
+        return E_OUTOFMEMORY;
+
+    This->Vtbl= &IEnumTfContexts_Vtbl;
+    This->refCount = 1;
+    This->docmgr = mgr;
+
+    TRACE("returning %p\n", This);
+    *ppOut = (IEnumTfContexts*)This;
+    return S_OK;
+}
index a904a68..0935c44 100644 (file)
 WINE_DEFAULT_DEBUG_CHANNEL(msctf);
 
 static const WCHAR szwLngp[] = {'L','a','n','g','u','a','g','e','P','r','o','f','i','l','e',0};
-static const WCHAR szwEnabled[] = {'E','n','a','b','l','e','d',0};
+static const WCHAR szwEnable[] = {'E','n','a','b','l','e',0};
 static const WCHAR szwTipfmt[] = {'%','s','\\','%','s',0};
 static const WCHAR szwFullLangfmt[] = {'%','s','\\','%','s','\\','%','s','\\','0','x','%','0','8','x','\\','%','s',0};
 
+static const WCHAR szwAssemblies[] = {'A','s','s','e','m','b','l','i','e','s',0};
+static const WCHAR szwDefault[] = {'D','e','f','a','u','l','t',0};
+static const WCHAR szwProfile[] = {'P','r','o','f','i','l','e',0};
+static const WCHAR szwDefaultFmt[] = {'%','s','\\','%','s','\\','0','x','%','0','8','x','\\','%','s',0};
+
 typedef struct tagInputProcessorProfilesSink {
     struct list         entry;
     union {
@@ -144,7 +149,7 @@ static void add_userkey( REFCLSID rclsid, LANGID langid,
     if (!res && disposition == REG_CREATED_NEW_KEY)
     {
         DWORD zero = 0x0;
-        RegSetValueExW(key, szwEnabled, 0, REG_DWORD, (LPBYTE)&zero, sizeof(DWORD));
+        RegSetValueExW(key, szwEnable, 0, REG_DWORD, (LPBYTE)&zero, sizeof(DWORD));
     }
 
     if (!res)
@@ -278,7 +283,7 @@ static HRESULT WINAPI InputProcessorProfiles_AddLanguageProfile(
         RegSetValueExW(fmtkey, icnf, 0, REG_SZ, (LPBYTE)pchIconFile, cchFile * sizeof(WCHAR));
         RegSetValueExW(fmtkey, icni, 0, REG_DWORD, (LPBYTE)&uIconIndex, sizeof(DWORD));
         if (disposition == REG_CREATED_NEW_KEY)
-            RegSetValueExW(fmtkey, szwEnabled, 0, REG_DWORD, (LPBYTE)&zero, sizeof(DWORD));
+            RegSetValueExW(fmtkey, szwEnable, 0, REG_DWORD, (LPBYTE)&zero, sizeof(DWORD));
         RegCloseKey(fmtkey);
 
         add_userkey(rclsid, langid, guidProfile);
@@ -312,18 +317,91 @@ static HRESULT WINAPI InputProcessorProfiles_GetDefaultLanguageProfile(
         ITfInputProcessorProfiles *iface, LANGID langid, REFGUID catid,
         CLSID *pclsid, GUID *pguidProfile)
 {
+    WCHAR fullkey[168];
+    WCHAR buf[39];
+    HKEY hkey;
+    DWORD count;
+    ULONG res;
     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+
+    TRACE("%p) %x %s %p %p\n",This, langid, debugstr_guid(catid),pclsid,pguidProfile);
+
+    if (!catid || !pclsid || !pguidProfile)
+        return E_INVALIDARG;
+
+    StringFromGUID2(catid, buf, 39);
+    sprintfW(fullkey, szwDefaultFmt, szwSystemCTFKey, szwAssemblies, langid, buf);
+
+    if (RegOpenKeyExW(HKEY_CURRENT_USER, fullkey, 0, KEY_READ | KEY_WRITE,
+                &hkey ) != ERROR_SUCCESS)
+        return S_FALSE;
+
+    count = sizeof(buf);
+    res = RegQueryValueExW(hkey, szwDefault, 0, NULL, (LPBYTE)buf, &count);
+    if (res != ERROR_SUCCESS)
+    {
+        RegCloseKey(hkey);
+        return S_FALSE;
+    }
+    CLSIDFromString(buf,pclsid);
+
+    res = RegQueryValueExW(hkey, szwProfile, 0, NULL, (LPBYTE)buf, &count);
+    if (res == ERROR_SUCCESS)
+        CLSIDFromString(buf,pguidProfile);
+
+    RegCloseKey(hkey);
+
+    return S_OK;
 }
 
 static HRESULT WINAPI InputProcessorProfiles_SetDefaultLanguageProfile(
         ITfInputProcessorProfiles *iface, LANGID langid, REFCLSID rclsid,
         REFGUID guidProfiles)
 {
+    WCHAR fullkey[168];
+    WCHAR buf[39];
+    HKEY hkey;
+    GUID catid;
+    HRESULT hr;
+    ITfCategoryMgr *catmgr;
     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+    static const GUID * tipcats[3] = { &GUID_TFCAT_TIP_KEYBOARD,
+                                       &GUID_TFCAT_TIP_SPEECH,
+                                       &GUID_TFCAT_TIP_HANDWRITING };
+
+    TRACE("%p) %x %s %s\n",This, langid, debugstr_guid(rclsid),debugstr_guid(guidProfiles));
+
+    if (!rclsid || !guidProfiles)
+        return E_INVALIDARG;
+
+    hr = CategoryMgr_Constructor(NULL,(IUnknown**)&catmgr);
+
+    if (FAILED(hr))
+        return hr;
+
+    if (ITfCategoryMgr_FindClosestCategory(catmgr, rclsid,
+            &catid, tipcats, 3) != S_OK)
+        hr = ITfCategoryMgr_FindClosestCategory(catmgr, rclsid,
+                &catid, NULL, 0);
+    ITfCategoryMgr_Release(catmgr);
+
+    if (FAILED(hr))
+        return E_FAIL;
+
+    StringFromGUID2(&catid, buf, 39);
+    sprintfW(fullkey, szwDefaultFmt, szwSystemCTFKey, szwAssemblies, langid, buf);
+
+    if (RegCreateKeyExW(HKEY_CURRENT_USER, fullkey, 0, NULL, 0, KEY_READ | KEY_WRITE,
+                NULL, &hkey, NULL ) != ERROR_SUCCESS)
+        return E_FAIL;
+
+    StringFromGUID2(rclsid, buf, 39);
+    RegSetValueExW(hkey, szwDefault, 0, REG_SZ, (LPBYTE)buf, sizeof(buf));
+    StringFromGUID2(guidProfiles, buf, 39);
+    RegSetValueExW(hkey, szwProfile, 0, REG_SZ, (LPBYTE)buf, sizeof(buf));
+    RegCloseKey(hkey);
+
+    return S_OK;
 }
 
 static HRESULT WINAPI InputProcessorProfiles_ActivateLanguageProfile(
@@ -413,8 +491,22 @@ static HRESULT WINAPI InputProcessorProfiles_GetCurrentLanguage(
 static HRESULT WINAPI InputProcessorProfiles_ChangeCurrentLanguage(
         ITfInputProcessorProfiles *iface, LANGID langid)
 {
+    struct list *cursor;
     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
+    BOOL accept;
+
     FIXME("STUB:(%p)\n",This);
+
+    LIST_FOR_EACH(cursor, &This->LanguageProfileNotifySink)
+    {
+        InputProcessorProfilesSink* sink = LIST_ENTRY(cursor,InputProcessorProfilesSink,entry);
+        accept = TRUE;
+        ITfLanguageProfileNotifySink_OnLanguageChange(sink->interfaces.pITfLanguageProfileNotifySink, langid, &accept);
+        if (!accept)
+            return  E_FAIL;
+    }
+
+    /* TODO:  On successful language change call OnLanguageChanged sink */
     return E_NOTIMPL;
 }
 
@@ -422,8 +514,11 @@ static HRESULT WINAPI InputProcessorProfiles_GetLanguageList(
         ITfInputProcessorProfiles *iface, LANGID **ppLangId, ULONG *pulCount)
 {
     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+    FIXME("Semi-STUB:(%p)\n",This);
+    *ppLangId = CoTaskMemAlloc(sizeof(LANGID));
+    **ppLangId = This->currentLanguage;
+    *pulCount = 1;
+    return S_OK;
 }
 
 static HRESULT WINAPI InputProcessorProfiles_EnumLanguageProfiles(
@@ -456,7 +551,7 @@ static HRESULT WINAPI InputProcessorProfiles_EnableLanguageProfile(
 
     if (!res)
     {
-        RegSetValueExW(key, szwEnabled, 0, REG_DWORD, (LPBYTE)&fEnable, sizeof(DWORD));
+        RegSetValueExW(key, szwEnable, 0, REG_DWORD, (LPBYTE)&fEnable, sizeof(DWORD));
         RegCloseKey(key);
     }
     else
@@ -490,7 +585,7 @@ static HRESULT WINAPI InputProcessorProfiles_IsEnabledLanguageProfile(
     if (!res)
     {
         DWORD count = sizeof(DWORD);
-        res = RegQueryValueExW(key, szwEnabled, 0, NULL, (LPBYTE)pfEnable, &count);
+        res = RegQueryValueExW(key, szwEnable, 0, NULL, (LPBYTE)pfEnable, &count);
         RegCloseKey(key);
     }
 
@@ -501,7 +596,7 @@ static HRESULT WINAPI InputProcessorProfiles_IsEnabledLanguageProfile(
         if (!res)
         {
             DWORD count = sizeof(DWORD);
-            res = RegQueryValueExW(key, szwEnabled, 0, NULL, (LPBYTE)pfEnable, &count);
+            res = RegQueryValueExW(key, szwEnable, 0, NULL, (LPBYTE)pfEnable, &count);
             RegCloseKey(key);
         }
     }
@@ -533,7 +628,7 @@ static HRESULT WINAPI InputProcessorProfiles_EnableLanguageProfileByDefault(
 
     if (!res)
     {
-        RegSetValueExW(key, szwEnabled, 0, REG_DWORD, (LPBYTE)&fEnable, sizeof(DWORD));
+        RegSetValueExW(key, szwEnable, 0, REG_DWORD, (LPBYTE)&fEnable, sizeof(DWORD));
         RegCloseKey(key);
     }
     else
index 675e4d5..8277278 100644 (file)
@@ -33,7 +33,6 @@
 #include "shlwapi.h"
 #include "shlguid.h"
 #include "comcat.h"
-#include "initguid.h"
 #include "msctf.h"
 
 #include "msctf_internal.h"
@@ -74,8 +73,10 @@ static UINT activated = 0;
 
 DWORD tlsIndex = 0;
 TfClientId processId = 0;
+ITfCompartmentMgr *globalCompartmentMgr = NULL;
 
 const WCHAR szwSystemTIPKey[] = {'S','O','F','T','W','A','R','E','\\','M','i','c','r','o','s','o','f','t','\\','C','T','F','\\','T','I','P',0};
+const WCHAR szwSystemCTFKey[] = {'S','O','F','T','W','A','R','E','\\','M','i','c','r','o','s','o','f','t','\\','C','T','F',0};
 
 typedef HRESULT (*LPFNCONSTRUCTOR)(IUnknown *pUnkOuter, IUnknown **ppvOut);
 
@@ -598,3 +599,12 @@ HRESULT WINAPI SetInputScopes(HWND hwnd, const INT *pInputScopes,
 
     return S_OK;
 }
+
+/***********************************************************************
+ *              TF_CreateInputProcessorProfiles(MSCTF.@)
+ */
+HRESULT WINAPI TF_CreateInputProcessorProfiles(
+                        ITfInputProcessorProfiles **ppipr)
+{
+    return InputProcessorProfiles_Constructor(NULL,(IUnknown**)ppipr);
+}
index 44664c7..e7cea9c 100644 (file)
@@ -9,6 +9,7 @@
        <define name="__WINESRC__" />
        <redefine name="_WIN32_WINNT">0x600</redefine>
        <file>categorymgr.c</file>
+       <file>compartmentmgr.c</file>
        <file>context.c</file>
        <file>documentmgr.c</file>
        <file>inputprocessor.c</file>
        <library>wine</library>
        <library>uuid</library>
        <library>ole32</library>
+       <library>oleaut32</library>
        <library>user32</library>
        <library>advapi32</library>
        <library>kernel32</library>
+       <library>msctf_local_interface</library>
+       <library>textstor_local_interface</library>
        <library>ntdll</library>
 </module>
 <module name="msctf_local_interface" type="idlinterface">
        <file>msctf_local.idl</file>
 </module>
+<module name="textstor_local_interface" type="idlinterface">
+       <file>textstor_local.idl</file>
+</module>
 </group>
index 1c8bb37..f7c35a3 100644 (file)
@@ -11,7 +11,7 @@
 @ stub TF_CreateCategoryMgr
 @ stub TF_CreateCicLoadMutex
 @ stub TF_CreateDisplayAttributeMgr
-@ stub TF_CreateInputProcessorProfiles
+@ stdcall TF_CreateInputProcessorProfiles(ptr)
 @ stub TF_CreateLangBarItemMgr
 @ stub TF_CreateLangBarMgr
 @ stdcall TF_CreateThreadMgr(ptr)
index 9181b8c..3bb0baa 100644 (file)
 #define COOKIE_MAGIC_GUIDATOM 0x0030
 #define COOKIE_MAGIC_IPPSINK 0x0040
 #define COOKIE_MAGIC_EDITCOOKIE 0x0050
+#define COOKIE_MAGIC_COMPARTMENTSINK 0x0060
 
 extern DWORD tlsIndex;
 extern TfClientId processId;
+extern ITfCompartmentMgr *globalCompartmentMgr;
 
 extern HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut);
 extern HRESULT DocumentMgr_Constructor(ITfThreadMgrEventSink*, ITfDocumentMgr **ppOut);
-extern HRESULT Context_Constructor(TfClientId tidOwner, IUnknown *punk, ITfContext **ppOut, TfEditCookie *pecTextStore);
+extern HRESULT Context_Constructor(TfClientId tidOwner, IUnknown *punk, ITfDocumentMgr *mgr, ITfContext **ppOut, TfEditCookie *pecTextStore);
 extern HRESULT InputProcessorProfiles_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut);
 extern HRESULT CategoryMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut);
 extern HRESULT Range_Constructor(ITfContext *context, ITextStoreACP *textstore, DWORD lockType, DWORD anchorStart, DWORD anchorEnd, ITfRange **ppOut);
+extern HRESULT CompartmentMgr_Constructor(IUnknown *pUnkOuter, REFIID riid, IUnknown **ppOut);
+extern HRESULT CompartmentMgr_Destructor(ITfCompartmentMgr *This);
 
-extern HRESULT Context_Initialize(ITfContext *cxt);
+extern HRESULT Context_Initialize(ITfContext *cxt, ITfDocumentMgr *manager);
 extern HRESULT Context_Uninitialize(ITfContext *cxt);
+extern void    ThreadMgr_OnDocumentMgrDestruction(ITfThreadMgr *tm, ITfDocumentMgr *mgr);
+extern HRESULT TF_SELECTION_to_TS_SELECTION_ACP(const TF_SELECTION *tf, TS_SELECTION_ACP *tsAcp);
 
 /* cookie function */
 extern DWORD  generate_Cookie(DWORD magic, LPVOID data);
@@ -58,4 +64,5 @@ extern HRESULT get_textservice_sink(TfClientId tid, REFCLSID iid, IUnknown** sin
 extern HRESULT set_textservice_sink(TfClientId tid, REFCLSID iid, IUnknown* sink);
 
 extern const WCHAR szwSystemTIPKey[];
+extern const WCHAR szwSystemCTFKey[];
 #endif /* __WINE_MSCTF_I_H */
index 63181af..dc9eae1 100644 (file)
@@ -201,8 +201,21 @@ static HRESULT WINAPI Range_Collapse(ITfRange *iface, TfEditCookie ec,
         TfAnchor aPos)
 {
     Range *This = (Range *)iface;
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+    TRACE("(%p) %i %i\n",This,ec,aPos);
+
+    switch (aPos)
+    {
+        case TF_ANCHOR_START:
+            This->anchorEnd = This->anchorStart;
+            break;
+        case TF_ANCHOR_END:
+            This->anchorStart = This->anchorEnd;
+            break;
+        default:
+            return E_INVALIDARG;
+    }
+
+    return S_OK;
 }
 
 static HRESULT WINAPI Range_IsEqualStart(ITfRange *iface, TfEditCookie ec,
@@ -331,3 +344,21 @@ HRESULT Range_Constructor(ITfContext *context, ITextStoreACP *textstore, DWORD l
 
     return S_OK;
 }
+
+/* Internal conversion functions */
+
+HRESULT TF_SELECTION_to_TS_SELECTION_ACP(const TF_SELECTION *tf, TS_SELECTION_ACP *tsAcp)
+{
+    Range *This;
+
+    if (!tf || !tsAcp || !tf->range)
+        return E_INVALIDARG;
+
+    This = (Range *)tf->range;
+
+    tsAcp->acpStart = This->anchorStart;
+    tsAcp->acpEnd = This->anchorEnd;
+    tsAcp->style.ase = tf->style.ase;
+    tsAcp->style.fInterimChar = tf->style.fInterimChar;
+    return S_OK;
+}
diff --git a/reactos/dll/win32/msctf/textstor_local.idl b/reactos/dll/win32/msctf/textstor_local.idl
new file mode 100644 (file)
index 0000000..a665b25
--- /dev/null
@@ -0,0 +1,2 @@
+
+#include "textstor.idl"
index 9b887f0..0661fec 100644 (file)
@@ -65,6 +65,19 @@ typedef struct tagPreservedKey
     TfClientId      tid;
 } PreservedKey;
 
+typedef struct tagDocumentMgrs
+{
+    struct list     entry;
+    ITfDocumentMgr  *docmgr;
+} DocumentMgrEntry;
+
+typedef struct tagAssociatedWindow
+{
+    struct list     entry;
+    HWND            hwnd;
+    ITfDocumentMgr  *docmgr;
+} AssociatedWindow;
+
 typedef struct tagACLMulti {
     const ITfThreadMgrVtbl *ThreadMgrVtbl;
     const ITfSourceVtbl *SourceVtbl;
@@ -78,6 +91,9 @@ typedef struct tagACLMulti {
     /* const ITfSourceSingleVtbl *SourceSingleVtbl; */
     LONG refCount;
 
+    /* Aggregation */
+    ITfCompartmentMgr  *CompartmentMgr;
+
     const ITfThreadMgrEventSinkVtbl *ThreadMgrEventSinkVtbl; /* internal */
 
     ITfDocumentMgr *focus;
@@ -87,6 +103,10 @@ typedef struct tagACLMulti {
     CLSID forgroundTextService;
 
     struct list CurrentPreservedKeys;
+    struct list CreatedDocumentMgrs;
+
+    struct list AssociatedFocusWindows;
+    HHOOK  focusHook;
 
     /* kept as separate lists to reduce unnecessary iterations */
     struct list     ActiveLanguageProfileNotifySink;
@@ -97,6 +117,17 @@ typedef struct tagACLMulti {
     struct list     ThreadMgrEventSink;
 } ThreadMgr;
 
+typedef struct tagEnumTfDocumentMgr {
+    const IEnumTfDocumentMgrsVtbl *Vtbl;
+    LONG refCount;
+
+    struct list *index;
+    struct list *head;
+} EnumTfDocumentMgr;
+
+static HRESULT EnumTfDocumentMgr_Constructor(struct list* head, IEnumTfDocumentMgrs **ppOut);
+LRESULT CALLBACK ThreadFocusHookProc(int nCode, WPARAM wParam, LPARAM lParam);
+
 static inline ThreadMgr *impl_from_ITfSourceVtbl(ITfSource *iface)
 {
     return (ThreadMgr *)((char *)iface - FIELD_OFFSET(ThreadMgr,SourceVtbl));
@@ -122,6 +153,22 @@ static inline ThreadMgr *impl_from_ITfThreadMgrEventSink(ITfThreadMgrEventSink *
     return (ThreadMgr *)((char *)iface - FIELD_OFFSET(ThreadMgr,ThreadMgrEventSinkVtbl));
 }
 
+static HRESULT SetupWindowsHook(ThreadMgr *This)
+{
+    if (!This->focusHook)
+    {
+        This->focusHook = SetWindowsHookExW(WH_CBT, ThreadFocusHookProc, 0,
+                             GetCurrentThreadId());
+        if (!This->focusHook)
+        {
+            ERR("Unable to set focus hook\n");
+            return E_FAIL;
+        }
+        return S_OK;
+    }
+    return S_FALSE;
+}
+
 static void free_sink(ThreadMgrSink *sink)
 {
         IUnknown_Release(sink->interfaces.pIUnknown);
@@ -132,6 +179,10 @@ static void ThreadMgr_Destructor(ThreadMgr *This)
 {
     struct list *cursor, *cursor2;
 
+    /* unhook right away */
+    if (This->focusHook)
+        UnhookWindowsHookEx(This->focusHook);
+
     TlsSetValue(tlsIndex,NULL);
     TRACE("destroying %p\n", This);
     if (This->focus)
@@ -183,6 +234,23 @@ static void ThreadMgr_Destructor(ThreadMgr *This)
         HeapFree(GetProcessHeap(),0,key);
     }
 
+    LIST_FOR_EACH_SAFE(cursor, cursor2, &This->CreatedDocumentMgrs)
+    {
+        DocumentMgrEntry *mgr = LIST_ENTRY(cursor,DocumentMgrEntry,entry);
+        list_remove(cursor);
+        FIXME("Left Over ITfDocumentMgr.  Should we do something with it?\n");
+        HeapFree(GetProcessHeap(),0,mgr);
+    }
+
+    LIST_FOR_EACH_SAFE(cursor, cursor2, &This->AssociatedFocusWindows)
+    {
+        AssociatedWindow *wnd = LIST_ENTRY(cursor,AssociatedWindow,entry);
+        list_remove(cursor);
+        HeapFree(GetProcessHeap(),0,wnd);
+    }
+
+    CompartmentMgr_Destructor(This->CompartmentMgr);
+
     HeapFree(GetProcessHeap(),0,This);
 }
 
@@ -211,6 +279,10 @@ static HRESULT WINAPI ThreadMgr_QueryInterface(ITfThreadMgr *iface, REFIID iid,
     {
         *ppvOut = &This->ClientIdVtbl;
     }
+    else if (IsEqualIID(iid, &IID_ITfCompartmentMgr))
+    {
+        *ppvOut = This->CompartmentMgr;
+    }
 
     if (*ppvOut)
     {
@@ -294,16 +366,37 @@ static HRESULT WINAPI ThreadMgr_CreateDocumentMgr( ITfThreadMgr* iface, ITfDocum
 **ppdim)
 {
     ThreadMgr *This = (ThreadMgr *)iface;
+    DocumentMgrEntry *mgrentry;
+    HRESULT hr;
+
     TRACE("(%p)\n",iface);
-    return DocumentMgr_Constructor((ITfThreadMgrEventSink*)&This->ThreadMgrEventSinkVtbl, ppdim);
+    mgrentry = HeapAlloc(GetProcessHeap(),0,sizeof(DocumentMgrEntry));
+    if (mgrentry == NULL)
+        return E_OUTOFMEMORY;
+
+    hr = DocumentMgr_Constructor((ITfThreadMgrEventSink*)&This->ThreadMgrEventSinkVtbl, ppdim);
+
+    if (SUCCEEDED(hr))
+    {
+        mgrentry->docmgr = *ppdim;
+        list_add_head(&This->CreatedDocumentMgrs,&mgrentry->entry);
+    }
+    else
+        HeapFree(GetProcessHeap(),0,mgrentry);
+
+    return hr;
 }
 
 static HRESULT WINAPI ThreadMgr_EnumDocumentMgrs( ITfThreadMgr* iface, IEnumTfDocumentMgrs
 **ppEnum)
 {
     ThreadMgr *This = (ThreadMgr *)iface;
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+    TRACE("(%p) %p\n",This,ppEnum);
+
+    if (!ppEnum)
+        return E_INVALIDARG;
+
+    return EnumTfDocumentMgr_Constructor(&This->CreatedDocumentMgrs, ppEnum);
 }
 
 static HRESULT WINAPI ThreadMgr_GetFocus( ITfThreadMgr* iface, ITfDocumentMgr
@@ -334,7 +427,9 @@ static HRESULT WINAPI ThreadMgr_SetFocus( ITfThreadMgr* iface, ITfDocumentMgr *p
 
     TRACE("(%p) %p\n",This,pdimFocus);
 
-    if (!pdimFocus || FAILED(IUnknown_QueryInterface(pdimFocus,&IID_ITfDocumentMgr,(LPVOID*) &check)))
+    if (!pdimFocus)
+        check = NULL;
+    else if (FAILED(IUnknown_QueryInterface(pdimFocus,&IID_ITfDocumentMgr,(LPVOID*) &check)))
         return E_INVALIDARG;
 
     ITfThreadMgrEventSink_OnSetFocus((ITfThreadMgrEventSink*)&This->ThreadMgrEventSinkVtbl, check, This->focus);
@@ -349,16 +444,53 @@ static HRESULT WINAPI ThreadMgr_SetFocus( ITfThreadMgr* iface, ITfDocumentMgr *p
 static HRESULT WINAPI ThreadMgr_AssociateFocus( ITfThreadMgr* iface, HWND hwnd,
 ITfDocumentMgr *pdimNew, ITfDocumentMgr **ppdimPrev)
 {
+    struct list *cursor, *cursor2;
     ThreadMgr *This = (ThreadMgr *)iface;
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+    AssociatedWindow *wnd;
+
+    TRACE("(%p) %p %p %p\n",This,hwnd,pdimNew,ppdimPrev);
+
+    if (!ppdimPrev)
+        return E_INVALIDARG;
+
+    *ppdimPrev = NULL;
+
+    LIST_FOR_EACH_SAFE(cursor, cursor2, &This->AssociatedFocusWindows)
+    {
+        wnd = LIST_ENTRY(cursor,AssociatedWindow,entry);
+        if (wnd->hwnd == hwnd)
+        {
+            if (wnd->docmgr)
+                ITfDocumentMgr_AddRef(wnd->docmgr);
+            *ppdimPrev = wnd->docmgr;
+            wnd->docmgr = pdimNew;
+            if (GetFocus() == hwnd)
+                ThreadMgr_SetFocus(iface,pdimNew);
+            return S_OK;
+        }
+    }
+
+    wnd = HeapAlloc(GetProcessHeap(),0,sizeof(AssociatedWindow));
+    wnd->hwnd = hwnd;
+    wnd->docmgr = pdimNew;
+    list_add_head(&This->AssociatedFocusWindows,&wnd->entry);
+
+    if (GetFocus() == hwnd)
+        ThreadMgr_SetFocus(iface,pdimNew);
+
+    SetupWindowsHook(This);
+
+    return S_OK;
 }
 
 static HRESULT WINAPI ThreadMgr_IsThreadFocus( ITfThreadMgr* iface, BOOL *pfThreadFocus)
 {
+    HWND focus;
     ThreadMgr *This = (ThreadMgr *)iface;
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+    TRACE("(%p) %p\n",This,pfThreadFocus);
+    focus = GetFocus();
+    *pfThreadFocus = (focus == NULL);
+    return S_OK;
 }
 
 static HRESULT WINAPI ThreadMgr_GetFunctionProvider( ITfThreadMgr* iface, REFCLSID clsid,
@@ -381,8 +513,22 @@ static HRESULT WINAPI ThreadMgr_GetGlobalCompartment( ITfThreadMgr* iface,
 ITfCompartmentMgr **ppCompMgr)
 {
     ThreadMgr *This = (ThreadMgr *)iface;
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+    HRESULT hr;
+    TRACE("(%p) %p\n",This, ppCompMgr);
+
+    if (!ppCompMgr)
+        return E_INVALIDARG;
+
+    if (!globalCompartmentMgr)
+    {
+        hr = CompartmentMgr_Constructor(NULL,&IID_ITfCompartmentMgr,(IUnknown**)&globalCompartmentMgr);
+        if (FAILED(hr))
+            return hr;
+    }
+
+    ITfCompartmentMgr_AddRef(globalCompartmentMgr);
+    *ppCompMgr = globalCompartmentMgr;
+    return S_OK;
 }
 
 static const ITfThreadMgrVtbl ThreadMgr_ThreadMgrVtbl =
@@ -1054,7 +1200,11 @@ HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut)
     This->refCount = 1;
     TlsSetValue(tlsIndex,This);
 
+    CompartmentMgr_Constructor((IUnknown*)This, &IID_IUnknown, (IUnknown**)&This->CompartmentMgr);
+
     list_init(&This->CurrentPreservedKeys);
+    list_init(&This->CreatedDocumentMgrs);
+    list_init(&This->AssociatedFocusWindows);
 
     list_init(&This->ActiveLanguageProfileNotifySink);
     list_init(&This->DisplayAttributeNotifySink);
@@ -1067,3 +1217,200 @@ HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut)
     *ppOut = (IUnknown *)This;
     return S_OK;
 }
+
+/**************************************************
+ * IEnumTfDocumentMgrs implementaion
+ **************************************************/
+static void EnumTfDocumentMgr_Destructor(EnumTfDocumentMgr *This)
+{
+    TRACE("destroying %p\n", This);
+    HeapFree(GetProcessHeap(),0,This);
+}
+
+static HRESULT WINAPI EnumTfDocumentMgr_QueryInterface(IEnumTfDocumentMgrs *iface, REFIID iid, LPVOID *ppvOut)
+{
+    EnumTfDocumentMgr *This = (EnumTfDocumentMgr *)iface;
+    *ppvOut = NULL;
+
+    if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumTfDocumentMgrs))
+    {
+        *ppvOut = This;
+    }
+
+    if (*ppvOut)
+    {
+        IUnknown_AddRef(iface);
+        return S_OK;
+    }
+
+    WARN("unsupported interface: %s\n", debugstr_guid(iid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI EnumTfDocumentMgr_AddRef(IEnumTfDocumentMgrs *iface)
+{
+    EnumTfDocumentMgr *This = (EnumTfDocumentMgr*)iface;
+    return InterlockedIncrement(&This->refCount);
+}
+
+static ULONG WINAPI EnumTfDocumentMgr_Release(IEnumTfDocumentMgrs *iface)
+{
+    EnumTfDocumentMgr *This = (EnumTfDocumentMgr *)iface;
+    ULONG ret;
+
+    ret = InterlockedDecrement(&This->refCount);
+    if (ret == 0)
+        EnumTfDocumentMgr_Destructor(This);
+    return ret;
+}
+
+static HRESULT WINAPI EnumTfDocumentMgr_Next(IEnumTfDocumentMgrs *iface,
+    ULONG ulCount, ITfDocumentMgr **rgDocumentMgr, ULONG *pcFetched)
+{
+    EnumTfDocumentMgr *This = (EnumTfDocumentMgr *)iface;
+    ULONG fetched = 0;
+
+    TRACE("(%p)\n",This);
+
+    if (rgDocumentMgr == NULL) return E_POINTER;
+
+    while (fetched < ulCount)
+    {
+        DocumentMgrEntry *mgrentry;
+        if (This->index == NULL)
+            break;
+
+        mgrentry = LIST_ENTRY(This->index,DocumentMgrEntry,entry);
+        if (mgrentry == NULL)
+            break;
+
+        *rgDocumentMgr = mgrentry->docmgr;
+        ITfDocumentMgr_AddRef(*rgDocumentMgr);
+
+        This->index = list_next(This->head, This->index);
+        ++fetched;
+        ++rgDocumentMgr;
+    }
+
+    if (pcFetched) *pcFetched = fetched;
+    return fetched == ulCount ? S_OK : S_FALSE;
+}
+
+static HRESULT WINAPI EnumTfDocumentMgr_Skip( IEnumTfDocumentMgrs* iface, ULONG celt)
+{
+    INT i;
+    EnumTfDocumentMgr *This = (EnumTfDocumentMgr *)iface;
+    TRACE("(%p)\n",This);
+    for(i = 0; i < celt && This->index != NULL; i++)
+        This->index = list_next(This->head, This->index);
+    return S_OK;
+}
+
+static HRESULT WINAPI EnumTfDocumentMgr_Reset( IEnumTfDocumentMgrs* iface)
+{
+    EnumTfDocumentMgr *This = (EnumTfDocumentMgr *)iface;
+    TRACE("(%p)\n",This);
+    This->index = list_head(This->head);
+    return S_OK;
+}
+
+static HRESULT WINAPI EnumTfDocumentMgr_Clone( IEnumTfDocumentMgrs *iface,
+    IEnumTfDocumentMgrs **ppenum)
+{
+    EnumTfDocumentMgr *This = (EnumTfDocumentMgr *)iface;
+    HRESULT res;
+
+    TRACE("(%p)\n",This);
+
+    if (ppenum == NULL) return E_POINTER;
+
+    res = EnumTfDocumentMgr_Constructor(This->head, ppenum);
+    if (SUCCEEDED(res))
+    {
+        EnumTfDocumentMgr *new_This = (EnumTfDocumentMgr *)*ppenum;
+        new_This->index = This->index;
+    }
+    return res;
+}
+
+static const IEnumTfDocumentMgrsVtbl IEnumTfDocumentMgrs_Vtbl ={
+    EnumTfDocumentMgr_QueryInterface,
+    EnumTfDocumentMgr_AddRef,
+    EnumTfDocumentMgr_Release,
+
+    EnumTfDocumentMgr_Clone,
+    EnumTfDocumentMgr_Next,
+    EnumTfDocumentMgr_Reset,
+    EnumTfDocumentMgr_Skip
+};
+
+static HRESULT EnumTfDocumentMgr_Constructor(struct list* head, IEnumTfDocumentMgrs **ppOut)
+{
+    EnumTfDocumentMgr *This;
+
+    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(EnumTfDocumentMgr));
+    if (This == NULL)
+        return E_OUTOFMEMORY;
+
+    This->Vtbl= &IEnumTfDocumentMgrs_Vtbl;
+    This->refCount = 1;
+    This->head = head;
+    This->index = list_head(This->head);
+
+    TRACE("returning %p\n", This);
+    *ppOut = (IEnumTfDocumentMgrs*)This;
+    return S_OK;
+}
+
+void ThreadMgr_OnDocumentMgrDestruction(ITfThreadMgr *tm, ITfDocumentMgr *mgr)
+{
+    ThreadMgr *This = (ThreadMgr *)tm;
+    struct list *cursor;
+    LIST_FOR_EACH(cursor, &This->CreatedDocumentMgrs)
+    {
+        DocumentMgrEntry *mgrentry = LIST_ENTRY(cursor,DocumentMgrEntry,entry);
+        if (mgrentry->docmgr == mgr)
+        {
+            list_remove(cursor);
+            HeapFree(GetProcessHeap(),0,mgrentry);
+            return;
+        }
+    }
+    FIXME("ITfDocumenMgr %p not found in this thread\n",mgr);
+}
+
+LRESULT CALLBACK ThreadFocusHookProc(int nCode, WPARAM wParam, LPARAM lParam)
+{
+    ThreadMgr *This;
+
+    This = TlsGetValue(tlsIndex);
+    if (!This)
+    {
+        ERR("Hook proc but no ThreadMgr for this thread. Serious Error\n");
+        return 0;
+    }
+    if (!This->focusHook)
+    {
+        ERR("Hook proc but no ThreadMgr focus Hook. Serious Error\n");
+        return 0;
+    }
+
+    if (nCode == HCBT_SETFOCUS) /* focus change within our thread */
+    {
+        struct list *cursor;
+
+        LIST_FOR_EACH(cursor, &This->AssociatedFocusWindows)
+        {
+            AssociatedWindow *wnd = LIST_ENTRY(cursor,AssociatedWindow,entry);
+            if (wnd->hwnd == (HWND)wParam)
+            {
+                TRACE("Triggering Associated window focus\n");
+                if (This->focus != wnd->docmgr)
+                    ThreadMgr_SetFocus((ITfThreadMgr*)This, wnd->docmgr);
+                break;
+            }
+        }
+    }
+
+    return CallNextHookEx(This->focusHook, nCode, wParam, lParam);
+}
index 3dd11b1..b8937e7 100644 (file)
@@ -35,12 +35,14 @@ typedef struct {
     DISPID id;
     BSTR name;
     tid_t tid;
+    int func_disp_idx;
 } func_info_t;
 
 struct dispex_data_t {
     DWORD func_cnt;
     func_info_t *funcs;
     func_info_t **name_table;
+    DWORD func_disp_cnt;
 
     struct list entry;
 };
@@ -50,10 +52,20 @@ typedef struct {
     LPWSTR name;
 } dynamic_prop_t;
 
+typedef struct {
+    DispatchEx dispex;
+    const IUnknownVtbl *lpIUnknownVtbl;
+    DispatchEx *obj;
+    func_info_t *info;
+} func_disp_t;
+
+#define FUNCUNKNOWN(x)  ((IUnknown*) &(x)->lpIUnknownVtbl)
+
 struct dispex_dynamic_data_t {
     DWORD buf_size;
     DWORD prop_cnt;
     dynamic_prop_t *props;
+    func_disp_t **func_disps;
 };
 
 #define DISPID_DYNPROP_0    0x50000000
@@ -188,22 +200,23 @@ void release_typelib(void)
     ITypeLib_Release(typelib);
 }
 
-static void add_func_info(dispex_data_t *data, DWORD *size, tid_t tid, DISPID id, ITypeInfo *dti)
+static void add_func_info(dispex_data_t *data, DWORD *size, tid_t tid, const FUNCDESC *desc, ITypeInfo *dti)
 {
     HRESULT hres;
 
-    if(data->func_cnt && data->funcs[data->func_cnt-1].id == id)
+    if(data->func_cnt && data->funcs[data->func_cnt-1].id == desc->memid)
         return;
 
     if(data->func_cnt == *size)
         data->funcs = heap_realloc(data->funcs, (*size <<= 1)*sizeof(func_info_t));
 
-    hres = ITypeInfo_GetDocumentation(dti, id, &data->funcs[data->func_cnt].name, NULL, NULL, NULL);
+    hres = ITypeInfo_GetDocumentation(dti, desc->memid, &data->funcs[data->func_cnt].name, NULL, NULL, NULL);
     if(FAILED(hres))
         return;
 
-    data->funcs[data->func_cnt].id = id;
+    data->funcs[data->func_cnt].id = desc->memid;
     data->funcs[data->func_cnt].tid = tid;
+    data->funcs[data->func_cnt].func_disp_idx = desc->invkind == INVOKE_FUNC ? data->func_disp_cnt++ : -1;
 
     data->func_cnt++;
 }
@@ -237,6 +250,7 @@ static dispex_data_t *preprocess_dispex_data(DispatchEx *This)
 
     data = heap_alloc(sizeof(dispex_data_t));
     data->func_cnt = 0;
+    data->func_disp_cnt = 0;
     data->funcs = heap_alloc(size*sizeof(func_info_t));
     list_add_tail(&dispex_data_list, &data->entry);
 
@@ -251,7 +265,7 @@ static dispex_data_t *preprocess_dispex_data(DispatchEx *This)
             if(FAILED(hres))
                 break;
 
-            add_func_info(data, &size, *tid, funcdesc->memid, dti);
+            add_func_info(data, &size, *tid, funcdesc, dti);
             ITypeInfo_ReleaseFuncDesc(ti, funcdesc);
         }
 
@@ -343,55 +357,56 @@ static inline BOOL is_dynamic_dispid(DISPID id)
     return DISPID_DYNPROP_0 <= id && id <= DISPID_DYNPROP_MAX;
 }
 
+static inline dispex_dynamic_data_t *get_dynamic_data(DispatchEx *This, BOOL alloc)
+{
+    return !alloc || This->dynamic_data
+        ? This->dynamic_data
+        : (This->dynamic_data = heap_alloc_zero(sizeof(dispex_dynamic_data_t)));
+}
+
 static HRESULT get_dynamic_prop(DispatchEx *This, const WCHAR *name, BOOL alloc, dynamic_prop_t **ret)
 {
-    dispex_dynamic_data_t *data = This->dynamic_data;
+    dispex_dynamic_data_t *data = get_dynamic_data(This, alloc);
+    unsigned i;
 
-    if(data) {
-        unsigned i;
+    if(!data) {
+        if(alloc)
+            return E_OUTOFMEMORY;
 
-        for(i=0; i < data->prop_cnt; i++) {
-            if(!strcmpW(data->props[i].name, name)) {
-                *ret = data->props+i;
-                return S_OK;
-            }
-        }
+        TRACE("not found %s\n", debugstr_w(name));
+        return DISP_E_UNKNOWNNAME;
     }
 
-    if(alloc) {
-        TRACE("creating dynamic prop %s\n", debugstr_w(name));
-
-        if(!data) {
-            data = This->dynamic_data = heap_alloc_zero(sizeof(dispex_dynamic_data_t));
-            if(!data)
-                return E_OUTOFMEMORY;
+    for(i=0; i < data->prop_cnt; i++) {
+        if(!strcmpW(data->props[i].name, name)) {
+            *ret = data->props+i;
+            return S_OK;
         }
+    }
 
-        if(!data->buf_size) {
-            data->props = heap_alloc(sizeof(dynamic_prop_t)*4);
-            if(!data->props)
-                return E_OUTOFMEMORY;
-            data->buf_size = 4;
-        }else if(data->buf_size == data->prop_cnt) {
-            dynamic_prop_t *new_props;
+    TRACE("creating dynamic prop %s\n", debugstr_w(name));
 
-            new_props = heap_realloc(data->props, sizeof(dynamic_prop_t)*(data->buf_size<<1));
-            if(!new_props)
-                return E_OUTOFMEMORY;
+    if(!data->buf_size) {
+        data->props = heap_alloc(sizeof(dynamic_prop_t)*4);
+        if(!data->props)
+            return E_OUTOFMEMORY;
+        data->buf_size = 4;
+    }else if(data->buf_size == data->prop_cnt) {
+        dynamic_prop_t *new_props;
 
-            data->props = new_props;
-            data->buf_size <<= 1;
-        }
+        new_props = heap_realloc(data->props, sizeof(dynamic_prop_t)*(data->buf_size<<1));
+        if(!new_props)
+            return E_OUTOFMEMORY;
 
-        data->props[data->prop_cnt].name = heap_strdupW(name);
-        VariantInit(&data->props[data->prop_cnt].var);
-        *ret = data->props + data->prop_cnt++;
-
-        return S_OK;
+        data->props = new_props;
+        data->buf_size <<= 1;
     }
 
-    TRACE("not found %s\n", debugstr_w(name));
-    return DISP_E_UNKNOWNNAME;
+    data->props[data->prop_cnt].name = heap_strdupW(name);
+    VariantInit(&data->props[data->prop_cnt].var);
+    *ret = data->props + data->prop_cnt++;
+
+    return S_OK;
 }
 
 HRESULT dispex_get_dprop_ref(DispatchEx *This, const WCHAR *name, BOOL alloc, VARIANT **ret)
@@ -407,6 +422,191 @@ HRESULT dispex_get_dprop_ref(DispatchEx *This, const WCHAR *name, BOOL alloc, VA
     return S_OK;
 }
 
+static HRESULT dispex_value(DispatchEx *This, LCID lcid, WORD flags, DISPPARAMS *params,
+        VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
+{
+    static const WCHAR objectW[] = {'[','o','b','j','e','c','t',']',0};
+
+    if(This->data->vtbl && This->data->vtbl->value)
+        return This->data->vtbl->value(This->outer, lcid, flags, params, res, ei, caller);
+
+    switch(flags) {
+    case DISPATCH_PROPERTYGET:
+        V_VT(res) = VT_BSTR;
+        V_BSTR(res) = SysAllocString(objectW);
+        if(!V_BSTR(res))
+            return E_OUTOFMEMORY;
+        break;
+    default:
+        FIXME("Unimplemented flags %x\n", flags);
+        return E_NOTIMPL;
+    }
+
+    return S_OK;
+}
+
+static HRESULT typeinfo_invoke(DispatchEx *This, func_info_t *func, WORD flags, DISPPARAMS *dp, VARIANT *res,
+        EXCEPINFO *ei)
+{
+    ITypeInfo *ti;
+    IUnknown *unk;
+    UINT argerr=0;
+    HRESULT hres;
+
+    hres = get_typeinfo(func->tid, &ti);
+    if(FAILED(hres)) {
+        ERR("Could not get type info: %08x\n", hres);
+        return hres;
+    }
+
+    hres = IUnknown_QueryInterface(This->outer, tid_ids[func->tid], (void**)&unk);
+    if(FAILED(hres)) {
+        ERR("Could not get iface %s: %08x\n", debugstr_guid(tid_ids[func->tid]), hres);
+        return E_FAIL;
+    }
+
+    hres = ITypeInfo_Invoke(ti, unk, func->id, flags, dp, res, ei, &argerr);
+
+    IUnknown_Release(unk);
+    return hres;
+}
+
+#define FUNCTION_THIS(iface) DEFINE_THIS(func_disp_t, IUnknown, iface)
+
+static HRESULT WINAPI Function_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
+{
+    func_disp_t *This = FUNCTION_THIS(iface);
+
+    if(IsEqualGUID(&IID_IUnknown, riid)) {
+        TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
+        *ppv = FUNCUNKNOWN(This);
+    }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
+        return *ppv ? S_OK : E_NOINTERFACE;
+    }else {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI Function_AddRef(IUnknown *iface)
+{
+    func_disp_t *This = FUNCTION_THIS(iface);
+
+    TRACE("(%p)\n", This);
+
+    return IDispatchEx_AddRef(DISPATCHEX(This->obj));
+}
+
+static ULONG WINAPI Function_Release(IUnknown *iface)
+{
+    func_disp_t *This = FUNCTION_THIS(iface);
+
+    TRACE("(%p)\n", This);
+
+    return IDispatchEx_Release(DISPATCHEX(This->obj));
+}
+
+static HRESULT function_value(IUnknown *iface, LCID lcid, WORD flags, DISPPARAMS *params,
+        VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
+{
+    func_disp_t *This = FUNCTION_THIS(iface);
+    HRESULT hres;
+
+    switch(flags) {
+    case DISPATCH_METHOD:
+        hres = typeinfo_invoke(This->obj, This->info, flags, params, res, ei);
+        break;
+    default:
+        FIXME("Unimplemented flags %x\n", flags);
+        hres = E_NOTIMPL;
+    }
+
+    return hres;
+}
+
+#undef FUNCTION_THIS
+
+static const IUnknownVtbl FunctionUnkVtbl = {
+    Function_QueryInterface,
+    Function_AddRef,
+    Function_Release
+};
+
+static const dispex_static_data_vtbl_t function_dispex_vtbl = {
+    function_value,
+    NULL,
+    NULL
+};
+
+static dispex_static_data_t function_dispex = {
+    &function_dispex_vtbl,
+    LAST_tid,
+    NULL,
+    NULL
+};
+
+static func_disp_t *create_func_disp(DispatchEx *obj, func_info_t *info)
+{
+    func_disp_t *ret;
+
+    ret = heap_alloc_zero(sizeof(func_disp_t));
+    if(!ret)
+        return NULL;
+
+    ret->lpIUnknownVtbl = &FunctionUnkVtbl;
+    init_dispex(&ret->dispex, FUNCUNKNOWN(ret),  &function_dispex);
+    ret->obj = obj;
+    ret->info = info;
+
+    return ret;
+}
+
+static HRESULT function_invoke(DispatchEx *This, func_info_t *func, WORD flags, DISPPARAMS *dp, VARIANT *res,
+        EXCEPINFO *ei)
+{
+    HRESULT hres;
+
+    switch(flags) {
+    case DISPATCH_METHOD:
+        hres = typeinfo_invoke(This, func, flags, dp, res, ei);
+        break;
+    case DISPATCH_PROPERTYGET: {
+        dispex_dynamic_data_t *dynamic_data;
+
+        dynamic_data = get_dynamic_data(This, TRUE);
+        if(!dynamic_data)
+            return E_OUTOFMEMORY;
+
+        if(!dynamic_data->func_disps) {
+            dynamic_data->func_disps = heap_alloc_zero(This->data->data->func_disp_cnt * sizeof(func_disp_t*));
+            if(!dynamic_data->func_disps)
+                return E_OUTOFMEMORY;
+        }
+
+        if(!dynamic_data->func_disps[func->func_disp_idx]) {
+            dynamic_data->func_disps[func->func_disp_idx] = create_func_disp(This, func);
+            if(!dynamic_data->func_disps[func->func_disp_idx])
+                return E_OUTOFMEMORY;
+        }
+
+        V_VT(res) = VT_DISPATCH;
+        V_DISPATCH(res) = (IDispatch*)DISPATCHEX(&dynamic_data->func_disps[func->func_disp_idx]->dispex);
+        IDispatch_AddRef(V_DISPATCH(res));
+        hres = S_OK;
+        break;
+    }
+    default:
+        FIXME("Unimplemented flags %x\n", flags);
+    case DISPATCH_PROPERTYPUT:
+        hres = E_NOTIMPL;
+    }
+
+    return hres;
+}
+
 #define DISPATCHEX_THIS(iface) DEFINE_THIS(DispatchEx, IDispatchEx, iface)
 
 static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
@@ -547,15 +747,15 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc
         VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
 {
     DispatchEx *This = DISPATCHEX_THIS(iface);
-    IUnknown *unk;
-    ITypeInfo *ti;
     dispex_data_t *data;
-    UINT argerr=0;
     int min, max, n;
     HRESULT hres;
 
     TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
 
+    if(id == DISPID_VALUE)
+        return dispex_value(This, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
+
     if(is_custom_dispid(id) && This->data->vtbl && This->data->vtbl->invoke)
         return This->data->vtbl->invoke(This->outer, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
 
@@ -648,21 +848,11 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc
         return DISP_E_UNKNOWNNAME;
     }
 
-    hres = get_typeinfo(data->funcs[n].tid, &ti);
-    if(FAILED(hres)) {
-        ERR("Could not get type info: %08x\n", hres);
-        return hres;
-    }
-
-    hres = IUnknown_QueryInterface(This->outer, tid_ids[data->funcs[n].tid], (void**)&unk);
-    if(FAILED(hres)) {
-        ERR("Could not get iface %s: %08x\n", debugstr_guid(tid_ids[data->funcs[n].tid]), hres);
-        return E_FAIL;
-    }
+    if(data->funcs[n].func_disp_idx == -1)
+        hres = typeinfo_invoke(This, data->funcs+n, wFlags, pdp, pvarRes, pei);
+    else
+        hres = function_invoke(This, data->funcs+n, wFlags, pdp, pvarRes, pei);
 
-    hres = ITypeInfo_Invoke(ti, unk, id, wFlags, pdp, pvarRes, pei, &argerr);
-
-    IUnknown_Release(unk);
     return hres;
 }
 
@@ -756,9 +946,40 @@ BOOL dispex_query_interface(DispatchEx *This, REFIID riid, void **ppv)
     return TRUE;
 }
 
+void release_dispex(DispatchEx *This)
+{
+    dynamic_prop_t *prop;
+
+    if(!This->dynamic_data)
+        return;
+
+    for(prop = This->dynamic_data->props; prop < This->dynamic_data->props + This->dynamic_data->prop_cnt; prop++) {
+        VariantClear(&prop->var);
+        heap_free(prop->name);
+    }
+
+    heap_free(This->dynamic_data->props);
+
+    if(This->dynamic_data->func_disps) {
+        unsigned i;
+
+        for(i=0; i < This->data->data->func_disp_cnt; i++) {
+            if(This->dynamic_data->func_disps[i]) {
+                release_dispex(&This->dynamic_data->func_disps[i]->dispex);
+                heap_free(This->dynamic_data->func_disps[i]);
+            }
+        }
+
+        heap_free(This->dynamic_data->func_disps);
+    }
+
+    heap_free(This->dynamic_data);
+}
+
 void init_dispex(DispatchEx *dispex, IUnknown *outer, dispex_static_data_t *data)
 {
     dispex->lpIDispatchExVtbl = &DispatchExVtbl;
     dispex->outer = outer;
     dispex->data = data;
+    dispex->dynamic_data = NULL;
 }
index 5aaaece..d622239 100644 (file)
@@ -90,6 +90,7 @@ static ULONG WINAPI HTMLCurrentStyle_Release(IHTMLCurrentStyle *iface)
     if(!ref) {
         if(This->nsstyle)
             nsIDOMCSSStyleDeclaration_Release(This->nsstyle);
+        release_dispex(&This->dispex);
         heap_free(This);
     }
 
@@ -144,15 +145,15 @@ static HRESULT WINAPI HTMLCurrentStyle_get_styleFloat(IHTMLCurrentStyle *iface,
 static HRESULT WINAPI HTMLCurrentStyle_get_color(IHTMLCurrentStyle *iface, VARIANT *p)
 {
     HTMLCurrentStyle *This = HTMLCURSTYLE_THIS(iface);
-    FIXME("(%p)->(%p)\n", This, p);
-    return E_NOTIMPL;
+    TRACE("(%p)->(%p)\n", This, p);
+    return get_nsstyle_attr_var(This->nsstyle, STYLEID_COLOR, p, 0);
 }
 
 static HRESULT WINAPI HTMLCurrentStyle_get_backgroundColor(IHTMLCurrentStyle *iface, VARIANT *p)
 {
     HTMLCurrentStyle *This = HTMLCURSTYLE_THIS(iface);
-    FIXME("(%p)->(%p)\n", This, p);
-    return E_NOTIMPL;
+    TRACE("(%p)->(%p)\n", This, p);
+    return get_nsstyle_attr_var(This->nsstyle, STYLEID_BACKGROUND_COLOR, p, 0);
 }
 
 static HRESULT WINAPI HTMLCurrentStyle_get_fontFamily(IHTMLCurrentStyle *iface, BSTR *p)
@@ -279,29 +280,29 @@ static HRESULT WINAPI HTMLCurrentStyle_get_borderLeftStyle(IHTMLCurrentStyle *if
 static HRESULT WINAPI HTMLCurrentStyle_get_borderTopWidth(IHTMLCurrentStyle *iface, VARIANT *p)
 {
     HTMLCurrentStyle *This = HTMLCURSTYLE_THIS(iface);
-    FIXME("(%p)->(%p)\n", This, p);
-    return E_NOTIMPL;
+    TRACE("(%p)->(%p)\n", This, p);
+    return get_nsstyle_attr_var(This->nsstyle, STYLEID_BORDER_TOP_WIDTH, p, 0);
 }
 
 static HRESULT WINAPI HTMLCurrentStyle_get_borderRightWidth(IHTMLCurrentStyle *iface, VARIANT *p)
 {
     HTMLCurrentStyle *This = HTMLCURSTYLE_THIS(iface);
-    FIXME("(%p)->(%p)\n", This, p);
-    return E_NOTIMPL;
+    TRACE("(%p)->(%p)\n", This, p);
+    return get_nsstyle_attr_var(This->nsstyle, STYLEID_BORDER_RIGHT_WIDTH, p, 0);
 }
 
 static HRESULT WINAPI HTMLCurrentStyle_get_borderBottomWidth(IHTMLCurrentStyle *iface, VARIANT *p)
 {
     HTMLCurrentStyle *This = HTMLCURSTYLE_THIS(iface);
-    FIXME("(%p)->(%p)\n", This, p);
-    return E_NOTIMPL;
+    TRACE("(%p)->(%p)\n", This, p);
+    return get_nsstyle_attr_var(This->nsstyle, STYLEID_BORDER_BOTTOM_WIDTH, p, 0);
 }
 
 static HRESULT WINAPI HTMLCurrentStyle_get_borderLeftWidth(IHTMLCurrentStyle *iface, VARIANT *p)
 {
     HTMLCurrentStyle *This = HTMLCURSTYLE_THIS(iface);
-    FIXME("(%p)->(%p)\n", This, p);
-    return E_NOTIMPL;
+    TRACE("(%p)->(%p)\n", This, p);
+    return get_nsstyle_attr_var(This->nsstyle, STYLEID_BORDER_LEFT_WIDTH, p, 0);
 }
 
 static HRESULT WINAPI HTMLCurrentStyle_get_left(IHTMLCurrentStyle *iface, VARIANT *p)
@@ -386,8 +387,10 @@ static HRESULT WINAPI HTMLCurrentStyle_get_display(IHTMLCurrentStyle *iface, BST
 static HRESULT WINAPI HTMLCurrentStyle_get_visibility(IHTMLCurrentStyle *iface, BSTR *p)
 {
     HTMLCurrentStyle *This = HTMLCURSTYLE_THIS(iface);
-    FIXME("(%p)->(%p)\n", This, p);
-    return E_NOTIMPL;
+
+    TRACE("(%p)->(%p)\n", This, p);
+
+    return get_nsstyle_attr(This->nsstyle, STYLEID_VISIBILITY, p);
 }
 
 static HRESULT WINAPI HTMLCurrentStyle_get_zIndex(IHTMLCurrentStyle *iface, VARIANT *p)
@@ -519,8 +522,8 @@ static HRESULT WINAPI HTMLCurrentStyle_get_clipLeft(IHTMLCurrentStyle *iface, VA
 static HRESULT WINAPI HTMLCurrentStyle_get_overflow(IHTMLCurrentStyle *iface, BSTR *p)
 {
     HTMLCurrentStyle *This = HTMLCURSTYLE_THIS(iface);
-    FIXME("(%p)->(%p)\n", This, p);
-    return E_NOTIMPL;
+    TRACE("(%p)->(%p)\n", This, p);
+    return get_nsstyle_attr(This->nsstyle, STYLEID_OVERFLOW, p);
 }
 
 static HRESULT WINAPI HTMLCurrentStyle_get_pageBreakBefore(IHTMLCurrentStyle *iface, BSTR *p)
@@ -723,8 +726,8 @@ static HRESULT WINAPI HTMLCurrentStyle_get_borderColor(IHTMLCurrentStyle *iface,
 static HRESULT WINAPI HTMLCurrentStyle_get_borderWidth(IHTMLCurrentStyle *iface, BSTR *p)
 {
     HTMLCurrentStyle *This = HTMLCURSTYLE_THIS(iface);
-    FIXME("(%p)->(%p)\n", This, p);
-    return E_NOTIMPL;
+    TRACE("(%p)->(%p)\n", This, p);
+    return get_nsstyle_attr(This->nsstyle, STYLEID_BORDER_WIDTH, p);
 }
 
 static HRESULT WINAPI HTMLCurrentStyle_get_padding(IHTMLCurrentStyle *iface, BSTR *p)
@@ -737,8 +740,8 @@ static HRESULT WINAPI HTMLCurrentStyle_get_padding(IHTMLCurrentStyle *iface, BST
 static HRESULT WINAPI HTMLCurrentStyle_get_margin(IHTMLCurrentStyle *iface, BSTR *p)
 {
     HTMLCurrentStyle *This = HTMLCURSTYLE_THIS(iface);
-    FIXME("(%p)->(%p)\n", This, p);
-    return E_NOTIMPL;
+    TRACE("(%p)->(%p)\n", This, p);
+    return get_nsstyle_attr(This->nsstyle, STYLEID_MARGIN, p);
 }
 
 static HRESULT WINAPI HTMLCurrentStyle_get_accelerator(IHTMLCurrentStyle *iface, BSTR *p)
index 0b95229..d5b6cbe 100644 (file)
@@ -215,6 +215,7 @@ static ULONG WINAPI HTMLDocument_Release(IHTMLDocument2 *iface)
         detach_selection(This);
         detach_ranges(This);
         release_nodes(This);
+        release_dispex(&This->dispex);
 
         ConnectionPointContainer_Destroy(&This->cp_container);
 
@@ -900,17 +901,14 @@ static HRESULT WINAPI HTMLDocument_get_nameProp(IHTMLDocument2 *iface, BSTR *p)
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI HTMLDocument_write(IHTMLDocument2 *iface, SAFEARRAY *psarray)
+static HRESULT document_write(HTMLDocument *This, SAFEARRAY *psarray, BOOL ln)
 {
-    HTMLDocument *This = HTMLDOC_THIS(iface);
     nsAString nsstr;
     VARIANT *var;
-    ULONG i;
+    ULONG i, argc;
     nsresult nsres;
     HRESULT hres;
 
-    TRACE("(%p)->(%p)\n", iface, psarray);
-
     if(!This->nsdoc) {
         WARN("NULL nsdoc\n");
         return E_UNEXPECTED;
@@ -929,10 +927,14 @@ static HRESULT WINAPI HTMLDocument_write(IHTMLDocument2 *iface, SAFEARRAY *psarr
 
     nsAString_Init(&nsstr, NULL);
 
-    for(i=0; i < psarray->rgsabound[0].cElements; i++) {
+    argc = psarray->rgsabound[0].cElements;
+    for(i=0; i < argc; i++) {
         if(V_VT(var+i) == VT_BSTR) {
             nsAString_SetData(&nsstr, V_BSTR(var+i));
-            nsres = nsIDOMHTMLDocument_Write(This->nsdoc, &nsstr);
+            if(!ln || i != argc-1)
+                nsres = nsIDOMHTMLDocument_Write(This->nsdoc, &nsstr);
+            else
+                nsres = nsIDOMHTMLDocument_Writeln(This->nsdoc, &nsstr);
             if(NS_FAILED(nsres))
                 ERR("Write failed: %08x\n", nsres);
         }else {
@@ -946,11 +948,22 @@ static HRESULT WINAPI HTMLDocument_write(IHTMLDocument2 *iface, SAFEARRAY *psarr
     return S_OK;
 }
 
+static HRESULT WINAPI HTMLDocument_write(IHTMLDocument2 *iface, SAFEARRAY *psarray)
+{
+    HTMLDocument *This = HTMLDOC_THIS(iface);
+
+    TRACE("(%p)->(%p)\n", iface, psarray);
+
+    return document_write(This, psarray, FALSE);
+}
+
 static HRESULT WINAPI HTMLDocument_writeln(IHTMLDocument2 *iface, SAFEARRAY *psarray)
 {
     HTMLDocument *This = HTMLDOC_THIS(iface);
-    FIXME("(%p)->(%p)\n", This, psarray);
-    return E_NOTIMPL;
+
+    TRACE("(%p)->(%p)\n", This, psarray);
+
+    return document_write(This, psarray, TRUE);
 }
 
 static HRESULT WINAPI HTMLDocument_open(IHTMLDocument2 *iface, BSTR url, VARIANT name,
index 170d5a0..84f6309 100644 (file)
@@ -931,8 +931,26 @@ static HRESULT WINAPI HTMLElement_put_outerHTML(IHTMLElement *iface, BSTR v)
 static HRESULT WINAPI HTMLElement_get_outerHTML(IHTMLElement *iface, BSTR *p)
 {
     HTMLElement *This = HTMLELEM_THIS(iface);
-    FIXME("(%p)->(%p)\n", This, p);
-    return E_NOTIMPL;
+    nsAString html_str;
+    HRESULT hres;
+
+    WARN("(%p)->(%p) semi-stub\n", This, p);
+
+    nsAString_Init(&html_str, NULL);
+    hres = nsnode_to_nsstring(This->node.nsnode, &html_str);
+    if(SUCCEEDED(hres)) {
+        const PRUnichar *html;
+
+        nsAString_GetData(&html_str, &html);
+        *p = SysAllocString(html);
+        if(!*p)
+            hres = E_OUTOFMEMORY;
+    }
+
+    nsAString_Finish(&html_str);
+
+    TRACE("ret %s\n", debugstr_w(*p));
+    return S_OK;
 }
 
 static HRESULT WINAPI HTMLElement_put_outerText(IHTMLElement *iface, BSTR v)
index 4362890..63fcb80 100644 (file)
@@ -132,6 +132,7 @@ static ULONG WINAPI HTMLElementCollection_Release(IHTMLElementCollection *iface)
 
     if(!ref) {
         IUnknown_Release(This->ref_unk);
+        release_dispex(&This->dispex);
         heap_free(This->elems);
         heap_free(This);
     }
@@ -428,6 +429,7 @@ static const IHTMLElementCollectionVtbl HTMLElementCollectionVtbl = {
 };
 
 static const dispex_static_data_vtbl_t HTMLElementColection_dispex_vtbl = {
+    NULL,
     HTMLElementCollection_get_dispid,
     HTMLElementCollection_invoke
 };
index b73f865..ca7166c 100644 (file)
@@ -176,8 +176,10 @@ static ULONG WINAPI HTMLEventObj_Release(IHTMLEventObj *iface)
 
     TRACE("(%p) ref=%d\n", This, ref);
 
-    if(!ref)
+    if(!ref) {
+        release_dispex(&This->dispex);
         heap_free(This);
+    }
 
     return ref;
 }
index eaffae5..df7cb5f 100644 (file)
@@ -839,7 +839,7 @@ static HRESULT WINAPI HTMLInputTextElement_get_value(IHTMLInputTextElement *ifac
 
     TRACE("(%p)->(%p)\n", This, p);
 
-    return IHTMLInputTextElement_get_value(HTMLINPUT(This), p);
+    return IHTMLInputElement_get_value(HTMLINPUT(This), p);
 }
 
 static HRESULT WINAPI HTMLInputTextElement_put_name(IHTMLInputTextElement *iface, BSTR v)
index 35f042a..8637838 100644 (file)
 #include "windef.h"
 #include "winbase.h"
 #include "winuser.h"
+#include "winreg.h"
 #include "ole2.h"
+#include "wininet.h"
+#include "shlwapi.h"
 
 #include "wine/debug.h"
 
@@ -79,6 +82,7 @@ static ULONG WINAPI HTMLLocation_Release(IHTMLLocation *iface)
     if(!ref) {
         if(This->doc && This->doc->location == This)
             This->doc->location = NULL;
+        release_dispex(&This->dispex);
         heap_free(This);
     }
 
@@ -125,8 +129,20 @@ static HRESULT WINAPI HTMLLocation_put_href(IHTMLLocation *iface, BSTR v)
 static HRESULT WINAPI HTMLLocation_get_href(IHTMLLocation *iface, BSTR *p)
 {
     HTMLLocation *This = HTMLLOCATION_THIS(iface);
-    FIXME("(%p)->(%p)\n", This, p);
-    return E_NOTIMPL;
+
+    TRACE("(%p)->(%p)\n", This, p);
+
+    if(!p)
+        return E_POINTER;
+
+    if(!This->doc || !This->doc->url) {
+        FIXME("No current URL\n");
+        return E_NOTIMPL;
+    }
+
+    *p = SysAllocString(This->doc->url);
+
+    return S_OK;
 }
 
 static HRESULT WINAPI HTMLLocation_put_protocol(IHTMLLocation *iface, BSTR v)
@@ -195,8 +211,41 @@ static HRESULT WINAPI HTMLLocation_put_pathname(IHTMLLocation *iface, BSTR v)
 static HRESULT WINAPI HTMLLocation_get_pathname(IHTMLLocation *iface, BSTR *p)
 {
     HTMLLocation *This = HTMLLOCATION_THIS(iface);
-    FIXME("(%p)->(%p)\n", This, p);
-    return E_NOTIMPL;
+    WCHAR buf[INTERNET_MAX_PATH_LENGTH];
+    URL_COMPONENTSW url = {sizeof(url)};
+    DWORD size = 0;
+    HRESULT hres;
+
+    TRACE("(%p)->(%p)\n", This, p);
+
+    if(!This->doc || !This->doc->url) {
+        FIXME("No current URL\n");
+        return E_NOTIMPL;
+    }
+
+    hres = CoInternetParseUrl(This->doc->url, PARSE_PATH_FROM_URL, 0, buf, sizeof(buf), &size, 0);
+    if(SUCCEEDED(hres)) {
+        *p = SysAllocString(buf);
+        if(!*p)
+            return E_OUTOFMEMORY;
+        return S_OK;
+    }
+
+    url.dwUrlPathLength = 1;
+    if(!InternetCrackUrlW(This->doc->url, 0, 0, &url)) {
+        FIXME("InternetCrackUrl failed\n");
+        return E_FAIL;
+    }
+
+    if(!url.dwUrlPathLength) {
+        *p = NULL;
+        return S_OK;
+    }
+
+    *p = SysAllocStringLen(url.lpszUrlPath, url.dwUrlPathLength);
+    if(!*p)
+        return E_OUTOFMEMORY;
+    return S_OK;
 }
 
 static HRESULT WINAPI HTMLLocation_put_search(IHTMLLocation *iface, BSTR v)
@@ -255,6 +304,34 @@ static HRESULT WINAPI HTMLLocation_toString(IHTMLLocation *iface, BSTR *String)
     return E_NOTIMPL;
 }
 
+static HRESULT HTMLLocation_value(IUnknown *iface, LCID lcid, WORD flags, DISPPARAMS *params,
+        VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
+{
+    HTMLLocation *This = HTMLLOCATION_THIS(iface);
+    HRESULT hres;
+
+    TRACE("(%p)\n", This);
+
+    switch(flags) {
+    case DISPATCH_PROPERTYGET: {
+        BSTR str;
+
+        hres = IHTMLLocation_get_href(HTMLLOCATION(This), &str);
+        if(FAILED(hres))
+            return hres;
+
+        V_VT(res) = VT_BSTR;
+        V_BSTR(res) = str;
+        break;
+    }
+    default:
+        FIXME("unimplemented flags %x\n", flags);
+        return E_NOTIMPL;
+    }
+
+    return S_OK;
+}
+
 #undef HTMLLOCATION_THIS
 
 static const IHTMLLocationVtbl HTMLLocationVtbl = {
@@ -287,12 +364,18 @@ static const IHTMLLocationVtbl HTMLLocationVtbl = {
     HTMLLocation_toString
 };
 
+static const dispex_static_data_vtbl_t HTMLLocation_dispex_vtbl = {
+    HTMLLocation_value,
+    NULL,
+    NULL
+};
+
 static const tid_t HTMLLocation_iface_tids[] = {
     IHTMLLocation_tid,
     0
 };
 static dispex_static_data_t HTMLLocation_dispex = {
-    NULL,
+    &HTMLLocation_dispex_vtbl,
     DispHTMLLocation_tid,
     NULL,
     HTMLLocation_iface_tids
index 720bbfe..30fdac8 100644 (file)
@@ -250,6 +250,7 @@ static const tid_t HTMLDOMChildrenCollection_iface_tids[] = {
 };
 
 static const dispex_static_data_vtbl_t HTMLDOMChildrenCollection_dispex_vtbl = {
+    NULL,
     HTMLDOMChildrenCollection_get_dispid,
     HTMLDOMChildrenCollection_invoke
 };
@@ -307,6 +308,7 @@ static ULONG WINAPI HTMLDOMNode_Release(IHTMLDOMNode *iface)
 
     if(!ref) {
         This->vtbl->destructor(This);
+        release_dispex(&This->dispex);
         heap_free(This);
     }
 
index f036077..a993702 100644 (file)
@@ -59,6 +59,8 @@ static const WCHAR attrBorderLeft[] =
     {'b','o','r','d','e','r','-','l','e','f','t',0};
 static const WCHAR attrBorderLeftStyle[] =
     {'b','o','r','d','e','r','-','l','e','f','t','-','s','t','y','l','e',0};
+static const WCHAR attrBorderLeftWidth[] =
+    {'b','o','r','d','e','r','-','l','e','f','t','-','w','i','d','t','h',0};
 static const WCHAR attrBorderRightStyle[] =
     {'b','o','r','d','e','r','-','r','i','g','h','t','-','s','t','y','l','e',0};
 static const WCHAR attrBorderRightWidth[] =
@@ -93,6 +95,8 @@ static const WCHAR attrHeight[] =
     {'h','e','i','g','h','t',0};
 static const WCHAR attrLeft[] =
     {'l','e','f','t',0};
+static const WCHAR attrLetterSpacing[] =
+    {'l','e','t','t','e','r','-','s','p','a','c','i','n','g',0};
 static const WCHAR attrMargin[] =
     {'m','a','r','g','i','n',0};
 static const WCHAR attrMarginLeft[] =
@@ -119,6 +123,8 @@ static const WCHAR attrVisibility[] =
     {'v','i','s','i','b','i','l','i','t','y',0};
 static const WCHAR attrWidth[] =
     {'w','i','d','t','h',0};
+static const WCHAR attrWordSpacing[] =
+    {'w','o','r','d','-','s','p','a','c','i','n','g',0};
 static const WCHAR attrWordWrap[] =
     {'w','o','r','d','-','w','r','a','p',0};
 static const WCHAR attrZIndex[] =
@@ -140,6 +146,7 @@ static const struct{
     {attrBorderColor,          DISPID_IHTMLSTYLE_BORDERCOLOR},
     {attrBorderLeft,           DISPID_IHTMLSTYLE_BORDERLEFT},
     {attrBorderLeftStyle,      DISPID_IHTMLSTYLE_BORDERLEFTSTYLE},
+    {attrBorderLeftWidth,      DISPID_IHTMLSTYLE_BORDERLEFTWIDTH},
     {attrBorderRightStyle,     DISPID_IHTMLSTYLE_BORDERRIGHTSTYLE},
     {attrBorderRightWidth,     DISPID_IHTMLSTYLE_BORDERRIGHTWIDTH},
     {attrBorderStyle,          DISPID_IHTMLSTYLE_BORDERSTYLE},
@@ -157,6 +164,7 @@ static const struct{
     {attrFontWeight,           DISPID_IHTMLSTYLE_FONTWEIGHT},
     {attrHeight,               DISPID_IHTMLSTYLE_HEIGHT},
     {attrLeft,                 DISPID_IHTMLSTYLE_LEFT},
+    {attrLetterSpacing,        DISPID_IHTMLSTYLE_LETTERSPACING},
     {attrMargin,               DISPID_IHTMLSTYLE_MARGIN},
     {attrMarginLeft,           DISPID_IHTMLSTYLE_MARGINLEFT},
     {attrMarginRight,          DISPID_IHTMLSTYLE_MARGINRIGHT},
@@ -170,6 +178,7 @@ static const struct{
     {attrVerticalAlign,        DISPID_IHTMLSTYLE_VERTICALALIGN},
     {attrVisibility,           DISPID_IHTMLSTYLE_VISIBILITY},
     {attrWidth,                DISPID_IHTMLSTYLE_WIDTH},
+    {attrWordSpacing,          DISPID_IHTMLSTYLE_WORDSPACING},
     {attrWordWrap,             DISPID_IHTMLSTYLE3_WORDWRAP},
     {attrZIndex,               DISPID_IHTMLSTYLE_ZINDEX}
 };
@@ -545,6 +554,7 @@ static ULONG WINAPI HTMLStyle_Release(IHTMLStyle *iface)
     if(!ref) {
         if(This->nsstyle)
             nsIDOMCSSStyleDeclaration_Release(This->nsstyle);
+        release_dispex(&This->dispex);
         heap_free(This);
     }
 
@@ -920,29 +930,29 @@ static HRESULT WINAPI HTMLStyle_get_backgroundPositionY(IHTMLStyle *iface, VARIA
 static HRESULT WINAPI HTMLStyle_put_wordSpacing(IHTMLStyle *iface, VARIANT v)
 {
     HTMLStyle *This = HTMLSTYLE_THIS(iface);
-    FIXME("(%p)->(v%d)\n", This, V_VT(&v));
-    return E_NOTIMPL;
+    TRACE("(%p)->(v%d)\n", This, V_VT(&v));
+    return set_nsstyle_attr_var(This->nsstyle, STYLEID_WORD_SPACING, &v, 0);
 }
 
 static HRESULT WINAPI HTMLStyle_get_wordSpacing(IHTMLStyle *iface, VARIANT *p)
 {
     HTMLStyle *This = HTMLSTYLE_THIS(iface);
-    FIXME("(%p)->(%p)\n", This, p);
-    return E_NOTIMPL;
+    TRACE("(%p)->(%p)\n", This, p);
+    return get_nsstyle_attr_var(This->nsstyle, STYLEID_WORD_SPACING, p, 0);
 }
 
 static HRESULT WINAPI HTMLStyle_put_letterSpacing(IHTMLStyle *iface, VARIANT v)
 {
     HTMLStyle *This = HTMLSTYLE_THIS(iface);
-    FIXME("(%p)->(v%d)\n", This, V_VT(&v));
-    return E_NOTIMPL;
+    TRACE("(%p)->(v%d)\n", This, V_VT(&v));
+    return set_nsstyle_attr_var(This->nsstyle, STYLEID_LETTER_SPACING, &v, 0);
 }
 
 static HRESULT WINAPI HTMLStyle_get_letterSpacing(IHTMLStyle *iface, VARIANT *p)
 {
     HTMLStyle *This = HTMLSTYLE_THIS(iface);
-    FIXME("(%p)->(%p)\n", This, p);
-    return E_NOTIMPL;
+    TRACE("(%p)->(%p)\n", This, p);
+    return get_nsstyle_attr_var(This->nsstyle, STYLEID_LETTER_SPACING, p, 0);
 }
 
 static HRESULT WINAPI HTMLStyle_put_textDecoration(IHTMLStyle *iface, BSTR v)
@@ -1574,15 +1584,15 @@ static HRESULT WINAPI HTMLStyle_get_borderBottomWidth(IHTMLStyle *iface, VARIANT
 static HRESULT WINAPI HTMLStyle_put_borderLeftWidth(IHTMLStyle *iface, VARIANT v)
 {
     HTMLStyle *This = HTMLSTYLE_THIS(iface);
-    FIXME("(%p)->(v%d)\n", This, V_VT(&v));
-    return E_NOTIMPL;
+    TRACE("(%p)->(v%d)\n", This, V_VT(&v));
+    return set_nsstyle_attr_var(This->nsstyle, STYLEID_BORDER_LEFT_WIDTH, &v, 0);
 }
 
 static HRESULT WINAPI HTMLStyle_get_borderLeftWidth(IHTMLStyle *iface, VARIANT *p)
 {
     HTMLStyle *This = HTMLSTYLE_THIS(iface);
-    FIXME("(%p)->(%p)\n", This, p);
-    return E_NOTIMPL;
+    TRACE("(%p)->(%p)\n", This, p);
+    return get_nsstyle_attr_var(This->nsstyle, STYLEID_BORDER_LEFT_WIDTH, p, 0);
 }
 
 static HRESULT WINAPI HTMLStyle_put_borderStyle(IHTMLStyle *iface, BSTR v)
@@ -2601,6 +2611,7 @@ static const IHTMLStyleVtbl HTMLStyleVtbl = {
 };
 
 static const dispex_static_data_vtbl_t HTMLStyle_dispex_vtbl = {
+    NULL,
     HTMLStyle_get_dispid,
     NULL
 };
index 307824e..b691804 100644 (file)
@@ -47,6 +47,7 @@ typedef enum {
     STYLEID_BORDER_COLOR,
     STYLEID_BORDER_LEFT,
     STYLEID_BORDER_LEFT_STYLE,
+    STYLEID_BORDER_LEFT_WIDTH,
     STYLEID_BORDER_RIGHT_STYLE,
     STYLEID_BORDER_RIGHT_WIDTH,
     STYLEID_BORDER_STYLE,
@@ -64,6 +65,7 @@ typedef enum {
     STYLEID_FONT_WEIGHT,
     STYLEID_HEIGHT,
     STYLEID_LEFT,
+    STYLEID_LETTER_SPACING,
     STYLEID_MARGIN,
     STYLEID_MARGIN_LEFT,
     STYLEID_MARGIN_RIGHT,
@@ -77,6 +79,7 @@ typedef enum {
     STYLEID_VERTICAL_ALIGN,
     STYLEID_VISIBILITY,
     STYLEID_WIDTH,
+    STYLEID_WORD_SPACING,
     STYLEID_WORD_WRAP,
     STYLEID_Z_INDEX
 } styleid_t;
index a928709..d50eca1 100644 (file)
@@ -93,6 +93,7 @@ static ULONG WINAPI HTMLWindow2_Release(IHTMLWindow2 *iface)
 
     if(!ref) {
         list_remove(&This->entry);
+        release_dispex(&This->dispex);
         heap_free(This);
     }
 
@@ -745,8 +746,16 @@ static HRESULT WINAPI HTMLWindow2_execScript(IHTMLWindow2 *iface, BSTR scode, BS
 static HRESULT WINAPI HTMLWindow2_toString(IHTMLWindow2 *iface, BSTR *String)
 {
     HTMLWindow *This = HTMLWINDOW2_THIS(iface);
-    FIXME("(%p)->(%p)\n", This, String);
-    return E_NOTIMPL;
+
+    static const WCHAR objectW[] = {'[','o','b','j','e','c','t',']',0};
+
+    TRACE("(%p)->(%p)\n", This, String);
+
+    if(!String)
+        return E_INVALIDARG;
+
+    *String = SysAllocString(objectW);
+    return *String ? S_OK : E_OUTOFMEMORY;
 }
 
 static HRESULT WINAPI HTMLWindow2_scrollBy(IHTMLWindow2 *iface, LONG x, LONG y)
index ead2dcb..ff60582 100644 (file)
@@ -77,6 +77,7 @@
        <library>gdi32</library>
        <library>advapi32</library>
        <library>kernel32</library>
+       <library>wininet</library>
        <library>ntdll</library>
        <dependency>mshtml_nsiface_header</dependency>
 </module>
index 6ab70f2..ecae0a5 100644 (file)
@@ -33,9 +33,6 @@
 
 #include "nsiface.h"
 
-#define GENERATE_MSHTML_NS_FAILURE(code) \
-    ((nsresult) ((PRUint32)(1<<31) | ((PRUint32)(0x45+6)<<16) | (PRUint32)(code)))
-
 #define NS_OK                     ((nsresult)0x00000000L)
 #define NS_ERROR_FAILURE          ((nsresult)0x80004005L)
 #define NS_NOINTERFACE            ((nsresult)0x80004002L)
@@ -44,8 +41,6 @@
 #define NS_ERROR_UNEXPECTED       ((nsresult)0x8000ffffL)
 #define NS_ERROR_UNKNOWN_PROTOCOL ((nsresult)0x804b0012L)
 
-#define WINE_NS_LOAD_FROM_MONIKER GENERATE_MSHTML_NS_FAILURE(0)
-
 #define NS_FAILED(res) ((res) & 0x80000000)
 #define NS_SUCCEEDED(res) (!NS_FAILED(res))
 
@@ -132,6 +127,7 @@ typedef struct dispex_dynamic_data_t dispex_dynamic_data_t;
 #define MSHTML_DISPID_CUSTOM_MAX 0x6fffffff
 
 typedef struct {
+    HRESULT (*value)(IUnknown*,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*);
     HRESULT (*get_dispid)(IUnknown*,BSTR,DWORD,DISPID*);
     HRESULT (*invoke)(IUnknown*,DISPID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*);
 } dispex_static_data_vtbl_t;
@@ -153,6 +149,7 @@ typedef struct {
 } DispatchEx;
 
 void init_dispex(DispatchEx*,IUnknown*,dispex_static_data_t*);
+void release_dispex(DispatchEx*);
 BOOL dispex_query_interface(DispatchEx*,REFIID,void**);
 HRESULT dispex_get_dprop_ref(DispatchEx*,const WCHAR*,BOOL,VARIANT**);
 
@@ -363,11 +360,13 @@ struct NSContainer {
 typedef struct {
     const nsIHttpChannelVtbl *lpHttpChannelVtbl;
     const nsIUploadChannelVtbl *lpUploadChannelVtbl;
+    const nsIHttpChannelInternalVtbl *lpIHttpChannelInternalVtbl;
 
     LONG ref;
 
     nsIChannel *channel;
     nsIHttpChannel *http_channel;
+    nsIHttpChannelInternal *http_channel_internal;
     nsIWineURI *uri;
     nsIInputStream *post_data_stream;
     nsILoadGroup *load_group;
@@ -377,6 +376,7 @@ typedef struct {
     nsIURI *original_uri;
     char *content_type;
     char *charset;
+    PRUint32 response_status;
 } nsChannel;
 
 typedef struct {
@@ -466,6 +466,7 @@ typedef struct {
 #define NSCHANNEL(x)     ((nsIChannel*)        &(x)->lpHttpChannelVtbl)
 #define NSHTTPCHANNEL(x) ((nsIHttpChannel*)    &(x)->lpHttpChannelVtbl)
 #define NSUPCHANNEL(x)   ((nsIUploadChannel*)  &(x)->lpUploadChannelVtbl)
+#define NSHTTPINTERNAL(x) ((nsIHttpChannelInternal*)  &(x)->lpIHttpChannelInternalVtbl)
 
 #define HTTPNEG(x)       ((IHttpNegotiate2*)              &(x)->lpHttpNegotiate2Vtbl)
 #define STATUSCLB(x)     ((IBindStatusCallback*)          &(x)->lpBindStatusCallbackVtbl)
@@ -559,9 +560,8 @@ void nsAString_SetData(nsAString*,const PRUnichar*);
 PRUint32 nsAString_GetData(const nsAString*,const PRUnichar**);
 void nsAString_Finish(nsAString*);
 
-nsIInputStream *create_nsstream(const char*,PRInt32);
 nsICommandParams *create_nscommand_params(void);
-void nsnode_to_nsstring(nsIDOMNode*,nsAString*);
+HRESULT nsnode_to_nsstring(nsIDOMNode*,nsAString*);
 void get_editor_controller(NSContainer*);
 void init_nsevents(NSContainer*);
 void add_nsevent_listener(NSContainer*,LPCWSTR);
index 6060a8d..f161de4 100644 (file)
@@ -461,6 +461,22 @@ static void NSAPI nsDocumentObserver_BeginLoad(nsIDocumentObserver *iface, nsIDo
 
 static void NSAPI nsDocumentObserver_EndLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
 {
+    NSContainer *This = NSDOCOBS_THIS(iface);
+    task_t *task;
+
+    TRACE("\n");
+
+    task = heap_alloc(sizeof(task_t));
+
+    task->doc = This->doc;
+    task->task_id = TASK_PARSECOMPLETE;
+    task->next = NULL;
+
+    /*
+     * This should be done in the worker thread that parses HTML,
+     * but we don't have such thread (Gecko parses HTML for us).
+     */
+    push_task(task);
 }
 
 static void NSAPI nsDocumentObserver_ContentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
index f882e6c..1a0d5eb 100644 (file)
@@ -54,10 +54,12 @@ typedef struct {
 
 typedef struct {
     void (*destroy)(BSCallback*);
+    HRESULT (*init_bindinfo)(BSCallback*);
     HRESULT (*start_binding)(BSCallback*);
     HRESULT (*stop_binding)(BSCallback*,HRESULT);
     HRESULT (*read_data)(BSCallback*,IStream*);
     HRESULT (*on_progress)(BSCallback*,ULONG,LPCWSTR);
+    HRESULT (*on_response)(BSCallback*,DWORD);
 } BSCallbackVtbl;
 
 struct BSCallback {
@@ -75,6 +77,7 @@ struct BSCallback {
     ULONG post_data_len;
     ULONG readed;
     DWORD bindf;
+    BOOL bindinfo_ready;
 
     IMoniker *mon;
     IBinding *binding;
@@ -344,19 +347,23 @@ static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *ifac
         HRESULT hresult, LPCWSTR szError)
 {
     BSCallback *This = STATUSCLB_THIS(iface);
+    HRESULT hres;
 
     TRACE("(%p)->(%08x %s)\n", This, hresult, debugstr_w(szError));
 
     /* NOTE: IE7 calls GetBindResult here */
 
+    hres = This->vtbl->stop_binding(This, hresult);
+
     if(This->binding) {
         IBinding_Release(This->binding);
         This->binding = NULL;
     }
 
     list_remove(&This->entry);
+    This->doc = NULL;
 
-    return This->vtbl->stop_binding(This, hresult);
+    return hres;
 }
 
 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface,
@@ -367,6 +374,16 @@ static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface,
 
     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
 
+    if(!This->bindinfo_ready) {
+        HRESULT hres;
+
+        hres = This->vtbl->init_bindinfo(This);
+        if(FAILED(hres))
+            return hres;
+
+        This->bindinfo_ready = TRUE;
+    }
+
     *grfBINDF = This->bindf;
 
     size = pbindinfo->cbSize;
@@ -469,9 +486,11 @@ static HRESULT WINAPI HttpNegotiate_OnResponse(IHttpNegotiate2 *iface, DWORD dwR
         LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders)
 {
     BSCallback *This = HTTPNEG_THIS(iface);
-    FIXME("(%p)->(%d %s %s %p)\n", This, dwResponseCode, debugstr_w(szResponseHeaders),
+
+    TRACE("(%p)->(%d %s %s %p)\n", This, dwResponseCode, debugstr_w(szResponseHeaders),
           debugstr_w(szRequestHeaders), pszAdditionalRequestHeaders);
-    return E_NOTIMPL;
+
+    return This->vtbl->on_response(This, dwResponseCode);
 }
 
 static HRESULT WINAPI HttpNegotiate_GetRootSecurityId(IHttpNegotiate2 *iface,
@@ -744,6 +763,11 @@ static void BufferBSC_destroy(BSCallback *bsc)
     heap_free(This);
 }
 
+static HRESULT BufferBSC_init_bindinfo(BSCallback *bsc)
+{
+    return S_OK;
+}
+
 static HRESULT BufferBSC_start_binding(BSCallback *bsc)
 {
     return S_OK;
@@ -794,14 +818,21 @@ static HRESULT BufferBSC_on_progress(BSCallback *bsc, ULONG status_code, LPCWSTR
     return S_OK;
 }
 
+static HRESULT BufferBSC_on_response(BSCallback *bsc, DWORD response_code)
+{
+    return S_OK;
+}
+
 #undef BUFFERBSC_THIS
 
 static const BSCallbackVtbl BufferBSCVtbl = {
     BufferBSC_destroy,
+    BufferBSC_init_bindinfo,
     BufferBSC_start_binding,
     BufferBSC_stop_binding,
     BufferBSC_read_data,
     BufferBSC_on_progress,
+    BufferBSC_on_response
 };
 
 
@@ -848,14 +879,46 @@ struct nsChannelBSC {
     nsProtocolStream *nsstream;
 };
 
+static void on_start_nsrequest(nsChannelBSC *This)
+{
+    nsresult nsres;
+
+    /* FIXME: it's needed for http connections from BindToObject. */
+    if(!This->nschannel->response_status)
+        This->nschannel->response_status = 200;
+
+    nsres = nsIStreamListener_OnStartRequest(This->nslistener,
+            (nsIRequest*)NSCHANNEL(This->nschannel), This->nscontext);
+    if(NS_FAILED(nsres))
+        FIXME("OnStartRequest failed: %08x\n", nsres);
+}
+
+static void on_stop_nsrequest(nsChannelBSC *This)
+{
+    nsresult nsres;
+
+    if(!This->nslistener)
+        return;
+
+    if(!This->bsc.readed) {
+        TRACE("No data read! Calling OnStartRequest\n");
+        on_start_nsrequest(This);
+    }
+
+    nsres = nsIStreamListener_OnStopRequest(This->nslistener, (nsIRequest*)NSCHANNEL(This->nschannel),
+            This->nscontext, NS_OK);
+    if(NS_FAILED(nsres))
+        WARN("OnStopRequest failed: %08x\n", nsres);
+}
+
 static HRESULT read_stream_data(nsChannelBSC *This, IStream *stream)
 {
+    DWORD read;
     nsresult nsres;
     HRESULT hres;
 
     if(!This->nslistener) {
         BYTE buf[1024];
-        DWORD read;
 
         do {
             read = 0;
@@ -869,21 +932,21 @@ static HRESULT read_stream_data(nsChannelBSC *This, IStream *stream)
         This->nsstream = create_nsprotocol_stream();
 
     do {
-        hres = IStream_Read(stream, This->nsstream->buf, sizeof(This->nsstream->buf),
-                &This->nsstream->buf_size);
-        if(!This->nsstream->buf_size)
+        read = 0;
+        hres = IStream_Read(stream, This->nsstream->buf+This->nsstream->buf_size,
+                sizeof(This->nsstream->buf)-This->nsstream->buf_size, &read);
+        if(!read)
             break;
 
-        if(!This->bsc.readed && This->nsstream->buf_size >= 2 && *(WORD*)This->nsstream->buf == 0xfeff) {
-            This->nschannel->charset = heap_alloc(sizeof(UTF16_STR));
-            memcpy(This->nschannel->charset, UTF16_STR, sizeof(UTF16_STR));
-        }
+        This->nsstream->buf_size += read;
 
         if(!This->bsc.readed) {
-            nsres = nsIStreamListener_OnStartRequest(This->nslistener,
-                    (nsIRequest*)NSCHANNEL(This->nschannel), This->nscontext);
-            if(NS_FAILED(nsres))
-                FIXME("OnStartRequest failed: %08x\n", nsres);
+            if(This->nsstream->buf_size >= 2
+               && (BYTE)This->nsstream->buf[0] == 0xff
+               && (BYTE)This->nsstream->buf[1] == 0xfe)
+                This->nschannel->charset = heap_strdupA(UTF16_STR);
+
+            on_start_nsrequest(This);
 
             /* events are reset when a new document URI is loaded, so re-initialise them here */
             if(This->bsc.doc && This->bsc.doc->bscallback == This && This->bsc.doc->nscontainer) {
@@ -901,22 +964,15 @@ static HRESULT read_stream_data(nsChannelBSC *This, IStream *stream)
         if(NS_FAILED(nsres))
             ERR("OnDataAvailable failed: %08x\n", nsres);
 
-        if(This->nsstream->buf_size)
-            FIXME("buffer is not empty!\n");
+        if(This->nsstream->buf_size == sizeof(This->nsstream->buf)) {
+            ERR("buffer is full\n");
+            break;
+        }
     }while(hres == S_OK);
 
     return S_OK;
 }
 
-static void on_stop_nsrequest(nsChannelBSC *This)
-{
-    if(!This->nslistener)
-        return;
-
-    nsIStreamListener_OnStopRequest(This->nslistener, (nsIRequest*)NSCHANNEL(This->nschannel),
-            This->nscontext, NS_OK);
-}
-
 static void add_nsrequest(nsChannelBSC *This)
 {
     nsresult nsres;
@@ -957,6 +1013,19 @@ static HRESULT nsChannelBSC_start_binding(BSCallback *bsc)
     return S_OK;
 }
 
+static HRESULT nsChannelBSC_init_bindinfo(BSCallback *bsc)
+{
+    nsChannelBSC *This = NSCHANNELBSC_THIS(bsc);
+
+    if(This->nschannel && This->nschannel->post_data_stream) {
+        parse_post_data(This->nschannel->post_data_stream, &This->bsc.headers, &This->bsc.post_data, &This->bsc.post_data_len);
+        TRACE("headers = %s post_data = %s\n", debugstr_w(This->bsc.headers),
+              debugstr_an(This->bsc.post_data, This->bsc.post_data_len));
+    }
+
+    return S_OK;
+}
+
 static HRESULT nsChannelBSC_stop_binding(BSCallback *bsc, HRESULT result)
 {
     nsChannelBSC *This = NSCHANNELBSC_THIS(bsc);
@@ -974,23 +1043,6 @@ static HRESULT nsChannelBSC_stop_binding(BSCallback *bsc, HRESULT result)
         }
     }
 
-    if(FAILED(result))
-        return S_OK;
-
-    if(This->bsc.doc && This->bsc.doc->bscallback == This && !This->bsc.doc->nscontainer) {
-        task_t *task = heap_alloc(sizeof(task_t));
-
-        task->doc = This->bsc.doc;
-        task->task_id = TASK_PARSECOMPLETE;
-        task->next = NULL;
-
-        /*
-         * This should be done in the worker thread that parses HTML,
-         * but we don't have such thread.
-         */
-        push_task(task);
-    }
-
     return S_OK;
 }
 
@@ -1017,14 +1069,24 @@ static HRESULT nsChannelBSC_on_progress(BSCallback *bsc, ULONG status_code, LPCW
     return S_OK;
 }
 
+static HRESULT nsChannelBSC_on_response(BSCallback *bsc, DWORD response_code)
+{
+    nsChannelBSC *This = NSCHANNELBSC_THIS(bsc);
+
+    This->nschannel->response_status = response_code;
+    return S_OK;
+}
+
 #undef NSCHANNELBSC_THIS
 
 static const BSCallbackVtbl nsChannelBSCVtbl = {
     nsChannelBSC_destroy,
+    nsChannelBSC_init_bindinfo,
     nsChannelBSC_start_binding,
     nsChannelBSC_stop_binding,
     nsChannelBSC_read_data,
     nsChannelBSC_on_progress,
+    nsChannelBSC_on_response
 };
 
 nsChannelBSC *create_channelbsc(IMoniker *mon)
index 0464e05..50001aa 100644 (file)
@@ -38,14 +38,10 @@ WINE_DECLARE_DEBUG_CHANNEL(gecko);
 
 #define NS_APPSTARTUPNOTIFIER_CONTRACTID "@mozilla.org/embedcomp/appstartup-notifier;1"
 #define NS_WEBBROWSER_CONTRACTID "@mozilla.org/embedding/browser/nsWebBrowser;1"
-#define NS_PROFILE_CONTRACTID "@mozilla.org/profile/manager;1"
 #define NS_MEMORY_CONTRACTID "@mozilla.org/xpcom/memory-service;1"
-#define NS_STRINGSTREAM_CONTRACTID "@mozilla.org/io/string-input-stream;1"
 #define NS_COMMANDPARAMS_CONTRACTID "@mozilla.org/embedcomp/command-params;1"
 #define NS_HTMLSERIALIZER_CONTRACTID "@mozilla.org/layout/contentserializer;1?mimetype=text/html"
 #define NS_EDITORCONTROLLER_CONTRACTID "@mozilla.org/editor/editorcontroller;1"
-#define NS_ARRAY_CONTRACTID "@mozilla.org/array;1"
-#define NS_VARIANT_CONTRACTID "@mozilla.org/variant;1"
 #define NS_PREFERENCES_CONTRACTID "@mozilla.org/preferences;1"
 
 #define APPSTARTUP_TOPIC "app-startup"
@@ -296,12 +292,38 @@ static BOOL load_wine_gecko(PRUnichar *gre_path)
     return ret;
 }
 
+static void set_bool_pref(nsIPrefBranch *pref, const char *pref_name, BOOL val)
+{
+    nsresult nsres;
+
+    nsres = nsIPrefBranch_SetBoolPref(pref, pref_name, val);
+    if(NS_FAILED(nsres))
+        ERR("Could not set pref %s\n", debugstr_a(pref_name));
+}
+
+static void set_int_pref(nsIPrefBranch *pref, const char *pref_name, int val)
+{
+    nsresult nsres;
+
+    nsres = nsIPrefBranch_SetIntPref(pref, pref_name, val);
+    if(NS_FAILED(nsres))
+        ERR("Could not set pref %s\n", debugstr_a(pref_name));
+}
+
+static void set_string_pref(nsIPrefBranch *pref, const char *pref_name, const char *val)
+{
+    nsresult nsres;
+
+    nsres = nsIPrefBranch_SetCharPref(pref, pref_name, val);
+    if(NS_FAILED(nsres))
+        ERR("Could not set pref %s\n", debugstr_a(pref_name));
+}
+
 static void set_lang(nsIPrefBranch *pref)
 {
     char langs[100];
     DWORD res, size, type;
     HKEY hkey;
-    nsresult nsres;
 
     static const WCHAR international_keyW[] =
         {'S','o','f','t','w','a','r','e',
@@ -321,9 +343,7 @@ static void set_lang(nsIPrefBranch *pref)
 
     TRACE("Setting lang %s\n", debugstr_a(langs));
 
-    nsres = nsIPrefBranch_SetCharPref(pref, "intl.accept_languages", langs);
-    if(NS_FAILED(nsres))
-        ERR("SetCharPref failed: %08x\n", nsres);
+    set_string_pref(pref, "intl.accept_languages", langs);
 }
 
 static void set_proxy(nsIPrefBranch *pref)
@@ -333,7 +353,6 @@ static void set_proxy(nsIPrefBranch *pref)
     int proxy_port_num;
     DWORD enabled = 0, res, size, type;
     HKEY hkey;
-    nsresult nsres;
 
     static const WCHAR proxy_keyW[] =
         {'S','o','f','t','w','a','r','e',
@@ -368,30 +387,12 @@ static void set_proxy(nsIPrefBranch *pref)
     proxy_port_num = atoi(proxy_port + 1);
     TRACE("Setting proxy to %s, port %d\n", debugstr_a(proxy), proxy_port_num);
 
-    nsres = nsIPrefBranch_SetIntPref(pref, "network.proxy.type", 1);
-    if(NS_FAILED(nsres))
-        ERR("SetIntPref network.proxy.type failed: %08x\n", nsres);
-    nsres = nsIPrefBranch_SetCharPref(pref, "network.proxy.http", proxy);
-    if(NS_FAILED(nsres))
-        ERR("SetCharPref network.proxy.http failed: %08x\n", nsres);
-    nsres = nsIPrefBranch_SetIntPref(pref, "network.proxy.http_port", proxy_port_num);
-    if(NS_FAILED(nsres))
-        ERR("SetIntPref network.proxy.http_port failed: %08x\n", nsres);
-    nsres = nsIPrefBranch_SetCharPref(pref, "network.proxy.ssl", proxy);
-    if(NS_FAILED(nsres))
-        ERR("SetCharPref network.proxy.ssl failed: %08x\n", nsres);
-    nsres = nsIPrefBranch_SetIntPref(pref, "network.proxy.ssl_port", proxy_port_num);
-    if(NS_FAILED(nsres))
-        ERR("SetIntPref network.proxy.ssl_port failed: %08x\n", nsres);
-}
-
-static void set_bool_pref(nsIPrefBranch *pref, const char *pref_name, BOOL val)
-{
-    nsresult nsres;
+    set_string_pref(pref, "network.proxy.http", proxy);
+    set_string_pref(pref, "network.proxy.ssl", proxy);
 
-    nsres = nsIPrefBranch_SetBoolPref(pref, pref_name, val);
-    if(NS_FAILED(nsres))
-        ERR("Could not set pref %s\n", debugstr_a(pref_name));
+    set_int_pref(pref, "network.proxy.type", 1);
+    set_int_pref(pref, "network.proxy.http_port", proxy_port_num);
+    set_int_pref(pref, "network.proxy.ssl_port", proxy_port_num);
 }
 
 static void set_preferences(void)
@@ -410,6 +411,7 @@ static void set_preferences(void)
     set_proxy(pref);
     set_bool_pref(pref, "security.warn_entering_secure", FALSE);
     set_bool_pref(pref, "security.warn_submit_insecure", FALSE);
+    set_int_pref(pref, "layout.spellcheckDefault", 0);
 
     nsIPrefBranch_Release(pref);
 }
@@ -575,32 +577,6 @@ void nsAString_Finish(nsAString *str)
     NS_StringContainerFinish(str);
 }
 
-nsIInputStream *create_nsstream(const char *data, PRInt32 data_len)
-{
-    nsIStringInputStream *ret;
-    nsresult nsres;
-
-    if(!pCompMgr)
-        return NULL;
-
-    nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr,
-            NS_STRINGSTREAM_CONTRACTID, NULL, &IID_nsIStringInputStream,
-            (void**)&ret);
-    if(NS_FAILED(nsres)) {
-        ERR("Could not get nsIStringInputStream\n");
-        return NULL;
-    }
-
-    nsres = nsIStringInputStream_SetData(ret, data, data_len);
-    if(NS_FAILED(nsres)) {
-        ERR("AdoptData failed: %08x\n", nsres);
-        nsIStringInputStream_Release(ret);
-        return NULL;
-    }
-
-    return (nsIInputStream*)ret;
-}
-
 nsICommandParams *create_nscommand_params(void)
 {
     nsICommandParams *ret = NULL;
@@ -633,7 +609,7 @@ nsresult get_nsinterface(nsISupports *iface, REFIID riid, void **ppv)
     return nsres;
 }
 
-static void nsnode_to_nsstring_rec(nsIContentSerializer *serializer, nsIDOMNode *nsnode, nsAString *str)
+static HRESULT nsnode_to_nsstring_rec(nsIContentSerializer *serializer, nsIDOMNode *nsnode, nsAString *str)
 {
     nsIDOMNodeList *node_list = NULL;
     PRBool has_children = FALSE;
@@ -645,7 +621,7 @@ static void nsnode_to_nsstring_rec(nsIContentSerializer *serializer, nsIDOMNode
     nsres = nsIDOMNode_GetNodeType(nsnode, &type);
     if(NS_FAILED(nsres)) {
         ERR("GetType failed: %08x\n", nsres);
-        return;
+        return E_FAIL;
     }
 
     switch(type) {
@@ -676,6 +652,9 @@ static void nsnode_to_nsstring_rec(nsIContentSerializer *serializer, nsIDOMNode
         nsIDOMDocument_Release(nsdoc);
         break;
     }
+    case DOCUMENT_TYPE_NODE:
+        WARN("Ignoring DOCUMENT_TYPE_NODE\n");
+        break;
     case DOCUMENT_FRAGMENT_NODE:
         break;
     default:
@@ -708,35 +687,37 @@ static void nsnode_to_nsstring_rec(nsIContentSerializer *serializer, nsIDOMNode
         nsIContentSerializer_AppendElementEnd(serializer, nselem, str);
         nsIDOMElement_Release(nselem);
     }
+
+    return S_OK;
 }
 
-void nsnode_to_nsstring(nsIDOMNode *nsdoc, nsAString *str)
+HRESULT nsnode_to_nsstring(nsIDOMNode *nsnode, nsAString *str)
 {
     nsIContentSerializer *serializer;
-    nsIDOMNode *nsnode;
     nsresult nsres;
+    HRESULT hres;
 
     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr,
             NS_HTMLSERIALIZER_CONTRACTID, NULL, &IID_nsIContentSerializer,
             (void**)&serializer);
     if(NS_FAILED(nsres)) {
         ERR("Could not get nsIContentSerializer: %08x\n", nsres);
-        return;
+        return E_FAIL;
     }
 
     nsres = nsIContentSerializer_Init(serializer, 0, 100, NULL, FALSE, FALSE /* FIXME */);
     if(NS_FAILED(nsres))
         ERR("Init failed: %08x\n", nsres);
 
-    nsIDOMDocument_QueryInterface(nsdoc, &IID_nsIDOMNode, (void**)&nsnode);
-    nsnode_to_nsstring_rec(serializer, nsnode, str);
-    nsIDOMNode_Release(nsnode);
-
-    nsres = nsIContentSerializer_Flush(serializer, str);
-    if(NS_FAILED(nsres))
-        ERR("Flush failed: %08x\n", nsres);
+    hres = nsnode_to_nsstring_rec(serializer, nsnode, str);
+    if(SUCCEEDED(hres)) {
+        nsres = nsIContentSerializer_Flush(serializer, str);
+        if(NS_FAILED(nsres))
+            ERR("Flush failed: %08x\n", nsres);
+    }
 
     nsIContentSerializer_Release(serializer);
+    return hres;
 }
 
 void get_editor_controller(NSContainer *This)
@@ -1179,6 +1160,33 @@ static nsrefcnt NSAPI nsURIContentListener_Release(nsIURIContentListener *iface)
     return nsIWebBrowserChrome_Release(NSWBCHROME(This));
 }
 
+static BOOL translate_url(HTMLDocument *doc, nsIWineURI *nsuri)
+{
+    OLECHAR *new_url = NULL, *url;
+    BOOL ret = FALSE;
+    LPCWSTR wine_url;
+    HRESULT hres;
+
+    if(!doc->hostui)
+        return FALSE;
+
+    nsIWineURI_GetWineURL(nsuri, &wine_url);
+
+    url = heap_strdupW(wine_url);
+    hres = IDocHostUIHandler_TranslateUrl(doc->hostui, 0, url, &new_url);
+    heap_free(url);
+    if(hres != S_OK || !new_url)
+        return FALSE;
+
+    if(strcmpW(url, new_url)) {
+        FIXME("TranslateUrl returned new URL %s -> %s\n", debugstr_w(url), debugstr_w(new_url));
+        ret = TRUE;
+    }
+
+    CoTaskMemFree(new_url);
+    return ret;
+}
+
 static nsresult NSAPI nsURIContentListener_OnStartURIOpen(nsIURIContentListener *iface,
                                                           nsIURI *aURI, PRBool *_retval)
 {
@@ -1222,12 +1230,15 @@ static nsresult NSAPI nsURIContentListener_OnStartURIOpen(nsIURIContentListener
 
             IMoniker_Release(mon);
         }
+
+        *_retval = FALSE;
+    }else if(This->doc) {
+        *_retval = translate_url(This->doc, wine_uri);
     }
 
     nsIWineURI_Release(wine_uri);
 
-    *_retval = FALSE;
-    return This->content_listener
+    return !*_retval && This->content_listener
         ? nsIURIContentListener_OnStartURIOpen(This->content_listener, aURI, _retval)
         : NS_OK;
 }
index 1933c57..0ba11d2 100644 (file)
@@ -131,7 +131,6 @@ static nsresult NSAPI handle_load(nsIDOMEventListener *iface, nsIDOMEvent *event
 {
     NSContainer *This = NSEVENTLIST_THIS(iface)->This;
     nsIDOMHTMLElement *nsbody = NULL;
-    task_t *task;
 
     TRACE("(%p)\n", This);
 
@@ -149,18 +148,6 @@ static nsresult NSAPI handle_load(nsIDOMEventListener *iface, nsIDOMEvent *event
     if(This->doc->usermode == EDITMODE)
         handle_edit_load(This->doc);
 
-    task = heap_alloc(sizeof(task_t));
-
-    task->doc = This->doc;
-    task->task_id = TASK_PARSECOMPLETE;
-    task->next = NULL;
-
-    /*
-     * This should be done in the worker thread that parses HTML,
-     * but we don't have such thread (Gecko parses HTML for us).
-     */
-    push_task(task);
-
     if(!This->doc->nsdoc) {
         ERR("NULL nsdoc\n");
         return NS_ERROR_FAILURE;
index 24c6214..cb8f768 100644 (file)
@@ -284,19 +284,6 @@ interface nsIInputStream : nsISupports
     nsresult IsNonBlocking(PRBool *_retval);
 }
 
-[
-    object,
-    uuid(450cd2d4-f0fd-424d-b365-b1251f80fd53),
-    local
-    /* NOT_FROZEN */
-]
-interface nsIStringInputStream : nsIInputStream
-{
-    nsresult SetData(const char *data, PRInt32 dataLen);
-    nsresult AdoptData(char *data, PRInt32 dataLen);
-    nsresult ShareData(const char *data, PRInt32 dataLen);
-}
-
 [
     object,
     uuid(07a22cc0-0ce5-11d3-9331-00104ba0fd40),
@@ -333,6 +320,34 @@ interface nsIURI : nsISupports
     nsresult GetOriginCharset(nsACString *aOriginCharset);
 }
 
+[
+    object,
+    uuid(d6116970-8034-11d3-9399-00104ba0fd40),
+    local
+    /* FROZEN */
+]
+interface nsIURL : nsIURI
+{
+    nsresult GetFilePath(nsACString *aFilePath);
+    nsresult SetFilePath(const nsACString *aFilePath);
+    nsresult GetParam(nsACString *aParam);
+    nsresult SetParam(const nsACString *aParam);
+    nsresult GetQuery(nsACString *aQuery);
+    nsresult SetQuery(const nsACString *aQuery);
+    nsresult GetRef(nsACString *aRef);
+    nsresult SetRef(const nsACString *aRef);
+    nsresult GetDirectory(nsACString *aDirectory);
+    nsresult SetDirectory(const nsACString *aDirectory);
+    nsresult GetFileName(nsACString *aFileName);
+    nsresult SetFileName(const nsACString *aFileName);
+    nsresult GetFileBaseName(nsACString *aFileBaseName);
+    nsresult SetFileBaseName(const nsACString *aFileBaseName);
+    nsresult GetFileExtension(nsACString *aFileExtension);
+    nsresult SetFileExtension(const nsACString *aFileExtension);
+    nsresult GetCommonBaseSpec(nsIURI *aURIToCompare, nsACString *_retval);
+    nsresult GetRelativeSpec(nsIURI *aURIToCompare, nsACString *_retval);
+}
+
 [
     object,
     uuid(ef6bfbd2-fd46-48d8-96b7-9f8f0fd387fe),
@@ -452,6 +467,24 @@ interface nsIHttpChannel : nsIChannel
     nsresult IsNoCacheResponse(PRBool *_retval);
 }
 
+[
+    object,
+    uuid(0eb66361-faaa-4e52-8c7e-6c25f11f8e3c),
+    local
+    /* NOT_FROZEN */
+]
+interface nsIHttpChannelInternal : nsISupports
+{
+    nsresult GetDocumentURI(nsIURI **aDocumentURI);
+    nsresult SetDocumentURI(nsIURI *aDocumentURI);
+    nsresult GetRequestVersion(PRUint32 *major, PRUint32 *minor);
+    nsresult GetResponseVersion(PRUint32 *major, PRUint32 *minor);
+    nsresult SetCookie(const char *aCookieHeader);
+    nsresult SetupFallbackChannel(const char *aFallbackKey);
+    nsresult GetForceAllowThirdPartyCookie(PRBool *aForceAllowThirdPartyCookie);
+    nsresult SetForceAllowThirdPartyCookie(PRBool aForceAllowThirdPartyCookie);
+}
+
 [
     object,
     uuid(ddf633d8-e9a4-439d-ad88-de636fd9bb75),
@@ -2547,7 +2580,7 @@ interface nsIDocumentObserver : nsIMutationObserver
     local
     /* INTERNAL */
 ]
-interface nsIWineURI : nsIURI
+interface nsIWineURI : nsIURL
 {
     typedef struct NSContainer NSContainer;
 
index 7c402b2..12e8520 100644 (file)
@@ -57,6 +57,7 @@ typedef struct {
     LONG ref;
 
     nsIURI *uri;
+    nsIURL *nsurl;
     NSContainer *container;
     LPWSTR wine_url;
     PRBool is_doc_uri;
@@ -68,6 +69,14 @@ typedef struct {
 
 static nsresult create_uri(nsIURI*,NSContainer*,nsIWineURI**);
 
+static const char *debugstr_nsacstr(const nsACString *nsstr)
+{
+    const char *data;
+
+    nsACString_GetData(nsstr, &data);
+    return debugstr_a(data);
+}
+
 HRESULT nsuri_to_url(LPCWSTR nsuri, BSTR *ret)
 {
     const WCHAR *ptr = nsuri;
@@ -167,8 +176,6 @@ static nsresult NSAPI nsChannel_QueryInterface(nsIHttpChannel *iface, nsIIDRef r
 {
     nsChannel *This = NSCHANNEL_THIS(iface);
 
-    *result = NULL;
-
     if(IsEqualGUID(&IID_nsISupports, riid)) {
         TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
         *result = NSCHANNEL(This);
@@ -178,12 +185,18 @@ static nsresult NSAPI nsChannel_QueryInterface(nsIHttpChannel *iface, nsIIDRef r
     }else if(IsEqualGUID(&IID_nsIChannel, riid)) {
         TRACE("(%p)->(IID_nsIChannel %p)\n", This, result);
         *result = NSCHANNEL(This);
-    }else if(This->http_channel && IsEqualGUID(&IID_nsIHttpChannel, riid)) {
+    }else if(IsEqualGUID(&IID_nsIHttpChannel, riid)) {
         TRACE("(%p)->(IID_nsIHttpChannel %p)\n", This, result);
-        *result = NSHTTPCHANNEL(This);
+        *result = This->http_channel ? NSHTTPCHANNEL(This) : NULL;
     }else if(IsEqualGUID(&IID_nsIUploadChannel, riid)) {
         TRACE("(%p)->(IID_nsIUploadChannel %p)\n", This, result);
         *result = NSUPCHANNEL(This);
+    }else if(IsEqualGUID(&IID_nsIHttpChannelInternal, riid)) {
+        TRACE("(%p)->(IID_nsIHttpChannelInternal %p)\n", This, result);
+        *result = This->http_channel_internal ? NSHTTPINTERNAL(This) : NULL;
+    }else {
+        TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
+        *result = NULL;
     }
 
     if(*result) {
@@ -191,10 +204,6 @@ static nsresult NSAPI nsChannel_QueryInterface(nsIHttpChannel *iface, nsIIDRef r
         return NS_OK;
     }
 
-    TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
-
-    if(This->channel)
-        return nsIChannel_QueryInterface(This->channel, riid, result);
     return NS_NOINTERFACE;
 }
 
@@ -219,6 +228,8 @@ static nsrefcnt NSAPI nsChannel_Release(nsIHttpChannel *iface)
             nsIChannel_Release(This->channel);
         if(This->http_channel)
             nsIHttpChannel_Release(This->http_channel);
+        if(This->http_channel_internal)
+            nsIHttpChannel_Release(This->http_channel_internal);
         if(This->owner)
             nsISupports_Release(This->owner);
         if(This->post_data_stream)
@@ -606,37 +617,6 @@ static nsresult NSAPI nsChannel_Open(nsIHttpChannel *iface, nsIInputStream **_re
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
-static BOOL do_load_from_moniker_hack(nsChannel *This)
-{
-    nsACString scheme_str;
-    nsresult nsres;
-    BOOL ret = TRUE;
-
-    /* 
-     * We should always load the page from IMoniker, but Wine is not yet
-     * ready for this. This function is a heuristic, that decides which
-     * way of loading is better (Gecko implementation or IMoniker). The
-     * aim is to always return TRUE.
-     */
-
-    /* Load from moniker if there is no Gecko channel available */
-    if(!This->channel)
-        return TRUE;
-
-    nsACString_Init(&scheme_str, NULL);
-    nsres = nsIWineURI_GetScheme(This->uri, &scheme_str);
-
-    if(NS_SUCCEEDED(nsres)) {
-        const char *scheme;
-
-        nsACString_GetData(&scheme_str, &scheme);
-        ret = !strcmp(scheme, "wine") || !strcmp(scheme, "about");
-    }
-
-    nsACString_Finish(&scheme_str);
-    return ret;
-}
-
 static HRESULT create_mon_for_nschannel(nsChannel *channel, IMoniker **mon)
 {
     nsIWineURI *wine_uri;
@@ -730,8 +710,7 @@ static nsresult async_open_doc_uri(nsChannel *This, NSContainer *container,
             This->content_type = heap_strdupWtoA(container->doc->mime);
         }
 
-        if(do_load_from_moniker_hack(This))
-            return WINE_NS_LOAD_FROM_MONIKER;
+        return NS_OK;
     }else  {
         BOOL cont = before_async_open(This, container);
 
@@ -762,23 +741,9 @@ static nsresult async_open(nsChannel *This, NSContainer *container, nsIStreamLis
 {
     nsChannelBSC *bscallback;
     IMoniker *mon = NULL;
-    nsresult nsres;
     task_t *task;
     HRESULT hres;
 
-    if(This->channel) {
-        nsres = nsIChannel_AsyncOpen(This->channel, listener, context);
-
-        if(mon)
-            IMoniker_Release(mon);
-
-        if(NS_FAILED(nsres) && (This->load_flags & LOAD_INITIAL_DOCUMENT_URI))
-            return WINE_NS_LOAD_FROM_MONIKER;
-        return nsres;
-    }
-
-    TRACE("channel == NULL\n");
-
     hres = create_mon_for_nschannel(This, &mon);
     if(FAILED(hres))
         return NS_ERROR_UNEXPECTED;
@@ -980,10 +945,15 @@ static nsresult NSAPI nsChannel_GetResponseStatus(nsIHttpChannel *iface, PRUint3
 
     TRACE("(%p)->(%p)\n", This, aResponseStatus);
 
+    if(This->response_status) {
+        *aResponseStatus = This->response_status;
+        return NS_OK;
+    }
+
     if(This->http_channel)
         return nsIHttpChannel_GetResponseStatus(This->http_channel, aResponseStatus);
 
-    return NS_ERROR_NOT_IMPLEMENTED;
+    return NS_ERROR_UNEXPECTED;
 }
 
 static nsresult NSAPI nsChannel_GetResponseStatusText(nsIHttpChannel *iface,
@@ -1217,6 +1187,131 @@ static const nsIUploadChannelVtbl nsUploadChannelVtbl = {
     nsUploadChannel_GetUploadStream
 };
 
+#define NSHTTPINTERNAL_THIS(iface) DEFINE_THIS(nsChannel, IHttpChannelInternal, iface)
+
+static nsresult NSAPI nsHttpChannelInternal_QueryInterface(nsIHttpChannelInternal *iface, nsIIDRef riid,
+        nsQIResult result)
+{
+    nsChannel *This = NSHTTPINTERNAL_THIS(iface);
+    return nsIChannel_QueryInterface(NSCHANNEL(This), riid, result);
+}
+
+static nsrefcnt NSAPI nsHttpChannelInternal_AddRef(nsIHttpChannelInternal *iface)
+{
+    nsChannel *This = NSHTTPINTERNAL_THIS(iface);
+    return nsIChannel_AddRef(NSCHANNEL(This));
+}
+
+static nsrefcnt NSAPI nsHttpChannelInternal_Release(nsIHttpChannelInternal *iface)
+{
+    nsChannel *This = NSHTTPINTERNAL_THIS(iface);
+    return nsIChannel_Release(NSCHANNEL(This));
+}
+
+static nsresult NSAPI nsHttpChannelInternal_GetDocumentURI(nsIHttpChannelInternal *iface, nsIURI **aDocumentURI)
+{
+    nsChannel *This = NSHTTPINTERNAL_THIS(iface);
+
+    TRACE("(%p)->()\n", This);
+
+    if(This->http_channel_internal)
+        return nsIHttpChannelInternal_GetDocumentURI(This->http_channel_internal, aDocumentURI);
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static nsresult NSAPI nsHttpChannelInternal_SetDocumentURI(nsIHttpChannelInternal *iface, nsIURI *aDocumentURI)
+{
+    nsChannel *This = NSHTTPINTERNAL_THIS(iface);
+
+    TRACE("(%p)->()\n", This);
+
+    if(This->http_channel_internal)
+        return nsIHttpChannelInternal_SetDocumentURI(This->http_channel_internal, aDocumentURI);
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static nsresult NSAPI nsHttpChannelInternal_GetRequestVersion(nsIHttpChannelInternal *iface, PRUint32 *major, PRUint32 *minor)
+{
+    nsChannel *This = NSHTTPINTERNAL_THIS(iface);
+
+    TRACE("(%p)->()\n", This);
+
+    if(This->http_channel_internal)
+        return nsIHttpChannelInternal_GetRequestVersion(This->http_channel_internal, major, minor);
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static nsresult NSAPI nsHttpChannelInternal_GetResponseVersion(nsIHttpChannelInternal *iface, PRUint32 *major, PRUint32 *minor)
+{
+    nsChannel *This = NSHTTPINTERNAL_THIS(iface);
+
+    TRACE("(%p)->()\n", This);
+
+    if(This->http_channel_internal)
+        return nsIHttpChannelInternal_GetResponseVersion(This->http_channel_internal, major, minor);
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static nsresult NSAPI nsHttpChannelInternal_SetCookie(nsIHttpChannelInternal *iface, const char *aCookieHeader)
+{
+    nsChannel *This = NSHTTPINTERNAL_THIS(iface);
+
+    TRACE("(%p)->()\n", This);
+
+    if(This->http_channel_internal)
+        return nsIHttpChannelInternal_SetCookie(This->http_channel_internal, aCookieHeader);
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static nsresult NSAPI nsHttpChannelInternal_SetupFallbackChannel(nsIHttpChannelInternal *iface, const char *aFallbackKey)
+{
+    nsChannel *This = NSHTTPINTERNAL_THIS(iface);
+
+    TRACE("(%p)->()\n", This);
+
+    if(This->http_channel_internal)
+        return nsIHttpChannelInternal_SetupFallbackChannel(This->http_channel_internal, aFallbackKey);
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static nsresult NSAPI nsHttpChannelInternal_GetForceAllowThirdPartyCookie(nsIHttpChannelInternal *iface, PRBool *aForceThirdPartyCookie)
+{
+    nsChannel *This = NSHTTPINTERNAL_THIS(iface);
+
+    TRACE("(%p)->()\n", This);
+
+    if(This->http_channel_internal)
+        return nsIHttpChannelInternal_GetForceAllowThirdPartyCookie(This->http_channel_internal, aForceThirdPartyCookie);
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static nsresult NSAPI nsHttpChannelInternal_SetForceAllowThirdPartyCookie(nsIHttpChannelInternal *iface, PRBool aForceThirdPartyCookie)
+{
+    nsChannel *This = NSHTTPINTERNAL_THIS(iface);
+
+    TRACE("(%p)->()\n", This);
+
+    if(This->http_channel_internal)
+        return nsIHttpChannelInternal_SetForceAllowThirdPartyCookie(This->http_channel_internal, aForceThirdPartyCookie);
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+#undef NSHTTPINTERNAL_THIS
+
+static const nsIHttpChannelInternalVtbl nsHttpChannelInternalVtbl = {
+    nsHttpChannelInternal_QueryInterface,
+    nsHttpChannelInternal_AddRef,
+    nsHttpChannelInternal_Release,
+    nsHttpChannelInternal_GetDocumentURI,
+    nsHttpChannelInternal_SetDocumentURI,
+    nsHttpChannelInternal_GetRequestVersion,
+    nsHttpChannelInternal_GetResponseVersion,
+    nsHttpChannelInternal_SetCookie,
+    nsHttpChannelInternal_SetupFallbackChannel,
+    nsHttpChannelInternal_GetForceAllowThirdPartyCookie,
+    nsHttpChannelInternal_SetForceAllowThirdPartyCookie
+};
+
 #define NSURI_THIS(iface) DEFINE_THIS(nsURI, WineURI, iface)
 
 static nsresult NSAPI nsURI_QueryInterface(nsIWineURI *iface, nsIIDRef riid, nsQIResult result)
@@ -1231,6 +1326,9 @@ static nsresult NSAPI nsURI_QueryInterface(nsIWineURI *iface, nsIIDRef riid, nsQ
     }else if(IsEqualGUID(&IID_nsIURI, riid)) {
         TRACE("(%p)->(IID_nsIURI %p)\n", This, result);
         *result = NSURI(This);
+    }else if(IsEqualGUID(&IID_nsIURL, riid)) {
+        TRACE("(%p)->(IID_nsIURL %p)\n", This, result);
+        *result = NSURI(This);
     }else if(IsEqualGUID(&IID_nsIWineURI, riid)) {
         TRACE("(%p)->(IID_nsIWineURI %p)\n", This, result);
         *result = NSURI(This);
@@ -1265,6 +1363,8 @@ static nsrefcnt NSAPI nsURI_Release(nsIWineURI *iface)
     if(!ref) {
         if(This->container)
             nsIWebBrowserChrome_Release(NSWBCHROME(This->container));
+        if(This->nsurl)
+            nsIURL_Release(This->nsurl);
         if(This->uri)
             nsIURI_Release(This->uri);
         heap_free(This->wine_url);
@@ -1688,6 +1788,280 @@ static nsresult NSAPI nsURI_GetOriginCharset(nsIWineURI *iface, nsACString *aOri
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
+static nsresult NSAPI nsURL_GetFilePath(nsIWineURI *iface, nsACString *aFilePath)
+{
+    nsURI *This = NSURI_THIS(iface);
+
+    TRACE("(%p)->(%p)\n", This, aFilePath);
+
+    if(This->nsurl)
+        return nsIURL_GetFilePath(This->nsurl, aFilePath);
+
+    FIXME("default action not implemented\n");
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static nsresult NSAPI nsURL_SetFilePath(nsIWineURI *iface, const nsACString *aFilePath)
+{
+    nsURI *This = NSURI_THIS(iface);
+
+    TRACE("(%p)->(%s)\n", This, debugstr_nsacstr(aFilePath));
+
+    if(This->nsurl)
+        return nsIURL_SetFilePath(This->nsurl, aFilePath);
+
+    FIXME("default action not implemented\n");
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static nsresult NSAPI nsURL_GetParam(nsIWineURI *iface, nsACString *aParam)
+{
+    nsURI *This = NSURI_THIS(iface);
+
+    TRACE("(%p)->(%p)\n", This, aParam);
+
+    if(This->nsurl)
+        return nsIURL_GetParam(This->nsurl, aParam);
+
+    FIXME("default action not implemented\n");
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static nsresult NSAPI nsURL_SetParam(nsIWineURI *iface, const nsACString *aParam)
+{
+    nsURI *This = NSURI_THIS(iface);
+
+    TRACE("(%p)->(%s)\n", This, debugstr_nsacstr(aParam));
+
+    if(This->nsurl)
+        return nsIURL_SetParam(This->nsurl, aParam);
+
+    FIXME("default action not implemented\n");
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static nsresult NSAPI nsURL_GetQuery(nsIWineURI *iface, nsACString *aQuery)
+{
+    nsURI *This = NSURI_THIS(iface);
+
+    TRACE("(%p)->(%p)\n", This, aQuery);
+
+    if(This->nsurl)
+        return nsIURL_GetQuery(This->nsurl, aQuery);
+
+    FIXME("default action not implemented\n");
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static nsresult NSAPI nsURL_SetQuery(nsIWineURI *iface, const nsACString *aQuery)
+{
+    nsURI *This = NSURI_THIS(iface);
+    const WCHAR *ptr1, *ptr2;
+    const char *query;
+    WCHAR *new_url, *ptr;
+    DWORD len, size;
+
+    TRACE("(%p)->(%s)\n", This, debugstr_nsacstr(aQuery));
+
+    if(This->nsurl)
+        nsIURL_SetQuery(This->nsurl, aQuery);
+
+    if(!This->wine_url)
+        return NS_OK;
+
+    nsACString_GetData(aQuery, &query);
+    size = len = MultiByteToWideChar(CP_ACP, 0, query, -1, NULL, 0);
+    ptr1 = strchrW(This->wine_url, '?');
+    if(ptr1) {
+        size += ptr1-This->wine_url;
+        ptr2 = strchrW(ptr1, '#');
+        if(ptr2)
+            size += strlenW(ptr2);
+    }else {
+        ptr1 = This->wine_url + strlenW(This->wine_url);
+        ptr2 = NULL;
+        size += strlenW(This->wine_url);
+    }
+
+    if(*query)
+        size++;
+
+    new_url = heap_alloc(size*sizeof(WCHAR));
+    memcpy(new_url, This->wine_url, (ptr1-This->wine_url)*sizeof(WCHAR));
+    ptr = new_url + (ptr1-This->wine_url);
+    if(*query) {
+        *ptr++ = '?';
+        MultiByteToWideChar(CP_ACP, 0, query, -1, ptr, len);
+        ptr += len-1;
+    }
+    if(ptr2)
+        strcpyW(ptr, ptr2);
+    else
+        *ptr = 0;
+
+    TRACE("setting %s\n", debugstr_w(new_url));
+
+    heap_free(This->wine_url);
+    This->wine_url = new_url;
+    return NS_OK;
+}
+
+static nsresult NSAPI nsURL_GetRef(nsIWineURI *iface, nsACString *aRef)
+{
+    nsURI *This = NSURI_THIS(iface);
+
+    TRACE("(%p)->(%p)\n", This, aRef);
+
+    if(This->nsurl)
+        return nsIURL_GetRef(This->nsurl, aRef);
+
+    FIXME("default action not implemented\n");
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static nsresult NSAPI nsURL_SetRef(nsIWineURI *iface, const nsACString *aRef)
+{
+    nsURI *This = NSURI_THIS(iface);
+
+    TRACE("(%p)->(%s)\n", This, debugstr_nsacstr(aRef));
+
+    if(This->nsurl)
+        return nsIURL_SetRef(This->nsurl, aRef);
+
+    FIXME("default action not implemented\n");
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static nsresult NSAPI nsURL_GetDirectory(nsIWineURI *iface, nsACString *aDirectory)
+{
+    nsURI *This = NSURI_THIS(iface);
+
+    TRACE("(%p)->(%p)\n", This, aDirectory);
+
+    if(This->nsurl)
+        return nsIURL_GetDirectory(This->nsurl, aDirectory);
+
+    FIXME("default action not implemented\n");
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static nsresult NSAPI nsURL_SetDirectory(nsIWineURI *iface, const nsACString *aDirectory)
+{
+    nsURI *This = NSURI_THIS(iface);
+
+    TRACE("(%p)->(%s)\n", This, debugstr_nsacstr(aDirectory));
+
+    if(This->nsurl)
+        return nsIURL_SetDirectory(This->nsurl, aDirectory);
+
+    FIXME("default action not implemented\n");
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static nsresult NSAPI nsURL_GetFileName(nsIWineURI *iface, nsACString *aFileName)
+{
+    nsURI *This = NSURI_THIS(iface);
+
+    TRACE("(%p)->(%p)\n", This, aFileName);
+
+    if(This->nsurl)
+        return nsIURL_GetFileName(This->nsurl, aFileName);
+
+    FIXME("default action not implemented\n");
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static nsresult NSAPI nsURL_SetFileName(nsIWineURI *iface, const nsACString *aFileName)
+{
+    nsURI *This = NSURI_THIS(iface);
+
+    TRACE("(%p)->(%s)\n", This, debugstr_nsacstr(aFileName));
+
+    if(This->nsurl)
+        return nsIURL_SetFileName(This->nsurl, aFileName);
+
+    FIXME("default action not implemented\n");
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static nsresult NSAPI nsURL_GetFileBaseName(nsIWineURI *iface, nsACString *aFileBaseName)
+{
+    nsURI *This = NSURI_THIS(iface);
+
+    TRACE("(%p)->(%p)\n", This, aFileBaseName);
+
+    if(This->nsurl)
+        return nsIURL_GetFileBaseName(This->nsurl, aFileBaseName);
+
+    FIXME("default action not implemented\n");
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static nsresult NSAPI nsURL_SetFileBaseName(nsIWineURI *iface, const nsACString *aFileBaseName)
+{
+    nsURI *This = NSURI_THIS(iface);
+
+    TRACE("(%p)->(%s)\n", This, debugstr_nsacstr(aFileBaseName));
+
+    if(This->nsurl)
+        return nsIURL_SetFileBaseName(This->nsurl, aFileBaseName);
+
+    FIXME("default action not implemented\n");
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static nsresult NSAPI nsURL_GetFileExtension(nsIWineURI *iface, nsACString *aFileExtension)
+{
+    nsURI *This = NSURI_THIS(iface);
+
+    TRACE("(%p)->(%p)\n", This, aFileExtension);
+
+    if(This->nsurl)
+        return nsIURL_GetFileExtension(This->nsurl, aFileExtension);
+
+    FIXME("default action not implemented\n");
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static nsresult NSAPI nsURL_SetFileExtension(nsIWineURI *iface, const nsACString *aFileExtension)
+{
+    nsURI *This = NSURI_THIS(iface);
+
+    TRACE("(%p)->(%s)\n", This, debugstr_nsacstr(aFileExtension));
+
+    if(This->nsurl)
+        return nsIURL_SetFileExtension(This->nsurl, aFileExtension);
+
+    FIXME("default action not implemented\n");
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static nsresult NSAPI nsURL_GetCommonBaseSpec(nsIWineURI *iface, nsIURI *aURIToCompare, nsACString *_retval)
+{
+    nsURI *This = NSURI_THIS(iface);
+
+    TRACE("(%p)->(%p %p)\n", This, aURIToCompare, _retval);
+
+    if(This->nsurl)
+        return nsIURL_GetCommonBaseSpec(This->nsurl, aURIToCompare, _retval);
+
+    FIXME("default action not implemented\n");
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static nsresult NSAPI nsURL_GetRelativeSpec(nsIWineURI *iface, nsIURI *aURIToCompare, nsACString *_retval)
+{
+    nsURI *This = NSURI_THIS(iface);
+
+    TRACE("(%p)->(%p %p)\n", This, aURIToCompare, _retval);
+
+    if(This->nsurl)
+        return nsIURL_GetRelativeSpec(This->nsurl, aURIToCompare, _retval);
+
+    FIXME("default action not implemented\n");
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
 static nsresult NSAPI nsURI_GetNSContainer(nsIWineURI *iface, NSContainer **aContainer)
 {
     nsURI *This = NSURI_THIS(iface);
@@ -1813,6 +2187,24 @@ static const nsIWineURIVtbl nsWineURIVtbl = {
     nsURI_GetAsciiSpec,
     nsURI_GetAsciiHost,
     nsURI_GetOriginCharset,
+    nsURL_GetFilePath,
+    nsURL_SetFilePath,
+    nsURL_GetParam,
+    nsURL_SetParam,
+    nsURL_GetQuery,
+    nsURL_SetQuery,
+    nsURL_GetRef,
+    nsURL_SetRef,
+    nsURL_GetDirectory,
+    nsURL_SetDirectory,
+    nsURL_GetFileName,
+    nsURL_SetFileName,
+    nsURL_GetFileBaseName,
+    nsURL_SetFileBaseName,
+    nsURL_GetFileExtension,
+    nsURL_SetFileExtension,
+    nsURL_GetCommonBaseSpec,
+    nsURL_GetRelativeSpec,
     nsURI_GetNSContainer,
     nsURI_SetNSContainer,
     nsURI_GetIsDocumentURI,
@@ -1836,6 +2228,11 @@ static nsresult create_uri(nsIURI *uri, NSContainer *container, nsIWineURI **_re
     if(container)
         nsIWebBrowserChrome_AddRef(NSWBCHROME(container));
 
+    if(uri)
+        nsIURI_QueryInterface(uri, &IID_nsIURL, (void**)&ret->nsurl);
+    else
+        ret->nsurl = NULL;
+
     TRACE("retval=%p\n", ret);
     *_retval = NSWINEURI(ret);
     return NS_OK;
@@ -2051,15 +2448,15 @@ static nsresult NSAPI nsIOService_GetProtocolFlags(nsIIOService *iface, const ch
 
 static BOOL is_gecko_special_uri(const char *spec)
 {
-    static const char chromeW[] = "chrome:";
-    static const char jarW[] = "jar:";
-    static const char resourceW[] = "resource:";
-    static const char javascriptW[] = "javascript:";
+    static const char *special_schemes[] = {"chrome:", "jar:", "resource:", "javascript:", "wyciwyg:"};
+    int i;
+
+    for(i=0; i < sizeof(special_schemes)/sizeof(*special_schemes); i++) {
+        if(!strncasecmp(spec, special_schemes[i], strlen(special_schemes[i])))
+            return TRUE;
+    }
 
-    return !strncasecmp(spec, chromeW,     sizeof(chromeW)-1)
-        || !strncasecmp(spec, resourceW,   sizeof(resourceW)-1)
-        || !strncasecmp(spec, jarW,        sizeof(jarW)-1)
-        || !strncasecmp(spec, javascriptW, sizeof(javascriptW)-1);
+    return FALSE;
 }
 
 static nsresult NSAPI nsIOService_NewURI(nsIIOService *iface, const nsACString *aSpec,
@@ -2187,6 +2584,7 @@ static nsresult NSAPI nsIOService_NewChannelFromURI(nsIIOService *iface, nsIURI
 
     ret->lpHttpChannelVtbl = &nsChannelVtbl;
     ret->lpUploadChannelVtbl = &nsUploadChannelVtbl;
+    ret->lpIHttpChannelInternalVtbl = &nsHttpChannelInternalVtbl;
     ret->ref = 1;
     ret->channel = channel;
     ret->uri = wine_uri;
@@ -2194,8 +2592,10 @@ static nsresult NSAPI nsIOService_NewChannelFromURI(nsIIOService *iface, nsIURI
     nsIURI_AddRef(aURI);
     ret->original_uri = aURI;
 
-    if(channel)
+    if(channel) {
         nsIChannel_QueryInterface(channel, &IID_nsIHttpChannel, (void**)&ret->http_channel);
+        nsIChannel_QueryInterface(channel, &IID_nsIHttpChannelInternal, (void**)&ret->http_channel_internal);
+    }
 
     *_retval = NSCHANNEL(ret);
     return NS_OK;
index e86537f..dc0fb4a 100644 (file)
@@ -84,8 +84,10 @@ static ULONG WINAPI OmNavigator_Release(IOmNavigator *iface)
 
     TRACE("(%p) ref=%d\n", This, ref);
 
-    if(!ref)
+    if(!ref) {
+        release_dispex(&This->dispex);
         heap_free(This);
+    }
 
     return ref;
 }
@@ -139,8 +141,19 @@ static HRESULT WINAPI OmNavigator_get_appCodeName(IOmNavigator *iface, BSTR *p)
 static HRESULT WINAPI OmNavigator_get_appName(IOmNavigator *iface, BSTR *p)
 {
     OmNavigator *This = OMNAVIGATOR_THIS(iface);
-    FIXME("(%p)->(%p)\n", This, p);
-    return E_NOTIMPL;
+
+    static const WCHAR app_nameW[] =
+        {'M','i','c','r','o','s','o','f','t',' ',
+         'I','n','t','e','r','n','e','t',' ',
+         'E','x','p','l','o','r','e','r',0};
+
+    TRACE("(%p)->(%p)\n", This, p);
+
+    *p = SysAllocString(app_nameW);
+    if(!*p)
+        return E_OUTOFMEMORY;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI OmNavigator_get_appVersion(IOmNavigator *iface, BSTR *p)
@@ -166,8 +179,24 @@ static HRESULT WINAPI OmNavigator_get_appVersion(IOmNavigator *iface, BSTR *p)
 static HRESULT WINAPI OmNavigator_get_userAgent(IOmNavigator *iface, BSTR *p)
 {
     OmNavigator *This = OMNAVIGATOR_THIS(iface);
-    FIXME("(%p)->(%p)\n", This, p);
-    return E_NOTIMPL;
+    char user_agent[512];
+    DWORD size;
+    HRESULT hres;
+
+    TRACE("(%p)->(%p)\n", This, p);
+
+    size = sizeof(user_agent);
+    hres = ObtainUserAgentString(0, user_agent, &size);
+    if(FAILED(hres))
+        return hres;
+
+    size = MultiByteToWideChar(CP_ACP, 0, user_agent, -1, NULL, 0);
+    *p = SysAllocStringLen(NULL, size-1);
+    if(!*p)
+        return E_OUTOFMEMORY;
+
+    MultiByteToWideChar(CP_ACP, 0, user_agent, -1, *p, size);
+    return S_OK;
 }
 
 static HRESULT WINAPI OmNavigator_javaEnabled(IOmNavigator *iface, VARIANT_BOOL *enabled)
@@ -215,8 +244,16 @@ static HRESULT WINAPI OmNavigator_get_opsProfile(IOmNavigator *iface, IHTMLOpsPr
 static HRESULT WINAPI OmNavigator_toString(IOmNavigator *iface, BSTR *String)
 {
     OmNavigator *This = OMNAVIGATOR_THIS(iface);
-    FIXME("(%p)->(%p)\n", This, String);
-    return E_NOTIMPL;
+
+    static const WCHAR objectW[] = {'[','o','b','j','e','c','t',']',0};
+
+    TRACE("(%p)->(%p)\n", This, String);
+
+    if(!String)
+        return E_INVALIDARG;
+
+    *String = SysAllocString(objectW);
+    return *String ? S_OK : E_OUTOFMEMORY;
 }
 
 static HRESULT WINAPI OmNavigator_get_cpuClass(IOmNavigator *iface, BSTR *p)
index c8a0c57..6c1a0e5 100644 (file)
 
 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
 
-#define USER_AGENT "User-Agent:"
-#define CONTENT_TYPE "Content-Type:"
-
-static int fix_headers(char *buf, DWORD post_len)
-{
-    char *ptr = buf, *ptr2;
-
-    while(*ptr && (ptr[0] != '\r' || ptr[1] != '\n')) {
-        for(ptr2=ptr+1; *ptr2 && (ptr2[0] != '\r' || ptr2[1] != '\n'); ptr2++);
-
-        if(*ptr2)
-            ptr2 += 2;
-
-        if(!strncasecmp(ptr, USER_AGENT, sizeof(USER_AGENT)-1)) {
-            FIXME("Ignoring User-Agent header\n");
-            memmove(ptr, ptr2, strlen(ptr2)+1);
-        }else if(!post_len && !strncasecmp(ptr, CONTENT_TYPE, sizeof(CONTENT_TYPE)-1)) {
-            TRACE("Ignoring Content-Type header\n");
-            memmove(ptr, ptr2, strlen(ptr2)+1);
-        }else {
-            ptr = ptr2;
-        }
-    }
-
-    *ptr = 0;
-    return ptr-buf;
-}
-
-static nsIInputStream *get_post_data_stream(IBindCtx *bctx)
-{
-    nsIInputStream *ret = NULL;
-    IUnknown *unk;
-    IBindStatusCallback *callback;
-    IServiceProvider *service_provider;
-    BINDINFO bindinfo;
-    DWORD bindf = 0;
-    DWORD post_len = 0, headers_len = 0;
-    LPWSTR headers = NULL;
-    WCHAR emptystr[] = {0};
-    char *data;
-    HRESULT hres;
-
-    static WCHAR _BSCB_Holder_[] =
-        {'_','B','S','C','B','_','H','o','l','d','e','r','_',0};
-
-
-    /* FIXME: This should be done in URLMoniker */
-    if(!bctx)
-        return NULL;
-
-    hres = IBindCtx_GetObjectParam(bctx, _BSCB_Holder_, &unk);
-    if(FAILED(hres))
-        return NULL;
-
-    hres = IUnknown_QueryInterface(unk, &IID_IBindStatusCallback, (void**)&callback);
-    if(FAILED(hres)) {
-        IUnknown_Release(unk);
-        return NULL;
-    }
-
-    hres = IUnknown_QueryInterface(unk, &IID_IServiceProvider, (void**)&service_provider);
-    IUnknown_Release(unk);
-    if(SUCCEEDED(hres)) {
-        IHttpNegotiate *http_negotiate;
-
-        hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate, &IID_IHttpNegotiate,
-                                             (void**)&http_negotiate);
-        if(SUCCEEDED(hres)) {
-            hres = IHttpNegotiate_BeginningTransaction(http_negotiate, emptystr,
-                                                       emptystr, 0, &headers);
-            IHttpNegotiate_Release(http_negotiate);
-
-            if(SUCCEEDED(hres) && headers)
-                headers_len = WideCharToMultiByte(CP_ACP, 0, headers, -1, NULL, 0, NULL, NULL);
-        }
-
-        IServiceProvider_Release(service_provider);
-    }
-
-    memset(&bindinfo, 0, sizeof(bindinfo));
-    bindinfo.cbSize = sizeof(bindinfo);
-
-    hres = IBindStatusCallback_GetBindInfo(callback, &bindf, &bindinfo);
-
-    if(SUCCEEDED(hres) && bindinfo.dwBindVerb == BINDVERB_POST)
-        post_len = bindinfo.cbstgmedData;
-
-    if(headers_len || post_len) {
-        int len = 0;
-
-        static const char content_length[] = "Content-Length: %u\r\n\r\n";
-
-        data = heap_alloc(headers_len+post_len+sizeof(content_length)+10);
-
-        if(headers_len) {
-            WideCharToMultiByte(CP_ACP, 0, headers, -1, data, headers_len, NULL, NULL);
-            len = fix_headers(data, post_len);
-            if(len >= 2 && (data[len-1] != '\n' || data[len-2] != '\r')) {
-                data[len++] = '\r';
-                data[len++] = '\n';
-            }
-        }
-
-        if(post_len) {
-            sprintf(data+len, content_length, post_len);
-            len += strlen(data+len);
-
-            memcpy(data+len, bindinfo.stgmedData.u.hGlobal, post_len);
-        }
-
-        TRACE("data = %s\n", debugstr_an(data, len+post_len));
-
-        if(len)
-            ret = create_nsstream(data, len+post_len);
-    }
-
-    CoTaskMemFree(headers);
-    ReleaseBindInfo(&bindinfo);
-    IBindStatusCallback_Release(callback);
-
-    return ret;
-}
-
 static BOOL use_gecko_script(LPCWSTR url)
 {
     static const WCHAR fileW[] = {'f','i','l','e',':'};
@@ -304,27 +181,15 @@ static HRESULT set_moniker(HTMLDocument *This, IMoniker *mon, IBindCtx *pibc, BO
     push_task(task);
 
     if(This->nscontainer) {
-        nsIInputStream *post_data_stream = get_post_data_stream(pibc);
-
         This->nscontainer->bscallback = bscallback;
         nsres = nsIWebNavigation_LoadURI(This->nscontainer->navigation, url,
-                LOAD_FLAGS_NONE, NULL, post_data_stream, NULL);
+                LOAD_FLAGS_NONE, NULL, NULL, NULL);
         This->nscontainer->bscallback = NULL;
-
-        if(post_data_stream)
-            nsIInputStream_Release(post_data_stream);
-
-        if(NS_SUCCEEDED(nsres)) {
-            /* FIXME: don't return here (URL Moniker needs to be good enough) */
-
+        if(NS_FAILED(nsres)) {
+            WARN("LoadURI failed: %08x\n", nsres);
             IUnknown_Release((IUnknown*)bscallback);
             CoTaskMemFree(url);
-
-            if(bind_complete)
-                *bind_complete = TRUE;
-            return S_OK;
-        }else if(nsres != WINE_NS_LOAD_FROM_MONIKER) {
-            WARN("LoadURI failed: %08x\n", nsres);
+            return E_FAIL;
         }
     }
 
@@ -337,7 +202,7 @@ static HRESULT set_moniker(HTMLDocument *This, IMoniker *mon, IBindCtx *pibc, BO
     return S_OK;
 }
 
-static HRESULT get_doc_string(HTMLDocument *This, char **str, DWORD *len)
+static HRESULT get_doc_string(HTMLDocument *This, char **str)
 {
     nsIDOMNode *nsnode;
     LPCWSTR strw;
@@ -362,9 +227,7 @@ static HRESULT get_doc_string(HTMLDocument *This, char **str, DWORD *len)
     nsAString_GetData(&nsstr, &strw);
     TRACE("%s\n", debugstr_w(strw));
 
-    *len = WideCharToMultiByte(CP_ACP, 0, strw, -1, NULL, 0, NULL, NULL);
-    *str = heap_alloc(*len);
-    WideCharToMultiByte(CP_ACP, 0, strw, -1, *str, *len, NULL, NULL);
+    *str = heap_strdupWtoA(strw);
 
     nsAString_Finish(&nsstr);
 
@@ -583,7 +446,7 @@ static HRESULT WINAPI PersistFile_Save(IPersistFile *iface, LPCOLESTR pszFileNam
 {
     HTMLDocument *This = PERSISTFILE_THIS(iface);
     char *str;
-    DWORD len, written=0;
+    DWORD written=0;
     HANDLE file;
     HRESULT hres;
 
@@ -596,9 +459,9 @@ static HRESULT WINAPI PersistFile_Save(IPersistFile *iface, LPCOLESTR pszFileNam
         return E_FAIL;
     }
 
-    hres = get_doc_string(This, &str, &len);
+    hres = get_doc_string(This, &str);
     if(SUCCEEDED(hres))
-        WriteFile(file, str, len, &written, NULL);
+        WriteFile(file, str, strlen(str), &written, NULL);
 
     CloseHandle(file);
     return hres;
@@ -698,16 +561,16 @@ static HRESULT WINAPI PersistStreamInit_Save(IPersistStreamInit *iface, LPSTREAM
 {
     HTMLDocument *This = PERSTRINIT_THIS(iface);
     char *str;
-    DWORD len, written=0;
+    DWORD written=0;
     HRESULT hres;
 
     TRACE("(%p)->(%p %x)\n", This, pStm, fClearDirty);
 
-    hres = get_doc_string(This, &str, &len);
+    hres = get_doc_string(This, &str);
     if(FAILED(hres))
         return hres;
 
-    hres = IStream_Write(pStm, str, len, &written);
+    hres = IStream_Write(pStm, str, strlen(str), &written);
     if(FAILED(hres))
         FIXME("Write failed: %08x\n", hres);
 
index 55636d2..e12588c 100644 (file)
@@ -67,12 +67,30 @@ typedef struct {
 #define ACTSCPWIN(x)   (&(x)->lpIActiveScriptSiteWindowVtbl)
 #define ACTSCPDBG32(x) (&(x)->lpIActiveScriptSiteDebug32Vtbl)
 
+static void set_script_prop(ScriptHost *script_host, DWORD property, VARIANT *val)
+{
+    IActiveScriptProperty *script_prop;
+    HRESULT hres;
+
+    hres = IActiveScript_QueryInterface(script_host->script, &IID_IActiveScriptProperty,
+            (void**)&script_prop);
+    if(FAILED(hres)) {
+        WARN("Could not get IActiveScriptProperty iface: %08x\n", hres);
+        return;
+    }
+
+    hres = IActiveScriptProperty_SetProperty(script_prop, property, NULL, val);
+    IActiveScriptProperty_Release(script_prop);
+    if(FAILED(hres))
+        WARN("SetProperty(%x) failed: %08x\n", property, hres);
+}
+
 static BOOL init_script_engine(ScriptHost *script_host)
 {
-    IActiveScriptProperty *property;
     IObjectSafety *safety;
     SCRIPTSTATE state;
     DWORD supported_opts=0, enabled_opts=0;
+    VARIANT var;
     HRESULT hres;
 
     hres = IActiveScript_QueryInterface(script_host->script, &IID_IActiveScriptParse, (void**)&script_host->parse);
@@ -104,20 +122,13 @@ static BOOL init_script_engine(ScriptHost *script_host)
     if(FAILED(hres))
         return FALSE;
 
-    hres = IActiveScript_QueryInterface(script_host->script, &IID_IActiveScriptProperty, (void**)&property);
-    if(SUCCEEDED(hres)) {
-        VARIANT var;
-
-        V_VT(&var) = VT_BOOL;
-        V_BOOL(&var) = VARIANT_TRUE;
-        hres = IActiveScriptProperty_SetProperty(property, SCRIPTPROP_HACK_TRIDENTEVENTSINK, NULL, &var);
-        if(FAILED(hres))
-            WARN("SetProperty failed: %08x\n", hres);
+    V_VT(&var) = VT_I4;
+    V_I4(&var) = 1;
+    set_script_prop(script_host, SCRIPTPROP_INVOKEVERSIONING, &var);
 
-        IActiveScriptProperty_Release(property);
-    }else {
-        WARN("Could not get IActiveScriptProperty: %08x\n", hres);
-    }
+    V_VT(&var) = VT_BOOL;
+    V_BOOL(&var) = VARIANT_TRUE;
+    set_script_prop(script_host, SCRIPTPROP_HACK_TRIDENTEVENTSINK, &var);
 
     hres = IActiveScriptParse64_InitNew(script_host->parse);
     if(FAILED(hres)) {
@@ -146,8 +157,13 @@ static BOOL init_script_engine(ScriptHost *script_host)
 
     hres = IActiveScript_AddNamedItem(script_host->script, windowW,
             SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS);
-    if(FAILED(hres))
+    if(SUCCEEDED(hres)) {
+        V_VT(&var) = VT_BOOL;
+        V_BOOL(&var) = VARIANT_TRUE;
+        set_script_prop(script_host, SCRIPTPROP_ABBREVIATE_GLOBALNAME_RESOLUTION, &var);
+    }else {
        WARN("AddNamedItem failed: %08x\n", hres);
+    }
 
     hres = IActiveScript_QueryInterface(script_host->script, &IID_IActiveScriptParseProcedure2,
                                         (void**)&script_host->parse_proc);
index 9fabc46..2fc32be 100644 (file)
@@ -556,7 +556,7 @@ IUnknown* create_attribute( xmlNodePtr attribute )
     This->lpVtbl = &domattr_vtbl;
     This->ref = 1;
 
-    node = create_basic_node( attribute, (IUnknown*)&This->lpVtbl );
+    node = create_basic_node( attribute, (IUnknown*)&This->lpVtbl, NULL );
     if(!node)
     {
         HeapFree(GetProcessHeap(), 0, This);
index a9b7fee..b0ef3d7 100644 (file)
@@ -779,7 +779,7 @@ IUnknown* create_cdata( xmlNodePtr text )
     This->lpVtbl = &domcdata_vtbl;
     This->ref = 1;
 
-    node = create_basic_node( text, (IUnknown*)&This->lpVtbl );
+    node = create_basic_node( text, (IUnknown*)&This->lpVtbl, NULL );
     if(!node)
     {
         HeapFree(GetProcessHeap(), 0, This);
index a8cf528..346ad19 100644 (file)
@@ -777,7 +777,7 @@ IUnknown* create_comment( xmlNodePtr comment )
     This->lpVtbl = &domcomment_vtbl;
     This->ref = 1;
 
-    node = create_basic_node( comment, (IUnknown*)&This->lpVtbl );
+    node = create_basic_node( comment, (IUnknown*)&This->lpVtbl, NULL );
     if(!node)
     {
         HeapFree(GetProcessHeap(), 0, This);
index 59d8878..529f9a4 100644 (file)
@@ -91,6 +91,7 @@ static REFIID tid_ids[] = {
     &IID_IXMLDOMParseError,
     &IID_IXMLDOMProcessingInstruction,
     &IID_IXMLDOMSchemaCollection,
+    &IID_IXMLDOMSelection,
     &IID_IXMLDOMText,
     &IID_IXMLElement,
     &IID_IXMLDOMDocument,
index 572d223..1330c19 100644 (file)
@@ -529,7 +529,7 @@ IUnknown* create_doc_fragment( xmlNodePtr fragment )
     This->lpVtbl = &domfrag_vtbl;
     This->ref = 1;
 
-    node = create_basic_node( fragment, (IUnknown*)&This->lpVtbl );
+    node = create_basic_node( fragment, (IUnknown*)&This->lpVtbl, NULL );
     if(!node)
     {
         HeapFree(GetProcessHeap(), 0, This);
index 84bd43c..ad0fe0a 100644 (file)
@@ -77,9 +77,6 @@ typedef struct _domdoc
 
     /* IObjectSafety */
     DWORD safeopt;
-
-    /* IDispatchEx */
-    DispatchEx dispex;
 } domdoc;
 
 /*
@@ -466,7 +463,7 @@ static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument2 *iface, REFIID rii
     {
         *ppvObject = &This->lpvtblISupportErrorInfo;
     }
-    else if(dispex_query_interface(&This->dispex, riid, ppvObject))
+    else if(dispex_query_interface(&This->node->dispex, riid, ppvObject))
     {
         return *ppvObject ? S_OK : E_NOINTERFACE;
     }
@@ -1043,7 +1040,7 @@ static HRESULT WINAPI domdoc_createElement(
     xmldoc_add_orphan(xmlnode->doc, xmlnode);
 
     TRACE("created xmlptr %p\n", xmlnode);
-    elem_unk = create_element(xmlnode, NULL);
+    elem_unk = create_element(xmlnode);
     HeapFree(GetProcessHeap(), 0, xml_name);
 
     hr = IUnknown_QueryInterface(elem_unk, &IID_IXMLDOMElement, (void **)element);
@@ -2218,15 +2215,13 @@ HRESULT DOMDocument_create_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument2 **docu
     doc->safeopt = 0;
     doc->bsc = NULL;
 
-    doc->node = create_basic_node( (xmlNodePtr)xmldoc, (IUnknown*)&doc->lpVtbl );
+    doc->node = create_basic_node( (xmlNodePtr)xmldoc, (IUnknown*)&doc->lpVtbl, &domdoc_dispex );
     if(!doc->node)
     {
         HeapFree(GetProcessHeap(), 0, doc);
         return E_FAIL;
     }
 
-    init_dispex(&doc->dispex, (IUnknown*)&doc->lpVtbl, &domdoc_dispex);
-
     *document = (IXMLDOMDocument2*)&doc->lpVtbl;
 
     TRACE("returning iface %p\n", *document);
index 33db539..6590e5b 100644 (file)
@@ -41,8 +41,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msxml);
 typedef struct _domelem
 {
     const struct IXMLDOMElementVtbl *lpVtbl;
-    const struct IUnknownVtbl *lpInternalUnkVtbl;
-    IUnknown *pUnkOuter;
     LONG ref;
     xmlnode *node;
 } domelem;
@@ -52,11 +50,6 @@ static inline domelem *impl_from_IXMLDOMElement( IXMLDOMElement *iface )
     return (domelem *)((char*)iface - FIELD_OFFSET(domelem, lpVtbl));
 }
 
-static inline domelem *impl_from_InternalUnknown( IUnknown *iface )
-{
-    return (domelem *)((char*)iface - FIELD_OFFSET(domelem, lpInternalUnkVtbl));
-}
-
 static inline xmlNodePtr get_element( domelem *This )
 {
     return This->node->node;
@@ -68,23 +61,54 @@ static HRESULT WINAPI domelem_QueryInterface(
     void** ppvObject )
 {
     domelem *This = impl_from_IXMLDOMElement( iface );
+
     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
 
-    return IUnknown_QueryInterface(This->pUnkOuter, riid, ppvObject);
+    if ( IsEqualGUID( riid, &IID_IXMLDOMElement ) ||
+         IsEqualGUID( riid, &IID_IDispatch ) ||
+         IsEqualGUID( riid, &IID_IUnknown ) )
+    {
+        *ppvObject = &This->lpVtbl;
+    }
+    else if ( IsEqualGUID( riid, &IID_IXMLDOMNode ) )
+    {
+        *ppvObject = IXMLDOMNode_from_impl(This->node);
+    }
+    else
+    {
+        FIXME("interface %s not implemented\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef( (IUnknown*)*ppvObject );
+    return S_OK;
 }
 
 static ULONG WINAPI domelem_AddRef(
     IXMLDOMElement *iface )
 {
     domelem *This = impl_from_IXMLDOMElement( iface );
-    return IUnknown_AddRef(This->pUnkOuter);
+    LONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) ref=%d\n", This, ref);
+
+    return ref;
 }
 
 static ULONG WINAPI domelem_Release(
     IXMLDOMElement *iface )
 {
     domelem *This = impl_from_IXMLDOMElement( iface );
-    return IUnknown_Release(This->pUnkOuter);
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) ref=%d\n", This, ref);
+
+    if(!ref) {
+        IXMLDOMNode_Release(IXMLDOMNode_from_impl(This->node));
+        heap_free(This);
+    }
+
+    return ref;
 }
 
 static HRESULT WINAPI domelem_GetTypeInfoCount(
@@ -727,66 +751,7 @@ static const struct IXMLDOMElementVtbl domelem_vtbl =
     domelem_normalize,
 };
 
-static HRESULT WINAPI Internal_QueryInterface(
-    IUnknown *iface,
-    REFIID riid,
-    void** ppvObject )
-{
-    domelem *This = impl_from_InternalUnknown( iface );
-    TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
-
-    if ( IsEqualGUID( riid, &IID_IXMLDOMElement ) ||
-         IsEqualGUID( riid, &IID_IDispatch ) ||
-         IsEqualGUID( riid, &IID_IUnknown ) )
-    {
-        *ppvObject = &This->lpVtbl;
-    }
-    else if ( IsEqualGUID( riid, &IID_IXMLDOMNode ) )
-    {
-        *ppvObject = IXMLDOMNode_from_impl(This->node);
-    }
-    else
-    {
-        FIXME("interface %s not implemented\n", debugstr_guid(riid));
-        return E_NOINTERFACE;
-    }
-
-    IUnknown_AddRef( (IUnknown*)*ppvObject );
-
-    return S_OK;
-}
-
-static ULONG WINAPI Internal_AddRef(
-    IUnknown *iface )
-{
-    domelem *This = impl_from_InternalUnknown( iface );
-    return InterlockedIncrement( &This->ref );
-}
-
-static ULONG WINAPI Internal_Release(
-    IUnknown *iface )
-{
-    domelem *This = impl_from_InternalUnknown( iface );
-    ULONG ref;
-
-    ref = InterlockedDecrement( &This->ref );
-    if ( ref == 0 )
-    {
-        IXMLDOMNode_Release( IXMLDOMNode_from_impl(This->node) );
-        HeapFree( GetProcessHeap(), 0, This );
-    }
-
-    return ref;
-}
-
-static const struct IUnknownVtbl internal_unk_vtbl =
-{
-    Internal_QueryInterface,
-    Internal_AddRef,
-    Internal_Release
-};
-
-IUnknown* create_element( xmlNodePtr element, IUnknown *pUnkOuter )
+IUnknown* create_element( xmlNodePtr element )
 {
     domelem *This;
 
@@ -796,21 +761,15 @@ IUnknown* create_element( xmlNodePtr element, IUnknown *pUnkOuter )
 
     This->lpVtbl = &domelem_vtbl;
     This->ref = 1;
-    This->lpInternalUnkVtbl = &internal_unk_vtbl;
-
-    if(pUnkOuter)
-        This->pUnkOuter = pUnkOuter; /* Don't take a ref on outer Unknown */
-    else
-        This->pUnkOuter = (IUnknown *)&This->lpInternalUnkVtbl;
 
-    This->node = create_basic_node( element, (IUnknown*)&This->lpVtbl );
+    This->node = create_basic_node( element, (IUnknown*)&This->lpVtbl, NULL );
     if(!This->node)
     {
         HeapFree(GetProcessHeap(), 0, This);
         return NULL;
     }
 
-    return (IUnknown*) &This->lpInternalUnkVtbl;
+    return (IUnknown*) &This->lpVtbl;
 }
 
 #endif
index 1726e2f..102bf44 100644 (file)
@@ -528,7 +528,7 @@ IUnknown* create_doc_entity_ref( xmlNodePtr entity )
     This->lpVtbl = &entityref_vtbl;
     This->ref = 1;
 
-    node = create_basic_node( entity, (IUnknown*)&This->lpVtbl );
+    node = create_basic_node( entity, (IUnknown*)&This->lpVtbl, NULL );
     if(!node)
     {
         HeapFree(GetProcessHeap(), 0, This);
index d09b380..57dec0f 100644 (file)
 # error You must include config.h to use this header
 #endif
 
+/* typelibs */
+typedef enum tid_t {
+    IXMLDOMAttribute_tid,
+    IXMLDOMCDATASection_tid,
+    IXMLDOMComment_tid,
+    IXMLDOMDocument_tid,
+    IXMLDOMDocument2_tid,
+    IXMLDOMDocumentFragment_tid,
+    IXMLDOMElement_tid,
+    IXMLDOMEntityReference_tid,
+    IXMLDOMImplementation_tid,
+    IXMLDOMNamedNodeMap_tid,
+    IXMLDOMNode_tid,
+    IXMLDOMNodeList_tid,
+    IXMLDOMParseError_tid,
+    IXMLDOMProcessingInstruction_tid,
+    IXMLDOMSchemaCollection_tid,
+    IXMLDOMSelection_tid,
+    IXMLDOMText_tid,
+    IXMLElement_tid,
+    IXMLDocument_tid,
+    IXMLHTTPRequest_tid,
+    IVBSAXAttributes_tid,
+    IVBSAXContentHandler_tid,
+    IVBSAXDeclHandler_tid,
+    IVBSAXDTDHandler_tid,
+    IVBSAXEntityResolver_tid,
+    IVBSAXErrorHandler_tid,
+    IVBSAXLexicalHandler_tid,
+    IVBSAXLocator_tid,
+    IVBSAXXMLFilter_tid,
+    IVBSAXXMLReader_tid,
+    IMXAttributes_tid,
+    IMXReaderControl_tid,
+    IMXWriter_tid,
+    LAST_tid
+} tid_t;
+
+extern HRESULT get_typeinfo(tid_t tid, ITypeInfo **typeinfo);
+extern void release_typelib(void);
+
+typedef struct dispex_data_t dispex_data_t;
+typedef struct dispex_dynamic_data_t dispex_dynamic_data_t;
+
+#define MSXML_DISPID_CUSTOM_MIN 0x60000000
+#define MSXML_DISPID_CUSTOM_MAX 0x6fffffff
+
+typedef struct {
+    HRESULT (*get_dispid)(IUnknown*,BSTR,DWORD,DISPID*);
+    HRESULT (*invoke)(IUnknown*,DISPID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*);
+} dispex_static_data_vtbl_t;
+
+typedef struct {
+    const dispex_static_data_vtbl_t *vtbl;
+    const tid_t disp_tid;
+    dispex_data_t *data;
+    const tid_t* const iface_tids;
+} dispex_static_data_t;
+
+typedef struct {
+    const IDispatchExVtbl  *lpIDispatchExVtbl;
+
+    IUnknown *outer;
+
+    dispex_static_data_t *data;
+    dispex_dynamic_data_t *dynamic_data;
+} DispatchEx;
+
+void init_dispex(DispatchEx*,IUnknown*,dispex_static_data_t*);
+BOOL dispex_query_interface(DispatchEx*,REFIID,void**);
+
 #ifdef HAVE_LIBXML2
 
 #ifdef HAVE_LIBXML_PARSER_H
 extern IUnknown         *create_domdoc( xmlNodePtr document );
 extern IUnknown         *create_xmldoc( void );
 extern IXMLDOMNode      *create_node( xmlNodePtr node );
-extern IUnknown         *create_element( xmlNodePtr element, IUnknown *pUnkOuter );
+extern IUnknown         *create_element( xmlNodePtr element );
 extern IUnknown         *create_attribute( xmlNodePtr attribute );
 extern IUnknown         *create_text( xmlNodePtr text );
 extern IUnknown         *create_pi( xmlNodePtr pi );
@@ -71,6 +142,7 @@ extern xmlDocPtr parse_xml(char *ptr, int len);
 /* IXMLDOMNode Internal Structure */
 typedef struct _xmlnode
 {
+    DispatchEx dispex;
     const struct IXMLDOMNodeVtbl *lpVtbl;
     const struct IUnknownVtbl *lpInternalUnkVtbl;
     IUnknown *pUnkOuter;
@@ -88,7 +160,7 @@ static inline IXMLDOMNode *IXMLDOMNode_from_impl(xmlnode *This)
     return (IXMLDOMNode*)&This->lpVtbl;
 }
 
-extern xmlnode *create_basic_node(xmlNodePtr,IUnknown*);
+extern xmlnode *create_basic_node(xmlNodePtr,IUnknown*,dispex_static_data_t*);
 
 extern HRESULT DOMDocument_create_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument2 **document);
 
@@ -140,76 +212,6 @@ typedef struct bsc_t bsc_t;
 HRESULT bind_url(LPCWSTR, HRESULT (*onDataAvailable)(void*,char*,DWORD), void*, bsc_t**);
 void detach_bsc(bsc_t*);
 
-/* typelibs */
-typedef enum tid_t {
-    IXMLDOMAttribute_tid,
-    IXMLDOMCDATASection_tid,
-    IXMLDOMComment_tid,
-    IXMLDOMDocument_tid,
-    IXMLDOMDocument2_tid,
-    IXMLDOMDocumentFragment_tid,
-    IXMLDOMElement_tid,
-    IXMLDOMEntityReference_tid,
-    IXMLDOMImplementation_tid,
-    IXMLDOMNamedNodeMap_tid,
-    IXMLDOMNode_tid,
-    IXMLDOMNodeList_tid,
-    IXMLDOMParseError_tid,
-    IXMLDOMProcessingInstruction_tid,
-    IXMLDOMSchemaCollection_tid,
-    IXMLDOMText_tid,
-    IXMLElement_tid,
-    IXMLDocument_tid,
-    IXMLHTTPRequest_tid,
-    IVBSAXAttributes_tid,
-    IVBSAXContentHandler_tid,
-    IVBSAXDeclHandler_tid,
-    IVBSAXDTDHandler_tid,
-    IVBSAXEntityResolver_tid,
-    IVBSAXErrorHandler_tid,
-    IVBSAXLexicalHandler_tid,
-    IVBSAXLocator_tid,
-    IVBSAXXMLFilter_tid,
-    IVBSAXXMLReader_tid,
-    IMXAttributes_tid,
-    IMXReaderControl_tid,
-    IMXWriter_tid,
-    LAST_tid
-} tid_t;
-
-extern HRESULT get_typeinfo(tid_t tid, ITypeInfo **typeinfo);
-extern void release_typelib(void);
-
-typedef struct dispex_data_t dispex_data_t;
-typedef struct dispex_dynamic_data_t dispex_dynamic_data_t;
-
-#define MSXML_DISPID_CUSTOM_MIN 0x60000000
-#define MSXML_DISPID_CUSTOM_MAX 0x6fffffff
-
-typedef struct {
-    HRESULT (*get_dispid)(IUnknown*,BSTR,DWORD,DISPID*);
-    HRESULT (*invoke)(IUnknown*,DISPID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*);
-} dispex_static_data_vtbl_t;
-
-typedef struct {
-    const dispex_static_data_vtbl_t *vtbl;
-    const tid_t disp_tid;
-    dispex_data_t *data;
-    const tid_t* const iface_tids;
-} dispex_static_data_t;
-
-typedef struct {
-    const IDispatchExVtbl  *lpIDispatchExVtbl;
-
-    IUnknown *outer;
-
-    dispex_static_data_t *data;
-    dispex_dynamic_data_t *dynamic_data;
-} DispatchEx;
-
-void init_dispex(DispatchEx*,IUnknown*,dispex_static_data_t*);
-BOOL dispex_query_interface(DispatchEx*,REFIID,void**);
-
 /* memory allocation functions */
 
 static inline void *heap_alloc(size_t len)
index 2876ef3..987b07d 100644 (file)
@@ -1542,7 +1542,7 @@ static const struct IUnknownVtbl internal_unk_vtbl =
     Internal_Release
 };
 
-xmlnode *create_basic_node( xmlNodePtr node, IUnknown *pUnkOuter )
+xmlnode *create_basic_node( xmlNodePtr node, IUnknown *pUnkOuter, dispex_static_data_t *dispex_data )
 {
     xmlnode *This;
 
@@ -1561,6 +1561,9 @@ xmlnode *create_basic_node( xmlNodePtr node, IUnknown *pUnkOuter )
     else
         This->pUnkOuter = (IUnknown *)&This->lpInternalUnkVtbl;
 
+    if(dispex_data)
+        init_dispex(&This->dispex, This->pUnkOuter, dispex_data);
+
     This->ref = 1;
     This->node = node;
 
@@ -1580,7 +1583,7 @@ IXMLDOMNode *create_node( xmlNodePtr node )
     switch(node->type)
     {
     case XML_ELEMENT_NODE:
-        pUnk = create_element( node, NULL );
+        pUnk = create_element( node );
         break;
     case XML_ATTRIBUTE_NODE:
         pUnk = create_attribute( node );
@@ -1599,7 +1602,7 @@ IXMLDOMNode *create_node( xmlNodePtr node )
         break;
     default:
         FIXME("only creating basic node for type %d\n", node->type);
-        pUnk = (IUnknown*)&create_basic_node( node, NULL )->lpInternalUnkVtbl;
+        pUnk = (IUnknown*)&create_basic_node( node, NULL, NULL )->lpInternalUnkVtbl;
     }
 
     hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret);
index 00a5266..ddcf68b 100644 (file)
@@ -614,7 +614,7 @@ IUnknown* create_pi( xmlNodePtr pi )
     This->lpVtbl = &dom_pi_vtbl;
     This->ref = 1;
 
-    node = create_basic_node( pi, (IUnknown*)&This->lpVtbl );
+    node = create_basic_node( pi, (IUnknown*)&This->lpVtbl, NULL );
     if(!node)
     {
         HeapFree(GetProcessHeap(), 0, This);
index 1cdd9f6..50e8b79 100644 (file)
@@ -366,7 +366,7 @@ static const tid_t queryresult_iface_tids[] = {
 };
 static dispex_static_data_t queryresult_dispex = {
     &queryresult_dispex_vtbl,
-    IXMLDOMNodeList_tid,
+    IXMLDOMSelection_tid,
     NULL,
     queryresult_iface_tids
 };
index 58de405..cb1966c 100644 (file)
@@ -781,7 +781,7 @@ IUnknown* create_text( xmlNodePtr text )
     This->lpVtbl = &domtext_vtbl;
     This->ref = 1;
 
-    node = create_basic_node( text, (IUnknown*)&This->lpVtbl );
+    node = create_basic_node( text, (IUnknown*)&This->lpVtbl, NULL );
     if(!node)
     {
         HeapFree(GetProcessHeap(), 0, This);