d3dcompiler: Fix SystemValueType for pixelshader output signature.
[wine] / dlls / msi / assembly.c
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2010 Hans Leidekker for CodeWeavers
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
23 #define COBJMACROS
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winreg.h"
28 #include "wine/debug.h"
29 #include "wine/unicode.h"
30 #include "msipriv.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(msi);
33
34 static HRESULT (WINAPI *pCreateAssemblyCacheNet)( IAssemblyCache **, DWORD );
35 static HRESULT (WINAPI *pCreateAssemblyCacheSxs)( IAssemblyCache **, DWORD );
36 static HRESULT (WINAPI *pLoadLibraryShim)( LPCWSTR, LPCWSTR, LPVOID, HMODULE * );
37
38 static BOOL init_function_pointers( void )
39 {
40     static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
41     HMODULE hfusion, hmscoree, hsxs;
42     HRESULT hr;
43
44     if (pCreateAssemblyCacheNet) return TRUE;
45
46     if (!(hmscoree = LoadLibraryA( "mscoree.dll" )))
47     {
48         WARN("mscoree.dll not available\n");
49         return FALSE;
50     }
51     if (!(pLoadLibraryShim = (void *)GetProcAddress( hmscoree, "LoadLibraryShim" )))
52     {
53         WARN("LoadLibraryShim not available\n");
54         FreeLibrary( hmscoree );
55         return FALSE;
56     }
57     hr = pLoadLibraryShim( szFusion, NULL, NULL, &hfusion );
58     if (FAILED( hr ))
59     {
60         WARN("fusion.dll not available 0x%08x\n", hr);
61         FreeLibrary( hmscoree );
62         return FALSE;
63     }
64     pCreateAssemblyCacheNet = (void *)GetProcAddress( hfusion, "CreateAssemblyCache" );
65     FreeLibrary( hmscoree );
66     if (!(hsxs = LoadLibraryA( "sxs.dll" )))
67     {
68         WARN("sxs.dll not available\n");
69         FreeLibrary( hfusion );
70         return FALSE;
71     }
72     pCreateAssemblyCacheSxs = (void *)GetProcAddress( hsxs, "CreateAssemblyCache" );
73     return TRUE;
74 }
75
76 static BOOL init_assembly_caches( MSIPACKAGE *package )
77 {
78     HRESULT hr;
79
80     if (!init_function_pointers()) return FALSE;
81     if (package->cache_net) return TRUE;
82
83     hr = pCreateAssemblyCacheNet( &package->cache_net, 0 );
84     if (hr != S_OK) return FALSE;
85
86     hr = pCreateAssemblyCacheSxs( &package->cache_sxs, 0 );
87     if (hr != S_OK)
88     {
89         IAssemblyCache_Release( package->cache_net );
90         package->cache_net = NULL;
91         return FALSE;
92     }
93     return TRUE;
94 }
95
96 MSIRECORD *get_assembly_record( MSIPACKAGE *package, const WCHAR *comp )
97 {
98     static const WCHAR query[] = {
99         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
100          '`','M','s','i','A','s','s','e','m','b','l','y','`',' ',
101          'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
102          ' ','=',' ','\'','%','s','\'',0};
103     MSIQUERY *view;
104     MSIRECORD *rec;
105     UINT r;
106
107     r = MSI_OpenQuery( package->db, &view, query, comp );
108     if (r != ERROR_SUCCESS)
109         return NULL;
110
111     r = MSI_ViewExecute( view, NULL );
112     if (r != ERROR_SUCCESS)
113     {
114         msiobj_release( &view->hdr );
115         return NULL;
116     }
117     r = MSI_ViewFetch( view, &rec );
118     if (r != ERROR_SUCCESS)
119     {
120         msiobj_release( &view->hdr );
121         return NULL;
122     }
123     if (!MSI_RecordGetString( rec, 4 ))
124         TRACE("component is a global assembly\n");
125
126     msiobj_release( &view->hdr );
127     return rec;
128 }
129
130 struct assembly_name
131 {
132     UINT    count;
133     UINT    index;
134     WCHAR **attrs;
135 };
136
137 static UINT get_assembly_name_attribute( MSIRECORD *rec, LPVOID param )
138 {
139     static const WCHAR fmtW[] = {'%','s','=','"','%','s','"',0};
140     static const WCHAR nameW[] = {'n','a','m','e',0};
141     struct assembly_name *name = param;
142     const WCHAR *attr = MSI_RecordGetString( rec, 2 );
143     const WCHAR *value = MSI_RecordGetString( rec, 3 );
144     int len = strlenW( fmtW ) + strlenW( attr ) + strlenW( value );
145
146     if (!(name->attrs[name->index] = msi_alloc( len * sizeof(WCHAR) )))
147         return ERROR_OUTOFMEMORY;
148
149     if (!strcmpiW( attr, nameW )) strcpyW( name->attrs[name->index++], value );
150     else sprintfW( name->attrs[name->index++], fmtW, attr, value );
151     return ERROR_SUCCESS;
152 }
153
154 static WCHAR *get_assembly_display_name( MSIDATABASE *db, const WCHAR *comp, MSIASSEMBLY *assembly )
155 {
156     static const WCHAR commaW[] = {',',0};
157     static const WCHAR queryW[] = {
158         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
159         '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
160         'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
161         ' ','=',' ','\'','%','s','\'',0};
162     struct assembly_name name;
163     WCHAR *display_name = NULL;
164     MSIQUERY *view;
165     UINT i, r;
166     int len;
167
168     r = MSI_OpenQuery( db, &view, queryW, comp );
169     if (r != ERROR_SUCCESS)
170         return NULL;
171
172     name.count = 0;
173     name.index = 0;
174     name.attrs = NULL;
175     MSI_IterateRecords( view, &name.count, NULL, NULL );
176     if (!name.count) goto done;
177
178     name.attrs = msi_alloc( name.count * sizeof(WCHAR *) );
179     if (!name.attrs) goto done;
180
181     MSI_IterateRecords( view, NULL, get_assembly_name_attribute, &name );
182
183     len = 0;
184     for (i = 0; i < name.count; i++) len += strlenW( name.attrs[i] ) + 1;
185
186     display_name = msi_alloc( (len + 1) * sizeof(WCHAR) );
187     if (display_name)
188     {
189         display_name[0] = 0;
190         for (i = 0; i < name.count; i++)
191         {
192             strcatW( display_name, name.attrs[i] );
193             if (i < name.count - 1) strcatW( display_name, commaW );
194         }
195     }
196
197 done:
198     msiobj_release( &view->hdr );
199     for (i = 0; i < name.count; i++) msi_free( name.attrs[i] );
200     msi_free( name.attrs );
201     return display_name;
202 }
203
204 static BOOL check_assembly_installed( MSIPACKAGE *package, MSIASSEMBLY *assembly )
205 {
206     IAssemblyCache *cache;
207     ASSEMBLY_INFO info;
208     HRESULT hr;
209
210     if (assembly->application)
211     {
212         FIXME("we should probably check the manifest file here\n");
213         if (msi_get_property_int( package->db, szInstalled, 0 )) return TRUE;
214         return FALSE;
215     }
216
217     if (!init_assembly_caches( package ))
218         return FALSE;
219
220     if (assembly->attributes == msidbAssemblyAttributesWin32)
221         cache = package->cache_sxs;
222     else
223         cache = package->cache_net;
224
225     memset( &info, 0, sizeof(info) );
226     info.cbAssemblyInfo = sizeof(info);
227     hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, assembly->display_name, &info );
228     if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
229         return FALSE;
230
231     return (info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
232 }
233
234 MSIASSEMBLY *load_assembly( MSIPACKAGE *package, MSICOMPONENT *comp )
235 {
236     MSIRECORD *rec;
237     MSIASSEMBLY *a;
238
239     if (!(rec = get_assembly_record( package, comp->Component )))
240         return NULL;
241
242     if (!(a = msi_alloc_zero( sizeof(MSIASSEMBLY) )))
243     {
244         msiobj_release( &rec->hdr );
245         return NULL;
246     }
247     a->feature = strdupW( MSI_RecordGetString( rec, 2 ) );
248     TRACE("feature %s\n", debugstr_w(a->feature));
249
250     a->manifest = strdupW( MSI_RecordGetString( rec, 3 ) );
251     TRACE("manifest %s\n", debugstr_w(a->manifest));
252
253     a->application = strdupW( MSI_RecordGetString( rec, 4 ) );
254     TRACE("application %s\n", debugstr_w(a->application));
255
256     a->attributes = MSI_RecordGetInteger( rec, 5 );
257     TRACE("attributes %u\n", a->attributes);
258
259     if (!(a->display_name = get_assembly_display_name( package->db, comp->Component, a )))
260     {
261         WARN("can't get display name\n");
262         msiobj_release( &rec->hdr );
263         msi_free( a->feature );
264         msi_free( a->manifest );
265         msi_free( a->application );
266         msi_free( a );
267         return NULL;
268     }
269     TRACE("display name %s\n", debugstr_w(a->display_name));
270
271     a->installed = check_assembly_installed( package, a );
272     TRACE("assembly is %s\n", a->installed ? "installed" : "not installed");
273
274     msiobj_release( &rec->hdr );
275     return a;
276 }
277
278 UINT install_assembly( MSIPACKAGE *package, MSICOMPONENT *comp )
279 {
280     HRESULT hr;
281     const WCHAR *manifest;
282     IAssemblyCache *cache;
283     MSIASSEMBLY *assembly = comp->assembly;
284     MSIFEATURE *feature = NULL;
285
286     if (comp->assembly->feature)
287         feature = get_loaded_feature( package, comp->assembly->feature );
288
289     if (assembly->application)
290     {
291         if (feature) feature->Action = INSTALLSTATE_LOCAL;
292         return ERROR_SUCCESS;
293     }
294     if (assembly->attributes == msidbAssemblyAttributesWin32)
295     {
296         if (!assembly->manifest)
297         {
298             WARN("no manifest\n");
299             return ERROR_FUNCTION_FAILED;
300         }
301         manifest = get_loaded_file( package, assembly->manifest )->TargetPath;
302         cache = package->cache_sxs;
303     }
304     else
305     {
306         manifest = get_loaded_file( package, comp->KeyPath )->TargetPath;
307         cache = package->cache_net;
308     }
309     TRACE("installing assembly %s\n", debugstr_w(manifest));
310
311     hr = IAssemblyCache_InstallAssembly( cache, 0, manifest, NULL );
312     if (hr != S_OK)
313     {
314         ERR("Failed to install assembly %s (0x%08x)\n", debugstr_w(manifest), hr);
315         return ERROR_FUNCTION_FAILED;
316     }
317     if (feature) feature->Action = INSTALLSTATE_LOCAL;
318     assembly->installed = TRUE;
319     return ERROR_SUCCESS;
320 }
321
322 static WCHAR *build_local_assembly_path( const WCHAR *filename )
323 {
324     UINT i;
325     WCHAR *ret;
326
327     if (!(ret = msi_alloc( (strlenW( filename ) + 1) * sizeof(WCHAR) )))
328         return NULL;
329
330     for (i = 0; filename[i]; i++)
331     {
332         if (filename[i] == '\\' || filename[i] == '/') ret[i] = '|';
333         else ret[i] = filename[i];
334     }
335     ret[i] = 0;
336     return ret;
337 }
338
339 static LONG open_assemblies_key( UINT context, BOOL win32, HKEY *hkey )
340 {
341     static const WCHAR path_win32[] =
342         {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
343           'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',0};
344     static const WCHAR path_dotnet[] =
345         {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
346          'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',0};
347     static const WCHAR classes_path_win32[] =
348         {'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',0};
349     static const WCHAR classes_path_dotnet[] =
350         {'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',0};
351     HKEY root;
352     const WCHAR *path;
353
354     if (context == MSIINSTALLCONTEXT_MACHINE)
355     {
356         root = HKEY_CLASSES_ROOT;
357         if (win32) path = classes_path_win32;
358         else path = classes_path_dotnet;
359     }
360     else
361     {
362         root = HKEY_CURRENT_USER;
363         if (win32) path = path_win32;
364         else path = path_dotnet;
365     }
366     return RegCreateKeyW( root, path, hkey );
367 }
368
369 static LONG open_local_assembly_key( UINT context, BOOL win32, const WCHAR *filename, HKEY *hkey )
370 {
371     LONG res;
372     HKEY root;
373     WCHAR *path;
374
375     if (!(path = build_local_assembly_path( filename )))
376         return ERROR_OUTOFMEMORY;
377
378     if ((res = open_assemblies_key( context, win32, &root )))
379     {
380         msi_free( path );
381         return res;
382     }
383     res = RegCreateKeyW( root, path, hkey );
384     RegCloseKey( root );
385     msi_free( path );
386     return res;
387 }
388
389 static LONG delete_local_assembly_key( UINT context, BOOL win32, const WCHAR *filename )
390 {
391     LONG res;
392     HKEY root;
393     WCHAR *path;
394
395     if (!(path = build_local_assembly_path( filename )))
396         return ERROR_OUTOFMEMORY;
397
398     if ((res = open_assemblies_key( context, win32, &root )))
399     {
400         msi_free( path );
401         return res;
402     }
403     res = RegDeleteKeyW( root, path );
404     RegCloseKey( root );
405     msi_free( path );
406     return res;
407 }
408
409 static LONG open_global_assembly_key( UINT context, BOOL win32, HKEY *hkey )
410 {
411     static const WCHAR path_win32[] =
412         {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
413          'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',
414          'G','l','o','b','a','l',0};
415     static const WCHAR path_dotnet[] =
416         {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
417          'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',
418          'G','l','o','b','a','l',0};
419     static const WCHAR classes_path_win32[] =
420         {'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',
421          'G','l','o','b','a','l',0};
422     static const WCHAR classes_path_dotnet[] =
423         {'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\','G','l','o','b','a','l',0};
424     HKEY root;
425     const WCHAR *path;
426
427     if (context == MSIINSTALLCONTEXT_MACHINE)
428     {
429         root = HKEY_CLASSES_ROOT;
430         if (win32) path = classes_path_win32;
431         else path = classes_path_dotnet;
432     }
433     else
434     {
435         root = HKEY_CURRENT_USER;
436         if (win32) path = path_win32;
437         else path = path_dotnet;
438     }
439     return RegCreateKeyW( root, path, hkey );
440 }
441
442 UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
443 {
444     MSICOMPONENT *comp;
445
446     LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
447     {
448         LONG res;
449         HKEY hkey;
450         GUID guid;
451         DWORD size;
452         WCHAR buffer[43];
453         MSIRECORD *uirow;
454         MSIASSEMBLY *assembly = comp->assembly;
455         BOOL win32;
456
457         if (!assembly || !comp->ComponentId) continue;
458
459         if (!comp->Enabled)
460         {
461             TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
462             continue;
463         }
464
465         if (comp->ActionRequest != INSTALLSTATE_LOCAL)
466         {
467             TRACE("Component not scheduled for installation: %s\n", debugstr_w(comp->Component));
468             comp->Action = comp->Installed;
469             continue;
470         }
471         comp->Action = INSTALLSTATE_LOCAL;
472
473         TRACE("publishing %s\n", debugstr_w(comp->Component));
474
475         CLSIDFromString( package->ProductCode, &guid );
476         encode_base85_guid( &guid, buffer );
477         buffer[20] = '>';
478         CLSIDFromString( comp->ComponentId, &guid );
479         encode_base85_guid( &guid, buffer + 21 );
480         buffer[42] = 0;
481
482         win32 = assembly->attributes & msidbAssemblyAttributesWin32;
483         if (assembly->application)
484         {
485             MSIFILE *file = get_loaded_file( package, assembly->application );
486             if ((res = open_local_assembly_key( package->Context, win32, file->TargetPath, &hkey )))
487             {
488                 WARN("failed to open local assembly key %d\n", res);
489                 return ERROR_FUNCTION_FAILED;
490             }
491         }
492         else
493         {
494             if ((res = open_global_assembly_key( package->Context, win32, &hkey )))
495             {
496                 WARN("failed to open global assembly key %d\n", res);
497                 return ERROR_FUNCTION_FAILED;
498             }
499         }
500         size = sizeof(buffer);
501         if ((res = RegSetValueExW( hkey, assembly->display_name, 0, REG_MULTI_SZ, (const BYTE *)buffer, size )))
502         {
503             WARN("failed to set assembly value %d\n", res);
504         }
505         RegCloseKey( hkey );
506
507         uirow = MSI_CreateRecord( 2 );
508         MSI_RecordSetStringW( uirow, 2, assembly->display_name );
509         ui_actiondata( package, szMsiPublishAssemblies, uirow );
510         msiobj_release( &uirow->hdr );
511     }
512     return ERROR_SUCCESS;
513 }
514
515 UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
516 {
517     MSICOMPONENT *comp;
518
519     LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
520     {
521         LONG res;
522         MSIRECORD *uirow;
523         MSIASSEMBLY *assembly = comp->assembly;
524         BOOL win32;
525
526         if (!assembly || !comp->ComponentId) continue;
527
528         if (!comp->Enabled)
529         {
530             TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
531             continue;
532         }
533
534         if (comp->ActionRequest != INSTALLSTATE_ABSENT)
535         {
536             TRACE("Component not scheduled for removal: %s\n", debugstr_w(comp->Component));
537             comp->Action = comp->Installed;
538             continue;
539         }
540         comp->Action = INSTALLSTATE_ABSENT;
541
542         TRACE("unpublishing %s\n", debugstr_w(comp->Component));
543
544         win32 = assembly->attributes & msidbAssemblyAttributesWin32;
545         if (assembly->application)
546         {
547             MSIFILE *file = get_loaded_file( package, assembly->application );
548             if ((res = delete_local_assembly_key( package->Context, win32, file->TargetPath )))
549                 WARN("failed to delete local assembly key %d\n", res);
550         }
551         else
552         {
553             HKEY hkey;
554             if ((res = open_global_assembly_key( package->Context, win32, &hkey )))
555                 WARN("failed to delete global assembly key %d\n", res);
556             else
557             {
558                 if ((res = RegDeleteValueW( hkey, assembly->display_name )))
559                     WARN("failed to delete global assembly value %d\n", res);
560                 RegCloseKey( hkey );
561             }
562         }
563
564         uirow = MSI_CreateRecord( 2 );
565         MSI_RecordSetStringW( uirow, 2, assembly->display_name );
566         ui_actiondata( package, szMsiPublishAssemblies, uirow );
567         msiobj_release( &uirow->hdr );
568     }
569     return ERROR_SUCCESS;
570 }