Properly cope with get_message being called recursively while
[wine] / dlls / itss / moniker.c
1 /*
2  *    ITSS Moniker implementation
3  *
4  * Copyright 2004 Mike McCormack
5  *
6  *  Implementation of the infamous mk:@MSITStore moniker
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24
25 #include <stdarg.h>
26 #include <stdio.h>
27
28 #define COBJMACROS
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "winnls.h"
34 #include "winreg.h"
35 #include "ole2.h"
36
37 #include "itss.h"
38 #include "uuids.h"
39
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
42
43 #include "itsstor.h"
44
45 WINE_DEFAULT_DEBUG_CHANNEL(itss);
46
47 extern ULONG dll_count;
48
49 /*****************************************************************************/
50
51 typedef struct {
52     IMonikerVtbl *vtbl_ITS_IMoniker;
53     DWORD ref;
54     LPWSTR szHtml;
55     WCHAR szFile[1];
56 } ITS_IMonikerImpl;
57
58 /*** IUnknown methods ***/
59 static HRESULT WINAPI ITS_IMonikerImpl_QueryInterface(
60     IMoniker* iface,
61     REFIID riid,
62     void** ppvObject)
63 {
64     ITS_IMonikerImpl *This = (ITS_IMonikerImpl *)iface;
65
66     if (IsEqualGUID(riid, &IID_IUnknown)
67         || IsEqualGUID(riid, &IID_IParseDisplayName))
68     {
69         IClassFactory_AddRef(iface);
70         *ppvObject = This;
71         return S_OK;
72     }
73
74     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
75     return E_NOINTERFACE;
76 }
77
78 static ULONG WINAPI ITS_IMonikerImpl_AddRef(
79     IMoniker* iface)
80 {
81     ITS_IMonikerImpl *This = (ITS_IMonikerImpl *)iface;
82     TRACE("%p\n", This);
83     return InterlockedIncrement(&This->ref);
84 }
85
86 static ULONG WINAPI ITS_IMonikerImpl_Release(
87     IMoniker* iface)
88 {
89     ITS_IMonikerImpl *This = (ITS_IMonikerImpl *)iface;
90     ULONG ref = InterlockedDecrement(&This->ref);
91
92     if (ref == 0) {
93         HeapFree(GetProcessHeap(), 0, This);
94         InterlockedDecrement(&dll_count);
95     }
96
97     return ref;
98 }
99
100 /*** IPersist methods ***/
101 static HRESULT WINAPI ITS_IMonikerImpl_GetClassID(
102     IMoniker* iface,
103     CLSID* pClassID)
104 {
105     ITS_IMonikerImpl *This = (ITS_IMonikerImpl *)iface;
106
107     TRACE("%p %p\n", This, pClassID);
108     memcpy( pClassID, &CLSID_ITStorage, sizeof (CLSID) );
109     return S_OK;
110 }
111
112 /*** IPersistStream methods ***/
113 static HRESULT WINAPI ITS_IMonikerImpl_IsDirty(
114     IMoniker* iface)
115 {
116     FIXME("\n");
117     return E_NOTIMPL;
118 }
119
120 static HRESULT WINAPI ITS_IMonikerImpl_Load(
121     IMoniker* iface,
122     IStream* pStm)
123 {
124     FIXME("\n");
125     return E_NOTIMPL;
126 }
127
128 static HRESULT WINAPI ITS_IMonikerImpl_Save(
129     IMoniker* iface,
130     IStream* pStm,
131     BOOL fClearDirty)
132 {
133     FIXME("\n");
134     return E_NOTIMPL;
135 }
136
137 static HRESULT WINAPI ITS_IMonikerImpl_GetSizeMax(
138     IMoniker* iface,
139     ULARGE_INTEGER* pcbSize)
140 {
141     FIXME("\n");
142     return E_NOTIMPL;
143 }
144
145 /*** IMoniker methods ***/
146 static HRESULT WINAPI ITS_IMonikerImpl_BindToObject(
147     IMoniker* iface,
148     IBindCtx* pbc,
149     IMoniker* pmkToLeft,
150     REFIID riidResult,
151     void** ppvResult)
152 {
153     FIXME("\n");
154     return E_NOTIMPL;
155 }
156
157 static HRESULT WINAPI ITS_IMonikerImpl_BindToStorage(
158     IMoniker* iface,
159     IBindCtx* pbc,
160     IMoniker* pmkToLeft,
161     REFIID riid,
162     void** ppvObj)
163 {
164     ITS_IMonikerImpl *This = (ITS_IMonikerImpl *)iface;
165     DWORD grfMode = STGM_SIMPLE | STGM_READ | STGM_SHARE_EXCLUSIVE;
166     HRESULT r;
167     IStorage *stg = NULL;
168
169     TRACE("%p %p %p %s %p\n", This,
170            pbc, pmkToLeft, debugstr_guid(riid), ppvObj);
171
172     r = ITSS_StgOpenStorage( This->szFile, NULL, grfMode, 0, 0, &stg );
173     if( r == S_OK )
174     {
175         TRACE("Opened storage %s\n", debugstr_w( This->szFile ) );
176         if (IsEqualGUID(riid, &IID_IStream))
177             r = IStorage_OpenStream( stg, This->szHtml,
178                        NULL, grfMode, 0, (IStream**)ppvObj );
179         else if (IsEqualGUID(riid, &IID_IStorage))
180             r = IStorage_OpenStorage( stg, This->szHtml,
181                        NULL, grfMode, NULL, 0, (IStorage**)ppvObj );
182         else
183             r = STG_E_ACCESSDENIED;
184         IStorage_Release( stg );
185     }
186
187     return r;
188 }
189
190 static HRESULT WINAPI ITS_IMonikerImpl_Reduce(
191     IMoniker* iface,
192     IBindCtx* pbc,
193     DWORD dwReduceHowFar,
194     IMoniker** ppmkToLeft,
195     IMoniker** ppmkReduced)
196 {
197     FIXME("\n");
198     return E_NOTIMPL;
199 }
200
201 static HRESULT WINAPI ITS_IMonikerImpl_ComposeWith(
202     IMoniker* iface,
203     IMoniker* pmkRight,
204     BOOL fOnlyIfNotGeneric,
205     IMoniker** ppmkComposite)
206 {
207     FIXME("\n");
208     return E_NOTIMPL;
209 }
210
211 static HRESULT WINAPI ITS_IMonikerImpl_Enum(
212     IMoniker* iface,
213     BOOL fForward,
214     IEnumMoniker** ppenumMoniker)
215 {
216     FIXME("\n");
217     return E_NOTIMPL;
218 }
219
220 static HRESULT WINAPI ITS_IMonikerImpl_IsEqual(
221     IMoniker* iface,
222     IMoniker* pmkOtherMoniker)
223 {
224     FIXME("\n");
225     return E_NOTIMPL;
226 }
227
228 static HRESULT WINAPI ITS_IMonikerImpl_Hash(
229     IMoniker* iface,
230     DWORD* pdwHash)
231 {
232     FIXME("\n");
233     return E_NOTIMPL;
234 }
235
236 static HRESULT WINAPI ITS_IMonikerImpl_IsRunning(
237     IMoniker* iface,
238     IBindCtx* pbc,
239     IMoniker* pmkToLeft,
240     IMoniker* pmkNewlyRunning)
241 {
242     FIXME("\n");
243     return E_NOTIMPL;
244 }
245
246 static HRESULT WINAPI ITS_IMonikerImpl_GetTimeOfLastChange(
247     IMoniker* iface,
248     IBindCtx* pbc,
249     IMoniker* pmkToLeft,
250     FILETIME* pFileTime)
251 {
252     FIXME("\n");
253     return E_NOTIMPL;
254 }
255
256 static HRESULT WINAPI ITS_IMonikerImpl_Inverse(
257     IMoniker* iface,
258     IMoniker** ppmk)
259 {
260     FIXME("\n");
261     return E_NOTIMPL;
262 }
263
264 static HRESULT WINAPI ITS_IMonikerImpl_CommonPrefixWith(
265     IMoniker* iface,
266     IMoniker* pmkOther,
267     IMoniker** ppmkPrefix)
268 {
269     FIXME("\n");
270     return E_NOTIMPL;
271 }
272
273 static HRESULT WINAPI ITS_IMonikerImpl_RelativePathTo(
274     IMoniker* iface,
275     IMoniker* pmkOther,
276     IMoniker** ppmkRelPath)
277 {
278     FIXME("\n");
279     return E_NOTIMPL;
280 }
281
282 static HRESULT WINAPI ITS_IMonikerImpl_GetDisplayName(
283     IMoniker* iface,
284     IBindCtx* pbc,
285     IMoniker* pmkToLeft,
286     LPOLESTR* ppszDisplayName)
287 {
288     ITS_IMonikerImpl *This = (ITS_IMonikerImpl *)iface;
289     static const WCHAR szFormat[] = {
290         'm','s','-','i','t','s',':','%','s',':',':','%','s',0 };
291     DWORD len = sizeof szFormat / sizeof(WCHAR);
292     LPWSTR str;
293
294     TRACE("%p %p %p %p\n", iface, pbc, pmkToLeft, ppszDisplayName);
295
296     len = strlenW( This->szFile ) + strlenW( This->szHtml );
297     str = CoTaskMemAlloc( len*sizeof(WCHAR) );
298     sprintfW( str, szFormat, This->szFile, This->szHtml );
299
300     *ppszDisplayName = str;
301     
302     return S_OK;
303 }
304
305 static HRESULT WINAPI ITS_IMonikerImpl_ParseDisplayName(
306     IMoniker* iface,
307     IBindCtx* pbc,
308     IMoniker* pmkToLeft,
309     LPOLESTR pszDisplayName,
310     ULONG* pchEaten,
311     IMoniker** ppmkOut)
312 {
313     FIXME("\n");
314     return E_NOTIMPL;
315 }
316
317 static HRESULT WINAPI ITS_IMonikerImpl_IsSystemMoniker(
318     IMoniker* iface,
319     DWORD* pdwMksys)
320 {
321     FIXME("\n");
322     return E_NOTIMPL;
323 }
324
325 static IMonikerVtbl ITS_IMonikerImpl_Vtbl =
326 {
327     ITS_IMonikerImpl_QueryInterface,
328     ITS_IMonikerImpl_AddRef,
329     ITS_IMonikerImpl_Release,
330     ITS_IMonikerImpl_GetClassID,
331     ITS_IMonikerImpl_IsDirty,
332     ITS_IMonikerImpl_Load,
333     ITS_IMonikerImpl_Save,
334     ITS_IMonikerImpl_GetSizeMax,
335     ITS_IMonikerImpl_BindToObject,
336     ITS_IMonikerImpl_BindToStorage,
337     ITS_IMonikerImpl_Reduce,
338     ITS_IMonikerImpl_ComposeWith,
339     ITS_IMonikerImpl_Enum,
340     ITS_IMonikerImpl_IsEqual,
341     ITS_IMonikerImpl_Hash,
342     ITS_IMonikerImpl_IsRunning,
343     ITS_IMonikerImpl_GetTimeOfLastChange,
344     ITS_IMonikerImpl_Inverse,
345     ITS_IMonikerImpl_CommonPrefixWith,
346     ITS_IMonikerImpl_RelativePathTo,
347     ITS_IMonikerImpl_GetDisplayName,
348     ITS_IMonikerImpl_ParseDisplayName,
349     ITS_IMonikerImpl_IsSystemMoniker
350 };
351
352 static HRESULT ITS_IMoniker_create( IMoniker **ppObj, LPWSTR name, DWORD n )
353 {
354     ITS_IMonikerImpl *itsmon;
355     DWORD sz;
356
357     /* szFile[1] has space for one character already */
358     sz = sizeof(ITS_IMonikerImpl) + strlenW( name )*sizeof(WCHAR);
359
360     itsmon = HeapAlloc( GetProcessHeap(), 0, sz );
361     itsmon->vtbl_ITS_IMoniker = &ITS_IMonikerImpl_Vtbl;
362     itsmon->ref = 1;
363     strcpyW( itsmon->szFile, name );
364     itsmon->szHtml = &itsmon->szFile[n];
365
366     while( *itsmon->szHtml == ':' )
367         *itsmon->szHtml++ = 0;
368
369     TRACE("-> %p %s %s\n", itsmon,
370           debugstr_w(itsmon->szFile), debugstr_w(itsmon->szHtml) );
371     *ppObj = (IMoniker*) itsmon;
372     InterlockedIncrement(&dll_count);
373
374     return S_OK;
375 }
376
377 /*****************************************************************************/
378
379 typedef struct {
380     IParseDisplayNameVtbl *vtbl_ITS_IParseDisplayName;
381     DWORD ref;
382 } ITS_IParseDisplayNameImpl;
383
384 static HRESULT WINAPI ITS_IParseDisplayNameImpl_QueryInterface(
385     IParseDisplayName* iface,
386     REFIID riid,
387     void** ppvObject)
388 {
389     ITS_IParseDisplayNameImpl *This = (ITS_IParseDisplayNameImpl *)iface;
390
391     if (IsEqualGUID(riid, &IID_IUnknown)
392         || IsEqualGUID(riid, &IID_IParseDisplayName))
393     {
394         IClassFactory_AddRef(iface);
395         *ppvObject = This;
396         return S_OK;
397     }
398
399     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
400     return E_NOINTERFACE;
401 }
402
403 static ULONG WINAPI ITS_IParseDisplayNameImpl_AddRef(
404     IParseDisplayName* iface)
405 {
406     ITS_IParseDisplayNameImpl *This = (ITS_IParseDisplayNameImpl *)iface;
407     TRACE("%p\n", This);
408     return InterlockedIncrement(&This->ref);
409 }
410
411 static ULONG WINAPI ITS_IParseDisplayNameImpl_Release(
412     IParseDisplayName* iface)
413 {
414     ITS_IParseDisplayNameImpl *This = (ITS_IParseDisplayNameImpl *)iface;
415     ULONG ref = InterlockedDecrement(&This->ref);
416
417     if (ref == 0) {
418         HeapFree(GetProcessHeap(), 0, This);
419         InterlockedDecrement(&dll_count);
420     }
421
422     return ref;
423 }
424
425 static HRESULT WINAPI ITS_IParseDisplayNameImpl_ParseDisplayName(
426     IParseDisplayName *iface,
427     IBindCtx * pbc,
428     LPOLESTR pszDisplayName, 
429     ULONG * pchEaten,
430     IMoniker ** ppmkOut)
431 {
432     static const WCHAR szPrefix[] = { 
433         '@','M','S','I','T','S','t','o','r','e',':',0 };
434     const DWORD prefix_len = (sizeof szPrefix/sizeof szPrefix[0])-1;
435     DWORD n;
436
437     ITS_IParseDisplayNameImpl *This = (ITS_IParseDisplayNameImpl *)iface;
438
439     TRACE("%p %s %p %p\n", This,
440           debugstr_w( pszDisplayName ), pchEaten, ppmkOut );
441
442     if( strncmpW( pszDisplayName, szPrefix, prefix_len ) )
443         return MK_E_SYNTAX;
444
445     /* search backwards for a double colon */
446     for( n = strlenW( pszDisplayName ) - 3; prefix_len <= n; n-- )
447         if( ( pszDisplayName[n] == ':' ) && ( pszDisplayName[n+1] == ':' ) )
448             break;
449
450     if( n < prefix_len )
451         return MK_E_SYNTAX;
452
453     if( !pszDisplayName[n+2] )
454         return MK_E_SYNTAX;
455
456     *pchEaten = strlenW( pszDisplayName ) - n - 3;
457
458     return ITS_IMoniker_create( ppmkOut,
459               &pszDisplayName[prefix_len], n-prefix_len );
460 }
461
462 static IParseDisplayNameVtbl ITS_IParseDisplayNameImpl_Vtbl =
463 {
464     ITS_IParseDisplayNameImpl_QueryInterface,
465     ITS_IParseDisplayNameImpl_AddRef,
466     ITS_IParseDisplayNameImpl_Release,
467     ITS_IParseDisplayNameImpl_ParseDisplayName
468 };
469  
470 HRESULT ITS_IParseDisplayName_create(IUnknown *pUnkOuter, LPVOID *ppObj)
471 {
472     ITS_IParseDisplayNameImpl *its;
473
474     if( pUnkOuter )
475         return CLASS_E_NOAGGREGATION;
476
477     its = HeapAlloc( GetProcessHeap(), 0, sizeof(ITS_IParseDisplayNameImpl) );
478     its->vtbl_ITS_IParseDisplayName = &ITS_IParseDisplayNameImpl_Vtbl;
479     its->ref = 1;
480
481     TRACE("-> %p\n", its);
482     *ppObj = (LPVOID) its;
483     InterlockedIncrement(&dll_count);
484
485     return S_OK;
486 }