|  | /* | 
|  | *    ITSS Moniker implementation | 
|  | * | 
|  | * Copyright 2004 Mike McCormack | 
|  | * | 
|  | *  Implementation of the infamous mk:@MSITStore moniker | 
|  | * | 
|  | * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  |  | 
|  | #include <stdarg.h> | 
|  | #include <stdio.h> | 
|  |  | 
|  | #define COBJMACROS | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "winuser.h" | 
|  | #include "winnls.h" | 
|  | #include "winreg.h" | 
|  | #include "ole2.h" | 
|  |  | 
|  | #include "itss.h" | 
|  | #include "uuids.h" | 
|  |  | 
|  | #include "wine/unicode.h" | 
|  | #include "wine/debug.h" | 
|  |  | 
|  | #include "itsstor.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(itss); | 
|  |  | 
|  | extern LONG dll_count; | 
|  |  | 
|  | /*****************************************************************************/ | 
|  |  | 
|  | typedef struct { | 
|  | const IMonikerVtbl *vtbl_ITS_IMoniker; | 
|  | LONG ref; | 
|  | LPWSTR szHtml; | 
|  | WCHAR szFile[1]; | 
|  | } ITS_IMonikerImpl; | 
|  |  | 
|  | /*** IUnknown methods ***/ | 
|  | static HRESULT WINAPI ITS_IMonikerImpl_QueryInterface( | 
|  | IMoniker* iface, | 
|  | REFIID riid, | 
|  | void** ppvObject) | 
|  | { | 
|  | ITS_IMonikerImpl *This = (ITS_IMonikerImpl *)iface; | 
|  |  | 
|  | if (IsEqualGUID(riid, &IID_IUnknown) | 
|  | || IsEqualGUID(riid, &IID_IParseDisplayName)) | 
|  | { | 
|  | IClassFactory_AddRef(iface); | 
|  | *ppvObject = This; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject); | 
|  | return E_NOINTERFACE; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI ITS_IMonikerImpl_AddRef( | 
|  | IMoniker* iface) | 
|  | { | 
|  | ITS_IMonikerImpl *This = (ITS_IMonikerImpl *)iface; | 
|  | TRACE("%p\n", This); | 
|  | return InterlockedIncrement(&This->ref); | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI ITS_IMonikerImpl_Release( | 
|  | IMoniker* iface) | 
|  | { | 
|  | ITS_IMonikerImpl *This = (ITS_IMonikerImpl *)iface; | 
|  | ULONG ref = InterlockedDecrement(&This->ref); | 
|  |  | 
|  | if (ref == 0) { | 
|  | HeapFree(GetProcessHeap(), 0, This); | 
|  | InterlockedDecrement(&dll_count); | 
|  | } | 
|  |  | 
|  | return ref; | 
|  | } | 
|  |  | 
|  | /*** IPersist methods ***/ | 
|  | static HRESULT WINAPI ITS_IMonikerImpl_GetClassID( | 
|  | IMoniker* iface, | 
|  | CLSID* pClassID) | 
|  | { | 
|  | ITS_IMonikerImpl *This = (ITS_IMonikerImpl *)iface; | 
|  |  | 
|  | TRACE("%p %p\n", This, pClassID); | 
|  | memcpy( pClassID, &CLSID_ITStorage, sizeof (CLSID) ); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /*** IPersistStream methods ***/ | 
|  | static HRESULT WINAPI ITS_IMonikerImpl_IsDirty( | 
|  | IMoniker* iface) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITS_IMonikerImpl_Load( | 
|  | IMoniker* iface, | 
|  | IStream* pStm) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITS_IMonikerImpl_Save( | 
|  | IMoniker* iface, | 
|  | IStream* pStm, | 
|  | BOOL fClearDirty) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITS_IMonikerImpl_GetSizeMax( | 
|  | IMoniker* iface, | 
|  | ULARGE_INTEGER* pcbSize) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | /*** IMoniker methods ***/ | 
|  | static HRESULT WINAPI ITS_IMonikerImpl_BindToObject( | 
|  | IMoniker* iface, | 
|  | IBindCtx* pbc, | 
|  | IMoniker* pmkToLeft, | 
|  | REFIID riidResult, | 
|  | void** ppvResult) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITS_IMonikerImpl_BindToStorage( | 
|  | IMoniker* iface, | 
|  | IBindCtx* pbc, | 
|  | IMoniker* pmkToLeft, | 
|  | REFIID riid, | 
|  | void** ppvObj) | 
|  | { | 
|  | ITS_IMonikerImpl *This = (ITS_IMonikerImpl *)iface; | 
|  | DWORD grfMode = STGM_SIMPLE | STGM_READ | STGM_SHARE_EXCLUSIVE; | 
|  | HRESULT r; | 
|  | IStorage *stg = NULL; | 
|  |  | 
|  | TRACE("%p %p %p %s %p\n", This, | 
|  | pbc, pmkToLeft, debugstr_guid(riid), ppvObj); | 
|  |  | 
|  | r = ITSS_StgOpenStorage( This->szFile, NULL, grfMode, 0, 0, &stg ); | 
|  | if( r == S_OK ) | 
|  | { | 
|  | TRACE("Opened storage %s\n", debugstr_w( This->szFile ) ); | 
|  | if (IsEqualGUID(riid, &IID_IStream)) | 
|  | r = IStorage_OpenStream( stg, This->szHtml, | 
|  | NULL, grfMode, 0, (IStream**)ppvObj ); | 
|  | else if (IsEqualGUID(riid, &IID_IStorage)) | 
|  | r = IStorage_OpenStorage( stg, This->szHtml, | 
|  | NULL, grfMode, NULL, 0, (IStorage**)ppvObj ); | 
|  | else | 
|  | r = STG_E_ACCESSDENIED; | 
|  | IStorage_Release( stg ); | 
|  | } | 
|  |  | 
|  | return r; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITS_IMonikerImpl_Reduce( | 
|  | IMoniker* iface, | 
|  | IBindCtx* pbc, | 
|  | DWORD dwReduceHowFar, | 
|  | IMoniker** ppmkToLeft, | 
|  | IMoniker** ppmkReduced) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITS_IMonikerImpl_ComposeWith( | 
|  | IMoniker* iface, | 
|  | IMoniker* pmkRight, | 
|  | BOOL fOnlyIfNotGeneric, | 
|  | IMoniker** ppmkComposite) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITS_IMonikerImpl_Enum( | 
|  | IMoniker* iface, | 
|  | BOOL fForward, | 
|  | IEnumMoniker** ppenumMoniker) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITS_IMonikerImpl_IsEqual( | 
|  | IMoniker* iface, | 
|  | IMoniker* pmkOtherMoniker) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITS_IMonikerImpl_Hash( | 
|  | IMoniker* iface, | 
|  | DWORD* pdwHash) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITS_IMonikerImpl_IsRunning( | 
|  | IMoniker* iface, | 
|  | IBindCtx* pbc, | 
|  | IMoniker* pmkToLeft, | 
|  | IMoniker* pmkNewlyRunning) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITS_IMonikerImpl_GetTimeOfLastChange( | 
|  | IMoniker* iface, | 
|  | IBindCtx* pbc, | 
|  | IMoniker* pmkToLeft, | 
|  | FILETIME* pFileTime) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITS_IMonikerImpl_Inverse( | 
|  | IMoniker* iface, | 
|  | IMoniker** ppmk) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITS_IMonikerImpl_CommonPrefixWith( | 
|  | IMoniker* iface, | 
|  | IMoniker* pmkOther, | 
|  | IMoniker** ppmkPrefix) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITS_IMonikerImpl_RelativePathTo( | 
|  | IMoniker* iface, | 
|  | IMoniker* pmkOther, | 
|  | IMoniker** ppmkRelPath) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITS_IMonikerImpl_GetDisplayName( | 
|  | IMoniker* iface, | 
|  | IBindCtx* pbc, | 
|  | IMoniker* pmkToLeft, | 
|  | LPOLESTR* ppszDisplayName) | 
|  | { | 
|  | ITS_IMonikerImpl *This = (ITS_IMonikerImpl *)iface; | 
|  | static const WCHAR szFormat[] = { | 
|  | 'm','s','-','i','t','s',':','%','s',':',':','%','s',0 }; | 
|  | DWORD len = sizeof szFormat / sizeof(WCHAR); | 
|  | LPWSTR str; | 
|  |  | 
|  | TRACE("%p %p %p %p\n", iface, pbc, pmkToLeft, ppszDisplayName); | 
|  |  | 
|  | len = strlenW( This->szFile ) + strlenW( This->szHtml ); | 
|  | str = CoTaskMemAlloc( len*sizeof(WCHAR) ); | 
|  | sprintfW( str, szFormat, This->szFile, This->szHtml ); | 
|  |  | 
|  | *ppszDisplayName = str; | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITS_IMonikerImpl_ParseDisplayName( | 
|  | IMoniker* iface, | 
|  | IBindCtx* pbc, | 
|  | IMoniker* pmkToLeft, | 
|  | LPOLESTR pszDisplayName, | 
|  | ULONG* pchEaten, | 
|  | IMoniker** ppmkOut) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITS_IMonikerImpl_IsSystemMoniker( | 
|  | IMoniker* iface, | 
|  | DWORD* pdwMksys) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static const IMonikerVtbl ITS_IMonikerImpl_Vtbl = | 
|  | { | 
|  | ITS_IMonikerImpl_QueryInterface, | 
|  | ITS_IMonikerImpl_AddRef, | 
|  | ITS_IMonikerImpl_Release, | 
|  | ITS_IMonikerImpl_GetClassID, | 
|  | ITS_IMonikerImpl_IsDirty, | 
|  | ITS_IMonikerImpl_Load, | 
|  | ITS_IMonikerImpl_Save, | 
|  | ITS_IMonikerImpl_GetSizeMax, | 
|  | ITS_IMonikerImpl_BindToObject, | 
|  | ITS_IMonikerImpl_BindToStorage, | 
|  | ITS_IMonikerImpl_Reduce, | 
|  | ITS_IMonikerImpl_ComposeWith, | 
|  | ITS_IMonikerImpl_Enum, | 
|  | ITS_IMonikerImpl_IsEqual, | 
|  | ITS_IMonikerImpl_Hash, | 
|  | ITS_IMonikerImpl_IsRunning, | 
|  | ITS_IMonikerImpl_GetTimeOfLastChange, | 
|  | ITS_IMonikerImpl_Inverse, | 
|  | ITS_IMonikerImpl_CommonPrefixWith, | 
|  | ITS_IMonikerImpl_RelativePathTo, | 
|  | ITS_IMonikerImpl_GetDisplayName, | 
|  | ITS_IMonikerImpl_ParseDisplayName, | 
|  | ITS_IMonikerImpl_IsSystemMoniker | 
|  | }; | 
|  |  | 
|  | static HRESULT ITS_IMoniker_create( IMoniker **ppObj, LPWSTR name, DWORD n ) | 
|  | { | 
|  | ITS_IMonikerImpl *itsmon; | 
|  | DWORD sz; | 
|  |  | 
|  | /* szFile[1] has space for one character already */ | 
|  | sz = sizeof(ITS_IMonikerImpl) + strlenW( name )*sizeof(WCHAR); | 
|  |  | 
|  | itsmon = HeapAlloc( GetProcessHeap(), 0, sz ); | 
|  | itsmon->vtbl_ITS_IMoniker = &ITS_IMonikerImpl_Vtbl; | 
|  | itsmon->ref = 1; | 
|  | strcpyW( itsmon->szFile, name ); | 
|  | itsmon->szHtml = &itsmon->szFile[n]; | 
|  |  | 
|  | while( *itsmon->szHtml == ':' ) | 
|  | *itsmon->szHtml++ = 0; | 
|  |  | 
|  | TRACE("-> %p %s %s\n", itsmon, | 
|  | debugstr_w(itsmon->szFile), debugstr_w(itsmon->szHtml) ); | 
|  | *ppObj = (IMoniker*) itsmon; | 
|  | InterlockedIncrement(&dll_count); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /*****************************************************************************/ | 
|  |  | 
|  | typedef struct { | 
|  | const IParseDisplayNameVtbl *vtbl_ITS_IParseDisplayName; | 
|  | LONG ref; | 
|  | } ITS_IParseDisplayNameImpl; | 
|  |  | 
|  | static HRESULT WINAPI ITS_IParseDisplayNameImpl_QueryInterface( | 
|  | IParseDisplayName* iface, | 
|  | REFIID riid, | 
|  | void** ppvObject) | 
|  | { | 
|  | ITS_IParseDisplayNameImpl *This = (ITS_IParseDisplayNameImpl *)iface; | 
|  |  | 
|  | if (IsEqualGUID(riid, &IID_IUnknown) | 
|  | || IsEqualGUID(riid, &IID_IParseDisplayName)) | 
|  | { | 
|  | IClassFactory_AddRef(iface); | 
|  | *ppvObject = This; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject); | 
|  | return E_NOINTERFACE; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI ITS_IParseDisplayNameImpl_AddRef( | 
|  | IParseDisplayName* iface) | 
|  | { | 
|  | ITS_IParseDisplayNameImpl *This = (ITS_IParseDisplayNameImpl *)iface; | 
|  | TRACE("%p\n", This); | 
|  | return InterlockedIncrement(&This->ref); | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI ITS_IParseDisplayNameImpl_Release( | 
|  | IParseDisplayName* iface) | 
|  | { | 
|  | ITS_IParseDisplayNameImpl *This = (ITS_IParseDisplayNameImpl *)iface; | 
|  | ULONG ref = InterlockedDecrement(&This->ref); | 
|  |  | 
|  | if (ref == 0) { | 
|  | HeapFree(GetProcessHeap(), 0, This); | 
|  | InterlockedDecrement(&dll_count); | 
|  | } | 
|  |  | 
|  | return ref; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ITS_IParseDisplayNameImpl_ParseDisplayName( | 
|  | IParseDisplayName *iface, | 
|  | IBindCtx * pbc, | 
|  | LPOLESTR pszDisplayName, | 
|  | ULONG * pchEaten, | 
|  | IMoniker ** ppmkOut) | 
|  | { | 
|  | static const WCHAR szPrefix[] = { | 
|  | '@','M','S','I','T','S','t','o','r','e',':',0 }; | 
|  | const DWORD prefix_len = (sizeof szPrefix/sizeof szPrefix[0])-1; | 
|  | DWORD n; | 
|  |  | 
|  | ITS_IParseDisplayNameImpl *This = (ITS_IParseDisplayNameImpl *)iface; | 
|  |  | 
|  | TRACE("%p %s %p %p\n", This, | 
|  | debugstr_w( pszDisplayName ), pchEaten, ppmkOut ); | 
|  |  | 
|  | if( strncmpW( pszDisplayName, szPrefix, prefix_len ) ) | 
|  | return MK_E_SYNTAX; | 
|  |  | 
|  | /* search backwards for a double colon */ | 
|  | for( n = strlenW( pszDisplayName ) - 3; prefix_len <= n; n-- ) | 
|  | if( ( pszDisplayName[n] == ':' ) && ( pszDisplayName[n+1] == ':' ) ) | 
|  | break; | 
|  |  | 
|  | if( n < prefix_len ) | 
|  | return MK_E_SYNTAX; | 
|  |  | 
|  | if( !pszDisplayName[n+2] ) | 
|  | return MK_E_SYNTAX; | 
|  |  | 
|  | *pchEaten = strlenW( pszDisplayName ) - n - 3; | 
|  |  | 
|  | return ITS_IMoniker_create( ppmkOut, | 
|  | &pszDisplayName[prefix_len], n-prefix_len ); | 
|  | } | 
|  |  | 
|  | static const IParseDisplayNameVtbl ITS_IParseDisplayNameImpl_Vtbl = | 
|  | { | 
|  | ITS_IParseDisplayNameImpl_QueryInterface, | 
|  | ITS_IParseDisplayNameImpl_AddRef, | 
|  | ITS_IParseDisplayNameImpl_Release, | 
|  | ITS_IParseDisplayNameImpl_ParseDisplayName | 
|  | }; | 
|  |  | 
|  | HRESULT ITS_IParseDisplayName_create(IUnknown *pUnkOuter, LPVOID *ppObj) | 
|  | { | 
|  | ITS_IParseDisplayNameImpl *its; | 
|  |  | 
|  | if( pUnkOuter ) | 
|  | return CLASS_E_NOAGGREGATION; | 
|  |  | 
|  | its = HeapAlloc( GetProcessHeap(), 0, sizeof(ITS_IParseDisplayNameImpl) ); | 
|  | its->vtbl_ITS_IParseDisplayName = &ITS_IParseDisplayNameImpl_Vtbl; | 
|  | its->ref = 1; | 
|  |  | 
|  | TRACE("-> %p\n", its); | 
|  | *ppObj = (LPVOID) its; | 
|  | InterlockedIncrement(&dll_count); | 
|  |  | 
|  | return S_OK; | 
|  | } |