Fixed definitions of TTTOOLINFOA/W_V1_SIZE and
[wine] / dlls / dmloader / loader.c
1 /* IDirectMusicLoader8 Implementation
2  *
3  * Copyright (C) 2003 Rok Mandeljc
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #include <stdarg.h>
21
22 #include "windef.h"
23 #include "winbase.h"
24 #include "winuser.h"
25 #include "wingdi.h"
26 #include "wine/debug.h"
27 #include "wine/unicode.h"
28 #include "winreg.h"
29
30 #include "dmloader_private.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(dmloader);
33
34 HRESULT WINAPI DMUSIC_GetDefaultGMPath (WCHAR wszPath[MAX_PATH]);
35
36 /* IDirectMusicLoader8 IUnknown part: */
37 HRESULT WINAPI IDirectMusicLoader8Impl_QueryInterface (LPDIRECTMUSICLOADER8 iface, REFIID riid, LPVOID *ppobj)
38 {
39         ICOM_THIS(IDirectMusicLoader8Impl,iface);
40
41         if (IsEqualIID (riid, &IID_IUnknown) || 
42             IsEqualIID (riid, &IID_IDirectMusicLoader) ||
43             IsEqualIID (riid, &IID_IDirectMusicLoader8)) {
44                 IDirectMusicLoader8Impl_AddRef(iface);
45                 *ppobj = This;
46                 return S_OK;
47         }
48         
49         WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
50         return E_NOINTERFACE;
51 }
52
53 ULONG WINAPI IDirectMusicLoader8Impl_AddRef (LPDIRECTMUSICLOADER8 iface)
54 {
55         ICOM_THIS(IDirectMusicLoader8Impl,iface);
56         TRACE("(%p) : AddRef from %ld\n", This, This->ref);
57         return ++(This->ref);
58 }
59
60 ULONG WINAPI IDirectMusicLoader8Impl_Release (LPDIRECTMUSICLOADER8 iface)
61 {
62         ICOM_THIS(IDirectMusicLoader8Impl,iface);
63         ULONG ref = --This->ref;
64         TRACE("(%p) : ReleaseRef to %ld\n", This, This->ref);
65         if (ref == 0) {
66                 HeapFree(GetProcessHeap(), 0, This);
67         }
68         return ref;
69 }
70
71 /* IDirectMusicLoader8 IDirectMusicLoader part: */
72 HRESULT WINAPI IDirectMusicLoader8Impl_GetObject (LPDIRECTMUSICLOADER8 iface, LPDMUS_OBJECTDESC pDesc, REFIID riid, LPVOID* ppv)
73 {
74         IDirectMusicObject* pObject;
75         DMUS_OBJECTDESC desc;
76         ICOM_THIS(IDirectMusicLoader8Impl,iface);
77         int i;
78         HRESULT result;
79
80         TRACE("(%p, %p, %s, %p)\n", This, pDesc, debugstr_guid(riid), ppv);
81         TRACE(": looking up cache");
82         /* first, check if requested object is already in cache (check by name and GUID) */
83         for (i = 0; i < This->dwCacheSize; i++) {
84                 if (pDesc->dwValidData & DMUS_OBJ_OBJECT) {
85                         if (IsEqualGUID (&pDesc->guidObject, &This->pCache[i].guidObject)) {
86                                 TRACE(": object already exist in cache (found by GUID)\n");
87                                 if (This->pCache[i].pObject) {
88                                         return IDirectMusicObject_QueryInterface (This->pCache[i].pObject, riid, ppv);
89                                 }
90                         }
91                 } else if (pDesc->dwValidData & DMUS_OBJ_FILENAME) {
92                         if (This->pCache[i].pwzFileName && !strncmpW(pDesc->wszFileName, This->pCache[i].pwzFileName, MAX_PATH)) {
93                                 TRACE(": object already exist in cache (found by file name)\n");
94                                 if (This->pCache[i].pObject) {
95                                         return IDirectMusicObject_QueryInterface (This->pCache[i].pObject, riid, ppv);
96                                 }
97                         }
98                 }
99         }
100
101         /* object doesn't exist in cache... guess we'll have to load it */
102         TRACE(": object does not exist in cache\n");
103         result = CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject);
104         if (FAILED(result)) return result;
105         if (pDesc->dwValidData & DMUS_OBJ_FILENAME) {
106                 /* load object from file */
107                 WCHAR wzFileName[MAX_PATH];
108                 ILoaderStream* pStream;
109         IPersistStream *pPersistStream = NULL;  
110                 /* if it's full path, don't add search directory path, otherwise do */
111                 if (pDesc->dwValidData & DMUS_OBJ_FULLPATH) {
112                     lstrcpyW( wzFileName, pDesc->wszFileName );
113                 } else {
114                     WCHAR *p;
115                     lstrcpyW( wzFileName, This->wzSearchPath );
116                     p = wzFileName + lstrlenW(wzFileName);
117                     if (p > wzFileName && p[-1] != '\\') *p++ = '\\';
118                     lstrcpyW( p, pDesc->wszFileName );
119                 }
120                 TRACE(": loading from file (%s)\n", debugstr_w(wzFileName));
121          
122                 result = DMUSIC_CreateLoaderStream ((LPSTREAM*)&pStream);
123                 if (FAILED(result)) return result;
124                 
125                 result = ILoaderStream_Attach (pStream, wzFileName, (LPDIRECTMUSICLOADER)iface);
126                 if (FAILED(result)) return result;
127                         
128                 result = IDirectMusicObject_QueryInterface (pObject, &IID_IPersistStream, (LPVOID*)&pPersistStream);
129         if (FAILED(result)) return result;
130                         
131                 result = IPersistStream_Load (pPersistStream, (LPSTREAM)pStream);
132         if (FAILED(result)) return result;
133                         
134         ILoaderStream_IStream_Release ((LPSTREAM)pStream);
135         IPersistStream_Release (pPersistStream);
136         } else if (pDesc->dwValidData & DMUS_OBJ_STREAM) {
137                 /* load object from stream */
138                 IStream* pClonedStream = NULL;
139                 IPersistStream* pPersistStream = NULL;
140
141                 TRACE(": loading from stream\n");
142                 result = IDirectMusicObject_QueryInterface (pObject, &IID_IPersistStream, (LPVOID*)&pPersistStream);
143         if (FAILED(result)) {
144                         TRACE("couln\'t get IPersistStream\n");
145                         return result;
146                 }
147                         
148         result = IStream_Clone (pDesc->pStream, &pClonedStream);
149         if (FAILED(result)) {
150                         TRACE("failed to clone\n");
151                         return result;
152                 }
153
154         result = IPersistStream_Load (pPersistStream, pClonedStream);
155         if (FAILED(result)) {
156                         TRACE("failed to load\n");
157                         return result;
158                 }
159
160                 IPersistStream_Release (pPersistStream);
161                 IStream_Release (pClonedStream);
162         } else if (pDesc->dwValidData & DMUS_OBJ_OBJECT) {
163                 /* load object by GUID */
164                 TRACE(": loading by GUID (only default DLS supported)\n");
165                 if (IsEqualGUID (&pDesc->guidObject, &GUID_DefaultGMCollection)) {
166                         /* great idea: let's just change dwValid and wszFileName fields and then call ourselves again :D */
167                         pDesc->dwValidData = DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH;
168                         if (FAILED(DMUSIC_GetDefaultGMPath (pDesc->wszFileName)))
169                                 return E_FAIL;
170                         return IDirectMusicLoader8Impl_GetObject (iface, pDesc, riid, ppv);
171                 } else {
172                         return E_FAIL;
173                 }
174         } else {
175                 /* nowhere to load from */
176                 FIXME(": unknown/unsupported way of loading\n");
177                 return E_FAIL;
178         }
179
180         memset((LPVOID)&desc, 0, sizeof(desc));
181         desc.dwSize = sizeof (DMUS_OBJECTDESC); 
182         IDirectMusicObject_GetDescriptor (pObject, &desc);
183         
184         /* tests with native dlls show that descriptor, which is received by GetDescriptor doesn't contain filepath
185            therefore we must copy it from input description     */      
186         if (pDesc->dwValidData & DMUS_OBJ_FILENAME || desc.dwValidData & DMUS_OBJ_OBJECT) {
187                 DMUS_PRIVATE_CACHE_ENTRY CacheEntry;
188                 This->dwCacheSize++; /* increase size of cache for one entry */
189                 This->pCache = HeapReAlloc (GetProcessHeap (), 0, This->pCache, sizeof(DMUS_PRIVATE_CACHE_ENTRY) * This->dwCacheSize);
190                 if (desc.dwValidData & DMUS_OBJ_OBJECT)
191                         CacheEntry.guidObject = desc.guidObject;
192                 if (pDesc->dwValidData & DMUS_OBJ_FILENAME)
193                         strncpyW (CacheEntry.pwzFileName, pDesc->wszFileName, MAX_PATH);
194                 CacheEntry.pObject = pObject;
195                 IDirectMusicObject_AddRef (pObject); /* MSDN says that we should */
196                 This->pCache[This->dwCacheSize - 1] = CacheEntry; /* fill in one backward, as list is zero based */
197                 TRACE(": filled in cache entry\n");
198         }
199         
200         TRACE(": nr. of entries = %ld\n", This->dwCacheSize);   
201         for (i = 0; i < This->dwCacheSize; i++) {
202                 TRACE(": cache entry [%i]: GUID = %s, file name = %s, object = %p\n", i, debugstr_guid(&This->pCache[i].guidObject), debugstr_w(This->pCache[i].pwzFileName), This->pCache[i].pObject);
203         }
204
205         return IDirectMusicObject_QueryInterface (pObject, riid, ppv);
206 }
207
208 HRESULT WINAPI IDirectMusicLoader8Impl_SetObject (LPDIRECTMUSICLOADER8 iface, LPDMUS_OBJECTDESC pDesc)
209 {
210         ICOM_THIS(IDirectMusicLoader8Impl,iface);
211
212         FIXME("(%p, %p): stub\n", This, pDesc);
213
214         return S_OK;
215 }
216
217 HRESULT WINAPI IDirectMusicLoader8Impl_SetSearchDirectory (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, WCHAR* pwzPath, BOOL fClear)
218 {
219         ICOM_THIS(IDirectMusicLoader8Impl,iface);
220
221         TRACE("(%p, %s, %p, %d)\n", This, debugstr_guid(rguidClass), pwzPath, fClear);
222         if (0 == strncmpW(This->wzSearchPath, pwzPath, MAX_PATH)) {
223           return S_FALSE;
224         } 
225         strncpyW(This->wzSearchPath, pwzPath, MAX_PATH);
226         
227         return S_OK;
228 }
229
230 HRESULT WINAPI IDirectMusicLoader8Impl_ScanDirectory (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, WCHAR* pwzFileExtension, WCHAR* pwzScanFileName)
231 {
232         ICOM_THIS(IDirectMusicLoader8Impl,iface);
233
234         FIXME("(%p, %s, %p, %p): stub\n", This, debugstr_guid(rguidClass), pwzFileExtension, pwzScanFileName);
235
236         return S_OK;
237 }
238
239 HRESULT WINAPI IDirectMusicLoader8Impl_CacheObject (LPDIRECTMUSICLOADER8 iface, IDirectMusicObject* pObject)
240 {
241         ICOM_THIS(IDirectMusicLoader8Impl,iface);
242
243         FIXME("(%p, %p): stub\n", This, pObject);
244
245         return S_OK;
246 }
247
248 HRESULT WINAPI IDirectMusicLoader8Impl_ReleaseObject (LPDIRECTMUSICLOADER8 iface, IDirectMusicObject* pObject)
249 {
250         ICOM_THIS(IDirectMusicLoader8Impl,iface);
251
252         FIXME("(%p, %p): stub\n", This, pObject);
253
254         return S_OK;
255 }
256
257 HRESULT WINAPI IDirectMusicLoader8Impl_ClearCache (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass)
258 {
259         ICOM_THIS(IDirectMusicLoader8Impl,iface);
260
261         FIXME("(%p, %s): stub\n", This, debugstr_guid(rguidClass));
262
263         return S_OK;
264 }
265
266 HRESULT WINAPI IDirectMusicLoader8Impl_EnableCache (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, BOOL fEnable)
267 {
268         ICOM_THIS(IDirectMusicLoader8Impl,iface);
269
270         FIXME("(%p, %s, %d): stub\n", This, debugstr_guid(rguidClass), fEnable);
271
272         return S_OK;
273 }
274
275 HRESULT WINAPI IDirectMusicLoader8Impl_EnumObject (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, DWORD dwIndex, LPDMUS_OBJECTDESC pDesc)
276 {
277         ICOM_THIS(IDirectMusicLoader8Impl,iface);
278
279         FIXME("(%p, %s, %ld, %p): stub\n", This, debugstr_guid(rguidClass), dwIndex, pDesc);
280
281         return S_OK;
282 }
283
284 /* IDirectMusicLoader8 Interface part follow: */
285 void WINAPI IDirectMusicLoader8Impl_CollectGarbage (LPDIRECTMUSICLOADER8 iface)
286 {
287         ICOM_THIS(IDirectMusicLoader8Impl,iface);
288
289         FIXME("(%p): stub\n", This);
290 }
291
292 HRESULT WINAPI IDirectMusicLoader8Impl_ReleaseObjectByUnknown (LPDIRECTMUSICLOADER8 iface, IUnknown* pObject)
293 {
294         ICOM_THIS(IDirectMusicLoader8Impl,iface);
295
296         FIXME("(%p, %p): stub\n", This, pObject);
297         
298         return S_OK;
299 }
300
301 HRESULT WINAPI IDirectMusicLoader8Impl_LoadObjectFromFile (LPDIRECTMUSICLOADER8 iface, 
302                                                            REFGUID rguidClassID, 
303                                                            REFIID iidInterfaceID, 
304                                                            WCHAR* pwzFilePath, 
305                                                            void** ppObject)
306 {
307         ICOM_THIS(IDirectMusicLoader8Impl,iface);
308         DMUS_OBJECTDESC ObjDesc;
309         
310         TRACE("(%p, %s, %s, %s, %p): wrapping to IDirectMusicLoader8Impl_GetObject\n", This, debugstr_guid(rguidClassID), debugstr_guid(iidInterfaceID), debugstr_w(pwzFilePath), ppObject);
311         
312         ObjDesc.dwSize = sizeof(DMUS_OBJECTDESC);
313         ObjDesc.dwValidData = DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_CLASS; /* I believe I've read somewhere in MSDN that this function requires either full path or relative path */
314         ObjDesc.guidClass = *rguidClassID;
315         strncpyW (ObjDesc.wszFileName, pwzFilePath, MAX_PATH);
316
317         return IDirectMusicLoader8Impl_GetObject (iface, &ObjDesc, iidInterfaceID, ppObject);
318 }
319
320 ICOM_VTABLE(IDirectMusicLoader8) DirectMusicLoader8_Vtbl =
321 {
322     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
323         IDirectMusicLoader8Impl_QueryInterface,
324         IDirectMusicLoader8Impl_AddRef,
325         IDirectMusicLoader8Impl_Release,
326         IDirectMusicLoader8Impl_GetObject,
327         IDirectMusicLoader8Impl_SetObject,
328         IDirectMusicLoader8Impl_SetSearchDirectory,
329         IDirectMusicLoader8Impl_ScanDirectory,
330         IDirectMusicLoader8Impl_CacheObject,
331         IDirectMusicLoader8Impl_ReleaseObject,
332         IDirectMusicLoader8Impl_ClearCache,
333         IDirectMusicLoader8Impl_EnableCache,
334         IDirectMusicLoader8Impl_EnumObject,
335         IDirectMusicLoader8Impl_CollectGarbage,
336         IDirectMusicLoader8Impl_ReleaseObjectByUnknown,
337         IDirectMusicLoader8Impl_LoadObjectFromFile
338 };
339
340 /* for ClassFactory */
341 HRESULT WINAPI DMUSIC_CreateDirectMusicLoader (LPCGUID lpcGUID, LPDIRECTMUSICLOADER8 *ppDMLoad, LPUNKNOWN pUnkOuter)
342 {
343         IDirectMusicLoader8Impl *dmloader;
344
345         TRACE("(%p,%p,%p)\n",lpcGUID, ppDMLoad, pUnkOuter);
346         if (IsEqualIID (lpcGUID, &IID_IDirectMusicLoader) || 
347             IsEqualIID (lpcGUID, &IID_IDirectMusicLoader8)) {
348                 dmloader = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoader8Impl));
349                 if (NULL == dmloader) {
350                         *ppDMLoad = (LPDIRECTMUSICLOADER8)NULL;
351                         return E_OUTOFMEMORY;
352                 }
353                 dmloader->lpVtbl = &DirectMusicLoader8_Vtbl;
354                 dmloader->ref = 1;
355                 *ppDMLoad = (LPDIRECTMUSICLOADER8)dmloader;
356                 return S_OK;
357         }
358         
359         WARN("No interface found\n");
360         return E_NOINTERFACE;
361 }
362
363 /* help function for IDirectMusicLoader8Impl_GetObject */
364 HRESULT WINAPI DMUSIC_GetDefaultGMPath (WCHAR wszPath[MAX_PATH])
365 {
366         HKEY hkDM;
367         DWORD returnType, sizeOfReturnBuffer = MAX_PATH;
368         char szPath[MAX_PATH];
369
370         if ((RegOpenKeyExA (HKEY_LOCAL_MACHINE, "Software\\Microsoft\\DirectMusic" , 0, KEY_READ, &hkDM) != ERROR_SUCCESS) || 
371             (RegQueryValueExA (hkDM, "GMFilePath", NULL, &returnType, szPath, &sizeOfReturnBuffer) != ERROR_SUCCESS)) {
372                 WARN(": registry entry missing\n" );
373                 return E_FAIL;
374         }
375         /* FIXME: Check return types to ensure we're interpreting data right */
376         MultiByteToWideChar (CP_ACP, 0, szPath, -1, wszPath, MAX_PATH);
377         
378         return S_OK;
379 }