Sync with trunk r63174.
[reactos.git] / dll / win32 / urlmon / umon.c
index fbb00a4..132e97e 100644 (file)
 
 #include "urlmon_main.h"
 
-#include "winreg.h"
-#include "shlwapi.h"
-#include "hlink.h"
-#include "shellapi.h"
-
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
+#include <shellapi.h>
+#include <hlink.h>
 
 typedef struct {
-    const IMonikerVtbl *lpIMonikerVtbl;
+    IMoniker      IMoniker_iface;
+    IUriContainer IUriContainer_iface;
 
     LONG ref;
 
-    LPOLESTR URLName; /* URL string identified by this URLmoniker */
+    IUri *uri;
+    BSTR URLName;
 } URLMoniker;
 
-#define MONIKER_THIS(iface) DEFINE_THIS(URLMoniker, IMoniker, iface)
+static inline URLMoniker *impl_from_IMoniker(IMoniker *iface)
+{
+    return CONTAINING_RECORD(iface, URLMoniker, IMoniker_iface);
+}
 
 static HRESULT WINAPI URLMoniker_QueryInterface(IMoniker *iface, REFIID riid, void **ppv)
 {
-    URLMoniker *This = MONIKER_THIS(iface);
+    URLMoniker *This = impl_from_IMoniker(iface);
 
     if(!ppv)
        return E_INVALIDARG;
@@ -63,19 +62,22 @@ static HRESULT WINAPI URLMoniker_QueryInterface(IMoniker *iface, REFIID riid, vo
     }else if(IsEqualIID(&IID_IAsyncMoniker, riid)) {
         TRACE("(%p)->(IID_IAsyncMoniker %p)\n", This, ppv);
         *ppv = iface;
+    }else if(IsEqualIID(&IID_IUriContainer, riid)) {
+        TRACE("(%p)->(IID_IUriContainer %p)\n", This, ppv);
+        *ppv = &This->IUriContainer_iface;
     }else {
         WARN("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppv);
         *ppv = NULL;
         return E_NOINTERFACE;
     }
 
-    IMoniker_AddRef((IUnknown*)*ppv);
+    IUnknown_AddRef((IUnknown*)*ppv);
     return S_OK;
 }
 
 static ULONG WINAPI URLMoniker_AddRef(IMoniker *iface)
 {
-    URLMoniker *This = MONIKER_THIS(iface);
+    URLMoniker *This = impl_from_IMoniker(iface);
     ULONG refCount = InterlockedIncrement(&This->ref);
 
     TRACE("(%p) ref=%u\n",This, refCount);
@@ -85,13 +87,15 @@ static ULONG WINAPI URLMoniker_AddRef(IMoniker *iface)
 
 static ULONG WINAPI URLMoniker_Release(IMoniker *iface)
 {
-    URLMoniker *This = MONIKER_THIS(iface);
+    URLMoniker *This = impl_from_IMoniker(iface);
     ULONG refCount = InterlockedDecrement(&This->ref);
 
     TRACE("(%p) ref=%u\n",This, refCount);
 
     if (!refCount) {
-        heap_free(This->URLName);
+        if(This->uri)
+            IUri_Release(This->uri);
+        SysFreeString(This->URLName);
         heap_free(This);
 
         URLMON_UnlockModule();
@@ -102,7 +106,7 @@ static ULONG WINAPI URLMoniker_Release(IMoniker *iface)
 
 static HRESULT WINAPI URLMoniker_GetClassID(IMoniker *iface, CLSID *pClassID)
 {
-    URLMoniker *This = MONIKER_THIS(iface);
+    URLMoniker *This = impl_from_IMoniker(iface);
 
     TRACE("(%p,%p)\n", This, pClassID);
 
@@ -116,7 +120,7 @@ static HRESULT WINAPI URLMoniker_GetClassID(IMoniker *iface, CLSID *pClassID)
 
 static HRESULT WINAPI URLMoniker_IsDirty(IMoniker *iface)
 {
-    URLMoniker *This = MONIKER_THIS(iface);
+    URLMoniker *This = impl_from_IMoniker(iface);
 
     TRACE("(%p)\n",This);
 
@@ -128,10 +132,13 @@ static HRESULT WINAPI URLMoniker_IsDirty(IMoniker *iface)
 
 static HRESULT WINAPI URLMoniker_Load(IMoniker* iface,IStream* pStm)
 {
-    URLMoniker *This = MONIKER_THIS(iface);
-    HRESULT res;
+    URLMoniker *This = impl_from_IMoniker(iface);
+    WCHAR *new_uri_str;
+    IUri *new_uri;
+    BSTR new_url;
     ULONG size;
     ULONG got;
+    HRESULT hres;
 
     TRACE("(%p,%p)\n",This,pStm);
 
@@ -143,28 +150,42 @@ static HRESULT WINAPI URLMoniker_Load(IMoniker* iface,IStream* pStm)
      *  Writes a ULONG containing length of unicode string, followed
      *  by that many unicode characters
      */
-    res = IStream_Read(pStm, &size, sizeof(ULONG), &got);
-    if(SUCCEEDED(res)) {
-        if(got == sizeof(ULONG)) {
-            heap_free(This->URLName);
-            This->URLName = heap_alloc(size);
-            if(!This->URLName)
-                res = E_OUTOFMEMORY;
-            else {
-                res = IStream_Read(pStm, This->URLName, size, NULL);
-                This->URLName[size/sizeof(WCHAR) - 1] = 0;
-            }
-        }
-        else
-            res = E_FAIL;
+    hres = IStream_Read(pStm, &size, sizeof(ULONG), &got);
+    if(FAILED(hres))
+        return hres;
+    if(got != sizeof(ULONG))
+        return E_FAIL;
+
+    new_uri_str = heap_alloc(size+sizeof(WCHAR));
+    if(!new_uri_str)
+        return E_OUTOFMEMORY;
+
+    hres = IStream_Read(pStm, new_uri_str, size, NULL);
+    new_uri_str[size/sizeof(WCHAR)] = 0;
+    if(SUCCEEDED(hres))
+        hres = CreateUri(new_uri_str, 0, 0, &new_uri);
+    heap_free(new_uri_str);
+    if(FAILED(hres))
+        return hres;
+
+    hres = IUri_GetDisplayUri(new_uri, &new_url);
+    if(FAILED(hres)) {
+        IUri_Release(new_uri);
+        return hres;
     }
 
-    return res;
+    SysFreeString(This->URLName);
+    if(This->uri)
+        IUri_Release(This->uri);
+
+    This->uri = new_uri;
+    This->URLName = new_url;
+    return S_OK;
 }
 
 static HRESULT WINAPI URLMoniker_Save(IMoniker *iface, IStream* pStm, BOOL fClearDirty)
 {
-    URLMoniker *This = MONIKER_THIS(iface);
+    URLMoniker *This = impl_from_IMoniker(iface);
     HRESULT res;
     ULONG size;
 
@@ -173,7 +194,7 @@ static HRESULT WINAPI URLMoniker_Save(IMoniker *iface, IStream* pStm, BOOL fClea
     if(!pStm)
         return E_INVALIDARG;
 
-    size = (strlenW(This->URLName) + 1)*sizeof(WCHAR);
+    size = (SysStringLen(This->URLName) + 1)*sizeof(WCHAR);
     res=IStream_Write(pStm,&size,sizeof(ULONG),NULL);
     if(SUCCEEDED(res))
         res=IStream_Write(pStm,This->URLName,size,NULL);
@@ -184,70 +205,80 @@ static HRESULT WINAPI URLMoniker_Save(IMoniker *iface, IStream* pStm, BOOL fClea
 
 static HRESULT WINAPI URLMoniker_GetSizeMax(IMoniker* iface, ULARGE_INTEGER *pcbSize)
 {
-    URLMoniker *This = MONIKER_THIS(iface);
+    URLMoniker *This = impl_from_IMoniker(iface);
 
     TRACE("(%p,%p)\n",This,pcbSize);
 
     if(!pcbSize)
         return E_INVALIDARG;
 
-    pcbSize->QuadPart = sizeof(ULONG) + ((strlenW(This->URLName)+1) * sizeof(WCHAR));
+    pcbSize->QuadPart = sizeof(ULONG) + ((SysStringLen(This->URLName)+1) * sizeof(WCHAR));
     return S_OK;
 }
 
 static HRESULT WINAPI URLMoniker_BindToObject(IMoniker *iface, IBindCtx* pbc, IMoniker *pmkToLeft,
         REFIID riid, void **ppv)
 {
-    URLMoniker *This = MONIKER_THIS(iface);
+    URLMoniker *This = impl_from_IMoniker(iface);
     IRunningObjectTable *obj_tbl;
-    IUri *uri;
     HRESULT hres;
 
-    TRACE("(%p)->(%p,%p,%s,%p): stub\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppv);
+    TRACE("(%p)->(%p,%p,%s,%p)\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppv);
 
     hres = IBindCtx_GetRunningObjectTable(pbc, &obj_tbl);
     if(SUCCEEDED(hres)) {
-        FIXME("use running object table\n");
+        hres = IRunningObjectTable_IsRunning(obj_tbl, &This->IMoniker_iface);
+        if(hres == S_OK) {
+            IUnknown *unk = NULL;
+
+            TRACE("Found in running object table\n");
+
+            hres = IRunningObjectTable_GetObject(obj_tbl, &This->IMoniker_iface, &unk);
+            if(SUCCEEDED(hres)) {
+                hres = IUnknown_QueryInterface(unk, riid, ppv);
+                IUnknown_Release(unk);
+            }
+
+            IRunningObjectTable_Release(obj_tbl);
+            return hres;
+        }
+
         IRunningObjectTable_Release(obj_tbl);
     }
 
-    hres = CreateUri(This->URLName, Uri_CREATE_FILE_USE_DOS_PATH, 0, &uri);
-    if(FAILED(hres))
-        return hres;
-
-    hres = bind_to_object(iface, uri, pbc, riid, ppv);
+    if(!This->uri) {
+        *ppv = NULL;
+        return MK_E_SYNTAX;
+    }
 
-    IUri_Release(uri);
-    return hres;
+    return bind_to_object(&This->IMoniker_iface, This->uri, pbc, riid, ppv);
 }
 
 static HRESULT WINAPI URLMoniker_BindToStorage(IMoniker* iface, IBindCtx* pbc,
         IMoniker* pmkToLeft, REFIID riid, void **ppvObject)
 {
-    URLMoniker *This = MONIKER_THIS(iface);
-    IUri *uri;
-    HRESULT hres;
+    URLMoniker *This = impl_from_IMoniker(iface);
 
     TRACE("(%p)->(%p %p %s %p)\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppvObject);
 
+    if(ppvObject) *ppvObject = NULL;
+
+    if(!pbc || !ppvObject) return E_INVALIDARG;
+
     if(pmkToLeft)
         FIXME("Unsupported pmkToLeft\n");
 
-    hres = CreateUri(This->URLName, Uri_CREATE_FILE_USE_DOS_PATH, 0, &uri);
-    if(FAILED(hres))
-        return hres;
-
-    hres = bind_to_storage(uri, pbc, riid, ppvObject);
+    if(!This->uri)
+        return MK_E_SYNTAX;
 
-    IUri_Release(uri);
-    return hres;
+    return bind_to_storage(This->uri, pbc, riid, ppvObject);
 }
 
 static HRESULT WINAPI URLMoniker_Reduce(IMoniker *iface, IBindCtx *pbc,
         DWORD dwReduceHowFar, IMoniker **ppmkToLeft, IMoniker **ppmkReduced)
 {
-    URLMoniker *This = MONIKER_THIS(iface);
-    
+    URLMoniker *This = impl_from_IMoniker(iface);
+
     TRACE("(%p,%p,%d,%p,%p)\n", This, pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced);
 
     if(!ppmkReduced)
@@ -261,14 +292,14 @@ static HRESULT WINAPI URLMoniker_Reduce(IMoniker *iface, IBindCtx *pbc,
 static HRESULT WINAPI URLMoniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight,
         BOOL fOnlyIfNotGeneric, IMoniker **ppmkComposite)
 {
-    URLMoniker *This = MONIKER_THIS(iface);
+    URLMoniker *This = impl_from_IMoniker(iface);
     FIXME("(%p)->(%p,%d,%p): stub\n",This,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI URLMoniker_Enum(IMoniker *iface, BOOL fForward, IEnumMoniker **ppenumMoniker)
 {
-    URLMoniker *This = MONIKER_THIS(iface);
+    URLMoniker *This = impl_from_IMoniker(iface);
 
     TRACE("(%p,%d,%p)\n", This, fForward, ppenumMoniker);
 
@@ -282,7 +313,7 @@ static HRESULT WINAPI URLMoniker_Enum(IMoniker *iface, BOOL fForward, IEnumMonik
 
 static HRESULT WINAPI URLMoniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker)
 {
-    URLMoniker *This = MONIKER_THIS(iface);
+    URLMoniker *This = impl_from_IMoniker(iface);
     CLSID clsid;
     LPOLESTR urlPath;
     IBindCtx* bind;
@@ -309,14 +340,14 @@ static HRESULT WINAPI URLMoniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoni
         if(result == 0)
             res = S_OK;
     }
-    IUnknown_Release(bind);
+    IBindCtx_Release(bind);
     return res;
 }
 
 
 static HRESULT WINAPI URLMoniker_Hash(IMoniker *iface, DWORD *pdwHash)
 {
-    URLMoniker *This = MONIKER_THIS(iface);
+    URLMoniker *This = impl_from_IMoniker(iface);
     int  h = 0,i,skip,len;
     int  off = 0;
     LPOLESTR val;
@@ -347,7 +378,7 @@ static HRESULT WINAPI URLMoniker_Hash(IMoniker *iface, DWORD *pdwHash)
 static HRESULT WINAPI URLMoniker_IsRunning(IMoniker* iface, IBindCtx* pbc,
         IMoniker *pmkToLeft, IMoniker *pmkNewlyRunning)
 {
-    URLMoniker *This = MONIKER_THIS(iface);
+    URLMoniker *This = impl_from_IMoniker(iface);
     FIXME("(%p)->(%p,%p,%p): stub\n",This,pbc,pmkToLeft,pmkNewlyRunning);
     return E_NOTIMPL;
 }
@@ -355,28 +386,28 @@ static HRESULT WINAPI URLMoniker_IsRunning(IMoniker* iface, IBindCtx* pbc,
 static HRESULT WINAPI URLMoniker_GetTimeOfLastChange(IMoniker *iface,
         IBindCtx *pbc, IMoniker *pmkToLeft, FILETIME *pFileTime)
 {
-    URLMoniker *This = MONIKER_THIS(iface);
+    URLMoniker *This = impl_from_IMoniker(iface);
     FIXME("(%p)->(%p,%p,%p): stub\n", This, pbc, pmkToLeft, pFileTime);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI URLMoniker_Inverse(IMoniker *iface, IMoniker **ppmk)
 {
-    URLMoniker *This = MONIKER_THIS(iface);
+    URLMoniker *This = impl_from_IMoniker(iface);
     TRACE("(%p,%p)\n",This,ppmk);
     return MK_E_NOINVERSE;
 }
 
 static HRESULT WINAPI URLMoniker_CommonPrefixWith(IMoniker *iface, IMoniker *pmkOther, IMoniker **ppmkPrefix)
 {
-    URLMoniker *This = MONIKER_THIS(iface);
+    URLMoniker *This = impl_from_IMoniker(iface);
     FIXME("(%p)->(%p,%p): stub\n",This,pmkOther,ppmkPrefix);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI URLMoniker_RelativePathTo(IMoniker *iface, IMoniker *pmOther, IMoniker **ppmkRelPath)
 {
-    URLMoniker *This = MONIKER_THIS(iface);
+    URLMoniker *This = impl_from_IMoniker(iface);
     FIXME("(%p)->(%p,%p): stub\n",This,pmOther,ppmkRelPath);
     return E_NOTIMPL;
 }
@@ -384,7 +415,7 @@ static HRESULT WINAPI URLMoniker_RelativePathTo(IMoniker *iface, IMoniker *pmOth
 static HRESULT WINAPI URLMoniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
         LPOLESTR *ppszDisplayName)
 {
-    URLMoniker *This = MONIKER_THIS(iface);
+    URLMoniker *This = impl_from_IMoniker(iface);
     int len;
     
     TRACE("(%p,%p,%p,%p)\n", This, pbc, pmkToLeft, ppszDisplayName);
@@ -398,7 +429,7 @@ static HRESULT WINAPI URLMoniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc,
     /* FIXME: If this is a partial URL, try and get a URL moniker from SZ_URLCONTEXT in the bind context,
         then look at pmkToLeft to try and complete the URL
     */
-    len = lstrlenW(This->URLName)+1;
+    len = SysStringLen(This->URLName)+1;
     *ppszDisplayName = CoTaskMemAlloc(len*sizeof(WCHAR));
     if(!*ppszDisplayName)
         return E_OUTOFMEMORY;
@@ -409,14 +440,14 @@ static HRESULT WINAPI URLMoniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc,
 static HRESULT WINAPI URLMoniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
         LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut)
 {
-    URLMoniker *This = MONIKER_THIS(iface);
+    URLMoniker *This = impl_from_IMoniker(iface);
     FIXME("(%p)->(%p,%p,%p,%p,%p): stub\n",This,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI URLMoniker_IsSystemMoniker(IMoniker *iface, DWORD *pwdMksys)
 {
-    URLMoniker *This = MONIKER_THIS(iface);
+    URLMoniker *This = impl_from_IMoniker(iface);
 
     TRACE("(%p,%p)\n",This,pwdMksys);
 
@@ -454,60 +485,112 @@ static const IMonikerVtbl URLMonikerVtbl =
     URLMoniker_IsSystemMoniker
 };
 
-static URLMoniker *alloc_moniker(void)
+static inline URLMoniker *impl_from_IUriContainer(IUriContainer *iface)
 {
-    URLMoniker *ret;
+    return CONTAINING_RECORD(iface, URLMoniker, IUriContainer_iface);
+}
 
-    ret = heap_alloc(sizeof(URLMoniker));
-    if(!ret)
-        return NULL;
+static HRESULT WINAPI UriContainer_QueryInterface(IUriContainer *iface, REFIID riid, void **ppv)
+{
+    URLMoniker *This = impl_from_IUriContainer(iface);
+    return IMoniker_QueryInterface(&This->IMoniker_iface, riid, ppv);
+}
 
-    ret->lpIMonikerVtbl = &URLMonikerVtbl;
-    ret->ref = 1;
-    ret->URLName = NULL;
+static ULONG WINAPI UriContainer_AddRef(IUriContainer *iface)
+{
+    URLMoniker *This = impl_from_IUriContainer(iface);
+    return IMoniker_AddRef(&This->IMoniker_iface);
+}
 
-    return ret;
+static ULONG WINAPI UriContainer_Release(IUriContainer *iface)
+{
+    URLMoniker *This = impl_from_IUriContainer(iface);
+    return IMoniker_Release(&This->IMoniker_iface);
 }
 
-static HRESULT URLMoniker_Init(URLMoniker *This, LPCOLESTR lpszLeftURLName, LPCOLESTR lpszURLName)
+static HRESULT WINAPI UriContainer_GetIUri(IUriContainer *iface, IUri **ppIUri)
 {
-    HRESULT hres;
-    DWORD sizeStr = 0;
+    URLMoniker *This = impl_from_IUriContainer(iface);
 
-    TRACE("(%p,%s,%s)\n",This,debugstr_w(lpszLeftURLName),debugstr_w(lpszURLName));
+    TRACE("(%p)->(%p)\n", This, ppIUri);
 
-    This->URLName = heap_alloc(INTERNET_MAX_URL_LENGTH*sizeof(WCHAR));
+    if(!This->uri) {
+        *ppIUri = NULL;
+        return S_FALSE;
+    }
 
-    if(lpszLeftURLName)
-        hres = CoInternetCombineUrl(lpszLeftURLName, lpszURLName, URL_FILE_USE_PATHURL,
-                This->URLName, INTERNET_MAX_URL_LENGTH, &sizeStr, 0);
-    else
-        hres = CoInternetParseUrl(lpszURLName, PARSE_CANONICALIZE, URL_FILE_USE_PATHURL,
-                This->URLName, INTERNET_MAX_URL_LENGTH, &sizeStr, 0);
+    IUri_AddRef(This->uri);
+    *ppIUri = This->uri;
+    return S_OK;
+}
 
-    if(FAILED(hres)) {
-        heap_free(This->URLName);
-        return hres;
-    }
+static const IUriContainerVtbl UriContainerVtbl = {
+    UriContainer_QueryInterface,
+    UriContainer_AddRef,
+    UriContainer_Release,
+    UriContainer_GetIUri
+};
 
-    URLMON_LockModule();
+static HRESULT create_moniker(IUri *uri, URLMoniker **ret)
+{
+    URLMoniker *mon;
+    HRESULT hres;
 
-    if(sizeStr != INTERNET_MAX_URL_LENGTH)
-        This->URLName = heap_realloc(This->URLName, (sizeStr+1)*sizeof(WCHAR));
+    mon = heap_alloc(sizeof(*mon));
+    if(!mon)
+        return E_OUTOFMEMORY;
 
-    TRACE("URLName = %s\n", debugstr_w(This->URLName));
+    mon->IMoniker_iface.lpVtbl = &URLMonikerVtbl;
+    mon->IUriContainer_iface.lpVtbl = &UriContainerVtbl;
+    mon->ref = 1;
 
+    if(uri) {
+        /* FIXME: try to avoid it */
+        hres = IUri_GetDisplayUri(uri, &mon->URLName);
+        if(FAILED(hres)) {
+            heap_free(mon);
+            return hres;
+        }
+
+        IUri_AddRef(uri);
+        mon->uri = uri;
+    }else {
+        mon->URLName = NULL;
+        mon->uri = NULL;
+    }
+
+    URLMON_LockModule();
+    *ret = mon;
     return S_OK;
 }
 
 HRESULT StdURLMoniker_Construct(IUnknown *outer, void **ppv)
 {
+    URLMoniker *mon;
+    HRESULT hres;
+
     TRACE("(%p %p)\n", outer, ppv);
 
-    *ppv = alloc_moniker();
-    return *ppv ? S_OK : E_OUTOFMEMORY;
+    hres = create_moniker(NULL, &mon);
+    if(FAILED(hres))
+        return hres;
+
+    *ppv = &mon->IMoniker_iface;
+    return S_OK;
 }
 
+static const DWORD create_flags_map[3] = {
+    Uri_CREATE_FILE_USE_DOS_PATH,  /* URL_MK_LEGACY */
+    0,                             /* URL_MK_UNIFORM */
+    Uri_CREATE_NO_CANONICALIZE     /* URL_MK_NO_CANONICALIZE */
+};
+
+static const DWORD combine_flags_map[3] = {
+    URL_FILE_USE_PATHURL,  /* URL_MK_LEGACY */
+    0,                     /* URL_MK_UNIFORM */
+    URL_DONT_SIMPLIFY      /* URL_MK_NO_CANONICALIZE */
+};
+
 /***********************************************************************
  *           CreateURLMonikerEx (URLMON.@)
  *
@@ -526,9 +609,9 @@ HRESULT StdURLMoniker_Construct(IUnknown *outer, void **ppv)
  */
 HRESULT WINAPI CreateURLMonikerEx(IMoniker *pmkContext, LPCWSTR szURL, IMoniker **ppmk, DWORD dwFlags)
 {
+    IUri *uri, *base_uri = NULL;
     URLMoniker *obj;
     HRESULT hres;
-    LPOLESTR lefturl = NULL;
 
     TRACE("(%p, %s, %p, %08x)\n", pmkContext, debugstr_w(szURL), ppmk, dwFlags);
 
@@ -538,28 +621,91 @@ HRESULT WINAPI CreateURLMonikerEx(IMoniker *pmkContext, LPCWSTR szURL, IMoniker
     if (!szURL || !ppmk)
         return E_INVALIDARG;
 
-    if (dwFlags & URL_MK_UNIFORM) FIXME("ignoring flag URL_MK_UNIFORM\n");
+    if(dwFlags >= sizeof(create_flags_map)/sizeof(*create_flags_map)) {
+        FIXME("Unsupported flags %x\n", dwFlags);
+        return E_INVALIDARG;
+    }
+
+    if(pmkContext) {
+        IUriContainer *uri_container;
 
-    if(!(obj = alloc_moniker()))
-       return E_OUTOFMEMORY;
+        hres = IMoniker_QueryInterface(pmkContext, &IID_IUriContainer, (void**)&uri_container);
+        if(SUCCEEDED(hres)) {
+            hres = IUriContainer_GetIUri(uri_container, &base_uri);
+            IUriContainer_Release(uri_container);
+            if(FAILED(hres))
+                return hres;
+        }
+    }
+
+    if(base_uri) {
+        hres = CoInternetCombineUrlEx(base_uri, szURL, combine_flags_map[dwFlags], &uri, 0);
+        IUri_Release(base_uri);
+    }else {
+        hres = CreateUri(szURL, Uri_CREATE_ALLOW_RELATIVE|Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME|create_flags_map[dwFlags], 0, &uri);
+    }
+    if(FAILED(hres))
+        return hres;
+
+    hres = create_moniker(uri, &obj);
+    IUri_Release(uri);
+    if(FAILED(hres))
+       return hres;
+
+    *ppmk = &obj->IMoniker_iface;
+    return S_OK;
+}
+
+/***********************************************************************
+ *           CreateURLMonikerEx2 (URLMON.@)
+ */
+HRESULT WINAPI CreateURLMonikerEx2(IMoniker *pmkContext, IUri *pUri, IMoniker **ppmk, DWORD dwFlags)
+{
+    IUri *context_uri = NULL, *uri;
+    IUriContainer *uri_container;
+    URLMoniker *ret;
+    HRESULT hres;
+
+    TRACE("(%p %p %p %x)\n", pmkContext, pUri, ppmk, dwFlags);
+
+    if (ppmk)
+        *ppmk = NULL;
+
+    if (!pUri || !ppmk)
+        return E_INVALIDARG;
+
+    if(dwFlags >= sizeof(create_flags_map)/sizeof(*create_flags_map)) {
+        FIXME("Unsupported flags %x\n", dwFlags);
+        return E_INVALIDARG;
+    }
 
     if(pmkContext) {
-        IBindCtx* bind;
-        DWORD dwMksys = 0;
-        IMoniker_IsSystemMoniker(pmkContext, &dwMksys);
-        if(dwMksys == MKSYS_URLMONIKER && SUCCEEDED(CreateBindCtx(0, &bind))) {
-            IMoniker_GetDisplayName(pmkContext, bind, NULL, &lefturl);
-            TRACE("lefturl = %s\n", debugstr_w(lefturl));
-            IBindCtx_Release(bind);
+        hres = IMoniker_QueryInterface(pmkContext, &IID_IUriContainer, (void**)&uri_container);
+        if(SUCCEEDED(hres)) {
+            hres = IUriContainer_GetIUri(uri_container, &context_uri);
+            if(FAILED(hres))
+                context_uri = NULL;
+            IUriContainer_Release(uri_container);
         }
     }
-        
-    hres = URLMoniker_Init(obj, lefturl, szURL);
-    CoTaskMemFree(lefturl);
-    if(SUCCEEDED(hres))
-       hres = URLMoniker_QueryInterface((IMoniker*)obj, &IID_IMoniker, (void**)ppmk);
-    IMoniker_Release((IMoniker*)obj);
-    return hres;
+
+    if(context_uri) {
+        hres = CoInternetCombineIUri(context_uri, pUri, combine_flags_map[dwFlags], &uri, 0);
+        IUri_Release(context_uri);
+        if(FAILED(hres))
+            return hres;
+    }else {
+        uri = pUri;
+        IUri_AddRef(uri);
+    }
+
+    hres = create_moniker(uri, &ret);
+    IUri_Release(uri);
+    if(FAILED(hres))
+        return hres;
+
+    *ppmk = &ret->IMoniker_iface;
+    return S_OK;
 }
 
 /**********************************************************************
@@ -813,14 +959,3 @@ HRESULT WINAPI GetSoftwareUpdateInfo( LPCWSTR szDistUnit, LPSOFTDISTINFO psdi )
     FIXME("%s %p\n", debugstr_w(szDistUnit), psdi );
     return E_FAIL;
 }
-
-/***********************************************************************
- *           AsyncInstallDistributionUnit (URLMON.@)
- */
-HRESULT WINAPI AsyncInstallDistributionUnit( LPCWSTR szDistUnit, LPCWSTR szTYPE,
-                            LPCWSTR szExt, DWORD dwFileVersionMS, DWORD dwFileVersionLS,
-                            LPCWSTR szURL, IBindCtx *pbc, LPVOID pvReserved, DWORD flags )
-{
-    FIXME(": stub\n");
-    return E_NOTIMPL;
-}