itss: Ignore trailing slash in IStorage::OpenStream.
[wine] / dlls / itss / itss.c
1 /*
2  *    ITSS Class Factory
3  *
4  * Copyright 2002 Lionel Ulmer
5  * Copyright 2004 Mike McCormack
6  *
7  *  see http://bonedaddy.net/pabs3/hhm/#chmspec
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 #include "config.h"
25
26 #include <stdarg.h>
27 #include <stdio.h>
28
29 #define COBJMACROS
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winuser.h"
34 #include "winnls.h"
35 #include "winreg.h"
36 #include "ole2.h"
37 #include "advpub.h"
38
39 #include "uuids.h"
40
41 #include "wine/unicode.h"
42 #include "wine/debug.h"
43
44 #include "itsstor.h"
45
46 #include "initguid.h"
47 #include "wine/itss.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(itss);
50
51 static HRESULT ITSS_create(IUnknown *pUnkOuter, LPVOID *ppObj);
52
53 LONG dll_count = 0;
54 static HINSTANCE hInst;
55
56 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
57 {
58     switch(fdwReason) {
59     case DLL_PROCESS_ATTACH:
60         DisableThreadLibraryCalls(hInstDLL);
61         hInst = hInstDLL;
62         break;
63     case DLL_PROCESS_DETACH:
64         break;
65     }
66     return TRUE;
67 }
68
69 /******************************************************************************
70  * ITSS ClassFactory
71  */
72 typedef struct {
73     const IClassFactoryVtbl *lpVtbl;
74     HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
75 } IClassFactoryImpl;
76
77 static HRESULT WINAPI
78 ITSSCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
79 {
80     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
81
82     if (IsEqualGUID(riid, &IID_IUnknown) ||
83         IsEqualGUID(riid, &IID_IClassFactory))
84     {
85         IClassFactory_AddRef(iface);
86         *ppobj = This;
87         return S_OK;
88     }
89
90     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
91     return E_NOINTERFACE;
92 }
93
94 static ULONG WINAPI ITSSCF_AddRef(LPCLASSFACTORY iface)
95 {
96     ITSS_LockModule();
97     return 2;
98 }
99
100 static ULONG WINAPI ITSSCF_Release(LPCLASSFACTORY iface)
101 {
102     ITSS_UnlockModule();
103     return 1;
104 }
105
106
107 static HRESULT WINAPI ITSSCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter,
108                                           REFIID riid, LPVOID *ppobj)
109 {
110     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
111     HRESULT hres;
112     LPUNKNOWN punk;
113
114     TRACE("(%p)->(%p,%s,%p)\n", This, pOuter, debugstr_guid(riid), ppobj);
115
116     *ppobj = NULL;
117     hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk);
118     if (SUCCEEDED(hres)) {
119         hres = IUnknown_QueryInterface(punk, riid, ppobj);
120         IUnknown_Release(punk);
121     }
122     return hres;
123 }
124
125 static HRESULT WINAPI ITSSCF_LockServer(LPCLASSFACTORY iface, BOOL dolock)
126 {
127     TRACE("(%p)->(%d)\n", iface, dolock);
128
129     if (dolock)
130         ITSS_LockModule();
131     else
132         ITSS_UnlockModule();
133
134     return S_OK;
135 }
136
137 static const IClassFactoryVtbl ITSSCF_Vtbl =
138 {
139     ITSSCF_QueryInterface,
140     ITSSCF_AddRef,
141     ITSSCF_Release,
142     ITSSCF_CreateInstance,
143     ITSSCF_LockServer
144 };
145
146 static const IClassFactoryImpl ITStorage_factory = { &ITSSCF_Vtbl, ITSS_create };
147 static const IClassFactoryImpl MSITStore_factory = { &ITSSCF_Vtbl, ITS_IParseDisplayName_create };
148 static const IClassFactoryImpl ITSProtocol_factory = { &ITSSCF_Vtbl, ITSProtocol_create };
149
150 /***********************************************************************
151  *              DllGetClassObject       (ITSS.@)
152  */
153 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
154 {
155     const IClassFactoryImpl *factory;
156
157     TRACE("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(iid), ppv);
158
159     if (IsEqualGUID(&CLSID_ITStorage, rclsid))
160         factory = &ITStorage_factory;
161     else if (IsEqualGUID(&CLSID_MSITStore, rclsid))
162         factory = &MSITStore_factory;
163     else if (IsEqualGUID(&CLSID_ITSProtocol, rclsid))
164         factory = &ITSProtocol_factory;
165     else
166     {
167         FIXME("%s: no class found.\n", debugstr_guid(rclsid));
168         return CLASS_E_CLASSNOTAVAILABLE;
169     }
170
171     return IUnknown_QueryInterface( (IUnknown*) factory, iid, ppv );
172 }
173
174 /*****************************************************************************/
175
176 typedef struct {
177     const IITStorageVtbl *vtbl_IITStorage;
178     LONG ref;
179 } ITStorageImpl;
180
181
182 static HRESULT WINAPI ITStorageImpl_QueryInterface(
183     IITStorage* iface,
184     REFIID riid,
185     void** ppvObject)
186 {
187     ITStorageImpl *This = (ITStorageImpl *)iface;
188     if (IsEqualGUID(riid, &IID_IUnknown)
189         || IsEqualGUID(riid, &IID_IITStorage))
190     {
191         IClassFactory_AddRef(iface);
192         *ppvObject = This;
193         return S_OK;
194     }
195
196     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
197     return E_NOINTERFACE;
198 }
199
200 static ULONG WINAPI ITStorageImpl_AddRef(
201     IITStorage* iface)
202 {
203     ITStorageImpl *This = (ITStorageImpl *)iface;
204     TRACE("%p\n", This);
205     return InterlockedIncrement(&This->ref);
206 }
207
208 static ULONG WINAPI ITStorageImpl_Release(
209     IITStorage* iface)
210 {
211     ITStorageImpl *This = (ITStorageImpl *)iface;
212     ULONG ref = InterlockedDecrement(&This->ref);
213
214     if (ref == 0) {
215         HeapFree(GetProcessHeap(), 0, This);
216         ITSS_UnlockModule();
217     }
218
219     return ref;
220 }
221
222 static HRESULT WINAPI ITStorageImpl_StgCreateDocfile(
223     IITStorage* iface,
224     const WCHAR* pwcsName,
225     DWORD grfMode,
226     DWORD reserved,
227     IStorage** ppstgOpen)
228 {
229     ITStorageImpl *This = (ITStorageImpl *)iface;
230
231     TRACE("%p %s %u %u %p\n", This,
232           debugstr_w(pwcsName), grfMode, reserved, ppstgOpen );
233
234     return ITSS_StgOpenStorage( pwcsName, NULL, grfMode,
235                                 0, reserved, ppstgOpen);
236 }
237
238 static HRESULT WINAPI ITStorageImpl_StgCreateDocfileOnILockBytes(
239     IITStorage* iface,
240     ILockBytes* plkbyt,
241     DWORD grfMode,
242     DWORD reserved,
243     IStorage** ppstgOpen)
244 {
245     ITStorageImpl *This = (ITStorageImpl *)iface;
246     FIXME("%p\n", This);
247     return E_NOTIMPL;
248 }
249
250 static HRESULT WINAPI ITStorageImpl_StgIsStorageFile(
251     IITStorage* iface,
252     const WCHAR* pwcsName)
253 {
254     ITStorageImpl *This = (ITStorageImpl *)iface;
255     FIXME("%p\n", This);
256     return E_NOTIMPL;
257 }
258
259 static HRESULT WINAPI ITStorageImpl_StgIsStorageILockBytes(
260     IITStorage* iface,
261     ILockBytes* plkbyt)
262 {
263     ITStorageImpl *This = (ITStorageImpl *)iface;
264     FIXME("%p\n", This);
265     return E_NOTIMPL;
266 }
267
268 static HRESULT WINAPI ITStorageImpl_StgOpenStorage(
269     IITStorage* iface,
270     const WCHAR* pwcsName,
271     IStorage* pstgPriority,
272     DWORD grfMode,
273     SNB snbExclude,
274     DWORD reserved,
275     IStorage** ppstgOpen)
276 {
277     ITStorageImpl *This = (ITStorageImpl *)iface;
278
279     TRACE("%p %s %p %d %p\n", This, debugstr_w( pwcsName ),
280            pstgPriority, grfMode, snbExclude );
281
282     return ITSS_StgOpenStorage( pwcsName, pstgPriority, grfMode,
283                                 snbExclude, reserved, ppstgOpen);
284 }
285
286 static HRESULT WINAPI ITStorageImpl_StgOpenStorageOnILockBytes(
287     IITStorage* iface,
288     ILockBytes* plkbyt,
289     IStorage* pStgPriority,
290     DWORD grfMode,
291     SNB snbExclude,
292     DWORD reserved,
293     IStorage** ppstgOpen)
294 {
295     ITStorageImpl *This = (ITStorageImpl *)iface;
296     FIXME("%p\n", This);
297     return E_NOTIMPL;
298 }
299
300 static HRESULT WINAPI ITStorageImpl_StgSetTimes(
301     IITStorage* iface,
302     WCHAR* lpszName,
303     FILETIME* pctime,
304     FILETIME* patime,
305     FILETIME* pmtime)
306 {
307     ITStorageImpl *This = (ITStorageImpl *)iface;
308     FIXME("%p\n", This);
309     return E_NOTIMPL;
310 }
311
312 static HRESULT WINAPI ITStorageImpl_SetControlData(
313     IITStorage* iface,
314     PITS_Control_Data pControlData)
315 {
316     ITStorageImpl *This = (ITStorageImpl *)iface;
317     FIXME("%p\n", This);
318     return E_NOTIMPL;
319 }
320
321 static HRESULT WINAPI ITStorageImpl_DefaultControlData(
322     IITStorage* iface,
323     PITS_Control_Data* ppControlData)
324 {
325     ITStorageImpl *This = (ITStorageImpl *)iface;
326     FIXME("%p\n", This);
327     return E_NOTIMPL;
328 }
329
330 static HRESULT WINAPI ITStorageImpl_Compact(
331     IITStorage* iface,
332     const WCHAR* pwcsName,
333     ECompactionLev iLev)
334 {
335     ITStorageImpl *This = (ITStorageImpl *)iface;
336     FIXME("%p\n", This);
337     return E_NOTIMPL;
338 }
339
340 static const IITStorageVtbl ITStorageImpl_Vtbl =
341 {
342     ITStorageImpl_QueryInterface,
343     ITStorageImpl_AddRef,
344     ITStorageImpl_Release,
345     ITStorageImpl_StgCreateDocfile,
346     ITStorageImpl_StgCreateDocfileOnILockBytes,
347     ITStorageImpl_StgIsStorageFile,
348     ITStorageImpl_StgIsStorageILockBytes,
349     ITStorageImpl_StgOpenStorage,
350     ITStorageImpl_StgOpenStorageOnILockBytes,
351     ITStorageImpl_StgSetTimes,
352     ITStorageImpl_SetControlData,
353     ITStorageImpl_DefaultControlData,
354     ITStorageImpl_Compact,
355 };
356
357 static HRESULT ITSS_create(IUnknown *pUnkOuter, LPVOID *ppObj)
358 {
359     ITStorageImpl *its;
360
361     if( pUnkOuter )
362         return CLASS_E_NOAGGREGATION;
363
364     its = HeapAlloc( GetProcessHeap(), 0, sizeof(ITStorageImpl) );
365     its->vtbl_IITStorage = &ITStorageImpl_Vtbl;
366     its->ref = 1;
367
368     TRACE("-> %p\n", its);
369     *ppObj = (LPVOID) its;
370
371     ITSS_LockModule();
372     return S_OK;
373 }
374
375 /*****************************************************************************/
376
377 HRESULT WINAPI DllCanUnloadNow(void)
378 {
379     TRACE("dll_count = %u\n", dll_count);
380     return dll_count ? S_FALSE : S_OK;
381 }
382
383 #define INF_SET_ID(id)            \
384     do                            \
385     {                             \
386         static CHAR name[] = #id; \
387                                   \
388         pse[i].pszName = name;    \
389         clsids[i++] = &id;        \
390     } while (0)
391
392 #define INF_SET_CLSID(clsid) INF_SET_ID(CLSID_ ## clsid)
393
394 static HRESULT register_server(BOOL do_register)
395 {
396     HRESULT hres;
397     HMODULE hAdvpack;
398     typeof(RegInstallA) *pRegInstall;
399     STRTABLEA strtable;
400     STRENTRYA pse[4];
401     static CLSID const *clsids[4];
402     int i = 0;
403
404     static const WCHAR wszAdvpack[] = {'a','d','v','p','a','c','k','.','d','l','l',0};
405
406     INF_SET_CLSID(ITStorage);
407     INF_SET_CLSID(MSFSStore);
408     INF_SET_CLSID(MSITStore);
409     INF_SET_CLSID(ITSProtocol);
410
411     strtable.cEntries = sizeof(pse)/sizeof(pse[0]);
412     strtable.pse = pse;
413
414     for(i=0; i < strtable.cEntries; i++) {
415         pse[i].pszValue = HeapAlloc(GetProcessHeap(), 0, 39);
416         sprintf(pse[i].pszValue, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
417                 clsids[i]->Data1, clsids[i]->Data2, clsids[i]->Data3, clsids[i]->Data4[0],
418                 clsids[i]->Data4[1], clsids[i]->Data4[2], clsids[i]->Data4[3], clsids[i]->Data4[4],
419                 clsids[i]->Data4[5], clsids[i]->Data4[6], clsids[i]->Data4[7]);
420     }
421
422     hAdvpack = LoadLibraryW(wszAdvpack);
423     pRegInstall = (typeof(RegInstallA)*)GetProcAddress(hAdvpack, "RegInstall");
424
425     hres = pRegInstall(hInst, do_register ? "RegisterDll" : "UnregisterDll", &strtable);
426
427     for(i=0; i < sizeof(pse)/sizeof(pse[0]); i++)
428         HeapFree(GetProcessHeap(), 0, pse[i].pszValue);
429
430     return hres;
431 }
432
433 #undef INF_SET_CLSID
434 #undef INF_SET_ID
435
436 /***********************************************************************
437  *          DllRegisterServer (ITSS.@)
438  */
439 HRESULT WINAPI DllRegisterServer(void)
440 {
441     return register_server(TRUE);
442 }
443
444 /***********************************************************************
445  *          DllUnregisterServer (ITSS.@)
446  */
447 HRESULT WINAPI DllUnregisterServer(void)
448 {
449     return register_server(FALSE);
450 }