msvcr90: Added _encoded_null() implementation.
[wine] / dlls / fusion / asmcache.c
1 /*
2  * IAssemblyCache implementation
3  *
4  * Copyright 2008 James Hawkins
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22 #include <stdio.h>
23
24 #define COBJMACROS
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winver.h"
30 #include "wincrypt.h"
31 #include "winreg.h"
32 #include "shlwapi.h"
33 #include "dbghelp.h"
34 #include "ole2.h"
35 #include "fusion.h"
36 #include "corerror.h"
37
38 #include "fusionpriv.h"
39 #include "wine/debug.h"
40 #include "wine/unicode.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(fusion);
43
44 static BOOL create_full_path(LPCWSTR path)
45 {
46     LPWSTR new_path;
47     BOOL ret = TRUE;
48     int len;
49
50     new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) * sizeof(WCHAR));
51     if (!new_path)
52         return FALSE;
53
54     strcpyW(new_path, path);
55
56     while ((len = strlenW(new_path)) && new_path[len - 1] == '\\')
57         new_path[len - 1] = 0;
58
59     while (!CreateDirectoryW(new_path, NULL))
60     {
61         LPWSTR slash;
62         DWORD last_error = GetLastError();
63
64         if(last_error == ERROR_ALREADY_EXISTS)
65             break;
66
67         if(last_error != ERROR_PATH_NOT_FOUND)
68         {
69             ret = FALSE;
70             break;
71         }
72
73         if(!(slash = strrchrW(new_path, '\\')))
74         {
75             ret = FALSE;
76             break;
77         }
78
79         len = slash - new_path;
80         new_path[len] = 0;
81         if(!create_full_path(new_path))
82         {
83             ret = FALSE;
84             break;
85         }
86
87         new_path[len] = '\\';
88     }
89
90     HeapFree(GetProcessHeap(), 0, new_path);
91     return ret;
92 }
93
94 static BOOL get_assembly_directory(LPWSTR dir, DWORD size)
95 {
96     static const WCHAR gac[] =
97         {'\\','a','s','s','e','m','b','l','y','\\','G','A','C','_','M','S','I','L',0};
98
99     FIXME("Ignoring assembly architecture\n");
100
101     GetWindowsDirectoryW(dir, size);
102     strcatW(dir, gac);
103     return TRUE;
104 }
105
106 /* IAssemblyCache */
107
108 typedef struct {
109     const IAssemblyCacheVtbl *lpIAssemblyCacheVtbl;
110
111     LONG ref;
112 } IAssemblyCacheImpl;
113
114 static HRESULT WINAPI IAssemblyCacheImpl_QueryInterface(IAssemblyCache *iface,
115                                                         REFIID riid, LPVOID *ppobj)
116 {
117     IAssemblyCacheImpl *This = (IAssemblyCacheImpl *)iface;
118
119     TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj);
120
121     *ppobj = NULL;
122
123     if (IsEqualIID(riid, &IID_IUnknown) ||
124         IsEqualIID(riid, &IID_IAssemblyCache))
125     {
126         IUnknown_AddRef(iface);
127         *ppobj = This;
128         return S_OK;
129     }
130
131     WARN("(%p, %s, %p): not found\n", This, debugstr_guid(riid), ppobj);
132     return E_NOINTERFACE;
133 }
134
135 static ULONG WINAPI IAssemblyCacheImpl_AddRef(IAssemblyCache *iface)
136 {
137     IAssemblyCacheImpl *This = (IAssemblyCacheImpl *)iface;
138     ULONG refCount = InterlockedIncrement(&This->ref);
139
140     TRACE("(%p)->(ref before = %u)\n", This, refCount - 1);
141
142     return refCount;
143 }
144
145 static ULONG WINAPI IAssemblyCacheImpl_Release(IAssemblyCache *iface)
146 {
147     IAssemblyCacheImpl *This = (IAssemblyCacheImpl *)iface;
148     ULONG refCount = InterlockedDecrement(&This->ref);
149
150     TRACE("(%p)->(ref before = %u)\n", This, refCount + 1);
151
152     if (!refCount)
153         HeapFree(GetProcessHeap(), 0, This);
154
155     return refCount;
156 }
157
158 static HRESULT WINAPI IAssemblyCacheImpl_UninstallAssembly(IAssemblyCache *iface,
159                                                            DWORD dwFlags,
160                                                            LPCWSTR pszAssemblyName,
161                                                            LPCFUSION_INSTALL_REFERENCE pRefData,
162                                                            ULONG *pulDisposition)
163 {
164     FIXME("(%p, %d, %s, %p, %p) stub!\n", iface, dwFlags,
165           debugstr_w(pszAssemblyName), pRefData, pulDisposition);
166
167     return E_NOTIMPL;
168 }
169
170 static HRESULT WINAPI IAssemblyCacheImpl_QueryAssemblyInfo(IAssemblyCache *iface,
171                                                            DWORD dwFlags,
172                                                            LPCWSTR pszAssemblyName,
173                                                            ASSEMBLY_INFO *pAsmInfo)
174 {
175     IAssemblyName *asmname, *next = NULL;
176     IAssemblyEnum *asmenum = NULL;
177     HRESULT hr;
178
179     TRACE("(%p, %d, %s, %p)\n", iface, dwFlags,
180           debugstr_w(pszAssemblyName), pAsmInfo);
181
182     if (pAsmInfo)
183     {
184         if (pAsmInfo->cbAssemblyInfo == 0)
185             pAsmInfo->cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
186         else if (pAsmInfo->cbAssemblyInfo != sizeof(ASSEMBLY_INFO))
187             return E_INVALIDARG;
188     }
189
190     hr = CreateAssemblyNameObject(&asmname, pszAssemblyName,
191                                   CANOF_PARSE_DISPLAY_NAME, NULL);
192     if (FAILED(hr))
193         return hr;
194
195     hr = CreateAssemblyEnum(&asmenum, NULL, asmname, ASM_CACHE_GAC, NULL);
196     if (FAILED(hr))
197         goto done;
198
199     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
200     if (hr == S_FALSE)
201     {
202         hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
203         goto done;
204     }
205
206     if (!pAsmInfo)
207         goto done;
208
209     pAsmInfo->dwAssemblyFlags = ASSEMBLYINFO_FLAG_INSTALLED;
210
211 done:
212     IAssemblyName_Release(asmname);
213     if (next) IAssemblyName_Release(next);
214     if (asmenum) IAssemblyEnum_Release(asmenum);
215
216     return hr;
217 }
218
219 static HRESULT WINAPI IAssemblyCacheImpl_CreateAssemblyCacheItem(IAssemblyCache *iface,
220                                                                  DWORD dwFlags,
221                                                                  PVOID pvReserved,
222                                                                  IAssemblyCacheItem **ppAsmItem,
223                                                                  LPCWSTR pszAssemblyName)
224 {
225     FIXME("(%p, %d, %p, %p, %s) stub!\n", iface, dwFlags, pvReserved,
226           ppAsmItem, debugstr_w(pszAssemblyName));
227
228     return E_NOTIMPL;
229 }
230
231 static HRESULT WINAPI IAssemblyCacheImpl_CreateAssemblyScavenger(IAssemblyCache *iface,
232                                                                  IUnknown **ppUnkReserved)
233 {
234     FIXME("(%p, %p) stub!\n", iface, ppUnkReserved);
235     return E_NOTIMPL;
236 }
237
238 static HRESULT WINAPI IAssemblyCacheImpl_InstallAssembly(IAssemblyCache *iface,
239                                                          DWORD dwFlags,
240                                                          LPCWSTR pszManifestFilePath,
241                                                          LPCFUSION_INSTALL_REFERENCE pRefData)
242 {
243     static const WCHAR format[] =
244         {'%','s','\\','%','s','\\','%','s','_','_','%','s','\\',0};
245
246     ASSEMBLY *assembly;
247     LPWSTR filename;
248     LPWSTR name = NULL;
249     LPWSTR token = NULL;
250     LPWSTR version = NULL;
251     LPWSTR asmpath = NULL;
252     WCHAR path[MAX_PATH];
253     WCHAR asmdir[MAX_PATH];
254     LPWSTR ext;
255     HRESULT hr;
256
257     static const WCHAR ext_exe[] = {'.','e','x','e',0};
258     static const WCHAR ext_dll[] = {'.','d','l','l',0};
259
260     TRACE("(%p, %d, %s, %p)\n", iface, dwFlags,
261           debugstr_w(pszManifestFilePath), pRefData);
262
263     if (!pszManifestFilePath || !*pszManifestFilePath)
264         return E_INVALIDARG;
265
266     if (!(ext = strrchrW(pszManifestFilePath, '.')))
267         return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
268
269     if (lstrcmpiW(ext, ext_exe) && lstrcmpiW(ext, ext_dll))
270         return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
271
272     if (GetFileAttributesW(pszManifestFilePath) == INVALID_FILE_ATTRIBUTES)
273         return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
274
275     hr = assembly_create(&assembly, pszManifestFilePath);
276     if (FAILED(hr))
277     {
278         hr = COR_E_ASSEMBLYEXPECTED;
279         goto done;
280     }
281
282     hr = assembly_get_name(assembly, &name);
283     if (FAILED(hr))
284         goto done;
285
286     hr = assembly_get_pubkey_token(assembly, &token);
287     if (FAILED(hr))
288         goto done;
289
290     hr = assembly_get_version(assembly, &version);
291     if (FAILED(hr))
292         goto done;
293
294     get_assembly_directory(asmdir, MAX_PATH);
295
296     sprintfW(path, format, asmdir, name, version, token);
297
298     create_full_path(path);
299
300     hr = assembly_get_path(assembly, &asmpath);
301     if (FAILED(hr))
302         goto done;
303
304     filename = PathFindFileNameW(asmpath);
305
306     strcatW(path, filename);
307     if (!CopyFileW(asmpath, path, FALSE))
308         hr = HRESULT_FROM_WIN32(GetLastError());
309
310 done:
311     HeapFree(GetProcessHeap(), 0, name);
312     HeapFree(GetProcessHeap(), 0, token);
313     HeapFree(GetProcessHeap(), 0, version);
314     HeapFree(GetProcessHeap(), 0, asmpath);
315     assembly_release(assembly);
316     return hr;
317 }
318
319 static const IAssemblyCacheVtbl AssemblyCacheVtbl = {
320     IAssemblyCacheImpl_QueryInterface,
321     IAssemblyCacheImpl_AddRef,
322     IAssemblyCacheImpl_Release,
323     IAssemblyCacheImpl_UninstallAssembly,
324     IAssemblyCacheImpl_QueryAssemblyInfo,
325     IAssemblyCacheImpl_CreateAssemblyCacheItem,
326     IAssemblyCacheImpl_CreateAssemblyScavenger,
327     IAssemblyCacheImpl_InstallAssembly
328 };
329
330 /******************************************************************
331  *  CreateAssemblyCache   (FUSION.@)
332  */
333 HRESULT WINAPI CreateAssemblyCache(IAssemblyCache **ppAsmCache, DWORD dwReserved)
334 {
335     IAssemblyCacheImpl *cache;
336
337     TRACE("(%p, %d)\n", ppAsmCache, dwReserved);
338
339     if (!ppAsmCache)
340         return E_INVALIDARG;
341
342     *ppAsmCache = NULL;
343
344     cache = HeapAlloc(GetProcessHeap(), 0, sizeof(IAssemblyCacheImpl));
345     if (!cache)
346         return E_OUTOFMEMORY;
347
348     cache->lpIAssemblyCacheVtbl = &AssemblyCacheVtbl;
349     cache->ref = 1;
350
351     *ppAsmCache = (IAssemblyCache *)cache;
352
353     return S_OK;
354 }
355
356 /* IAssemblyCacheItem */
357
358 typedef struct {
359     const IAssemblyCacheItemVtbl *lpIAssemblyCacheItemVtbl;
360
361     LONG ref;
362 } IAssemblyCacheItemImpl;
363
364 static HRESULT WINAPI IAssemblyCacheItemImpl_QueryInterface(IAssemblyCacheItem *iface,
365                                                             REFIID riid, LPVOID *ppobj)
366 {
367     IAssemblyCacheItemImpl *This = (IAssemblyCacheItemImpl *)iface;
368
369     TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj);
370
371     *ppobj = NULL;
372
373     if (IsEqualIID(riid, &IID_IUnknown) ||
374         IsEqualIID(riid, &IID_IAssemblyCacheItem))
375     {
376         IUnknown_AddRef(iface);
377         *ppobj = This;
378         return S_OK;
379     }
380
381     WARN("(%p, %s, %p): not found\n", This, debugstr_guid(riid), ppobj);
382     return E_NOINTERFACE;
383 }
384
385 static ULONG WINAPI IAssemblyCacheItemImpl_AddRef(IAssemblyCacheItem *iface)
386 {
387     IAssemblyCacheItemImpl *This = (IAssemblyCacheItemImpl *)iface;
388     ULONG refCount = InterlockedIncrement(&This->ref);
389
390     TRACE("(%p)->(ref before = %u)\n", This, refCount - 1);
391
392     return refCount;
393 }
394
395 static ULONG WINAPI IAssemblyCacheItemImpl_Release(IAssemblyCacheItem *iface)
396 {
397     IAssemblyCacheItemImpl *This = (IAssemblyCacheItemImpl *)iface;
398     ULONG refCount = InterlockedDecrement(&This->ref);
399
400     TRACE("(%p)->(ref before = %u)\n", This, refCount + 1);
401
402     if (!refCount)
403         HeapFree(GetProcessHeap(), 0, This);
404
405     return refCount;
406 }
407
408 static HRESULT WINAPI IAssemblyCacheItemImpl_CreateStream(IAssemblyCacheItem *iface,
409                                                         DWORD dwFlags,
410                                                         LPCWSTR pszStreamName,
411                                                         DWORD dwFormat,
412                                                         DWORD dwFormatFlags,
413                                                         IStream **ppIStream,
414                                                         ULARGE_INTEGER *puliMaxSize)
415 {
416     FIXME("(%p, %d, %s, %d, %d, %p, %p) stub!\n", iface, dwFlags,
417           debugstr_w(pszStreamName), dwFormat, dwFormatFlags, ppIStream, puliMaxSize);
418
419     return E_NOTIMPL;
420 }
421
422 static HRESULT WINAPI IAssemblyCacheItemImpl_Commit(IAssemblyCacheItem *iface,
423                                                   DWORD dwFlags,
424                                                   ULONG *pulDisposition)
425 {
426     FIXME("(%p, %d, %p) stub!\n", iface, dwFlags, pulDisposition);
427     return E_NOTIMPL;
428 }
429
430 static HRESULT WINAPI IAssemblyCacheItemImpl_AbortItem(IAssemblyCacheItem *iface)
431 {
432     FIXME("(%p) stub!\n", iface);
433     return E_NOTIMPL;
434 }
435
436 static const IAssemblyCacheItemVtbl AssemblyCacheItemVtbl = {
437     IAssemblyCacheItemImpl_QueryInterface,
438     IAssemblyCacheItemImpl_AddRef,
439     IAssemblyCacheItemImpl_Release,
440     IAssemblyCacheItemImpl_CreateStream,
441     IAssemblyCacheItemImpl_Commit,
442     IAssemblyCacheItemImpl_AbortItem
443 };