Moved mciavi32 to the top-level dlls directory.
[wine] / dlls / msi / classes.c
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2005 Aric Stewart 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 /* actions handled in this module
22  * RegisterClassInfo
23  * RegisterProgIdInfo
24  * RegisterExtensionInfo
25  * RegisterMIMEInfo
26  * UnRegisterClassInfo (TODO)
27  * UnRegisterProgIdInfo (TODO)
28  * UnRegisterExtensionInfo (TODO)
29  * UnRegisterMIMEInfo (TODO)
30  */
31
32 #include <stdarg.h>
33
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "winreg.h"
38 #include "wine/debug.h"
39 #include "msipriv.h"
40 #include "winuser.h"
41 #include "wine/unicode.h"
42 #include "action.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(msi);
45
46
47 extern const WCHAR szRegisterClassInfo[];
48 extern const WCHAR szRegisterProgIdInfo[];
49 extern const WCHAR szRegisterExtensionInfo[];
50 extern const WCHAR szRegisterMIMEInfo[];
51
52 extern const WCHAR szUnregisterClassInfo[];
53 extern const WCHAR szUnregisterExtensionInfo[];
54 extern const WCHAR szUnregisterMIMEInfo[];
55 extern const WCHAR szUnregisterProgIdInfo[];
56
57 static INT load_appid(MSIPACKAGE* package, MSIRECORD *row)
58 {
59     DWORD index = package->loaded_appids;
60     DWORD sz;
61     LPCWSTR buffer;
62
63     /* fill in the data */
64
65     package->loaded_appids++;
66     if (package->loaded_appids == 1)
67         package->appids = HeapAlloc(GetProcessHeap(),0,sizeof(MSIAPPID));
68     else
69         package->appids = HeapReAlloc(GetProcessHeap(),0,
70             package->appids, package->loaded_appids * sizeof(MSIAPPID));
71
72     memset(&package->appids[index],0,sizeof(MSIAPPID));
73     
74     sz = IDENTIFIER_SIZE;
75     MSI_RecordGetStringW(row, 1, package->appids[index].AppID, &sz);
76     TRACE("loading appid %s\n",debugstr_w(package->appids[index].AppID));
77
78     buffer = MSI_RecordGetString(row,2);
79     deformat_string(package,buffer,&package->appids[index].RemoteServerName);
80
81     package->appids[index].LocalServer = load_dynamic_stringW(row,3);
82     package->appids[index].ServiceParameters = load_dynamic_stringW(row,4);
83     package->appids[index].DllSurrogate = load_dynamic_stringW(row,5);
84
85     package->appids[index].ActivateAtStorage = !MSI_RecordIsNull(row,6);
86     package->appids[index].RunAsInteractiveUser = !MSI_RecordIsNull(row,7);
87     
88     return index;
89 }
90
91 static INT load_given_appid(MSIPACKAGE *package, LPCWSTR appid)
92 {
93     INT rc;
94     MSIRECORD *row;
95     INT i;
96     static const WCHAR ExecSeqQuery[] =
97         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
98          '`','A','p','p','I','d','`',' ','W','H','E','R','E',' ',
99          '`','A','p','p','I','d','`',' ','=',' ','\'','%','s','\'',0};
100
101     if (!appid)
102         return -1;
103
104     /* check for appids already loaded */
105     for (i = 0; i < package->loaded_appids; i++)
106         if (strcmpiW(package->appids[i].AppID,appid)==0)
107         {
108             TRACE("found appid %s at index %i\n",debugstr_w(appid),i);
109             return i;
110         }
111     
112     row = MSI_QueryGetRecord(package->db, ExecSeqQuery, appid);
113     if (!row)
114         return -1;
115
116     rc = load_appid(package, row);
117     msiobj_release(&row->hdr);
118
119     return rc;
120 }
121
122 static INT load_given_progid(MSIPACKAGE *package, LPCWSTR progid);
123 static INT load_given_class(MSIPACKAGE *package, LPCWSTR classid);
124
125 static INT load_progid(MSIPACKAGE* package, MSIRECORD *row)
126 {
127     DWORD index = package->loaded_progids;
128     LPCWSTR buffer;
129
130     /* fill in the data */
131
132     package->loaded_progids++;
133     if (package->loaded_progids == 1)
134         package->progids = HeapAlloc(GetProcessHeap(),0,sizeof(MSIPROGID));
135     else
136         package->progids = HeapReAlloc(GetProcessHeap(),0,
137             package->progids , package->loaded_progids * sizeof(MSIPROGID));
138
139     memset(&package->progids[index],0,sizeof(MSIPROGID));
140
141     package->progids[index].ProgID = load_dynamic_stringW(row,1);
142     TRACE("loading progid %s\n",debugstr_w(package->progids[index].ProgID));
143
144     buffer = MSI_RecordGetString(row,2);
145     package->progids[index].ParentIndex = load_given_progid(package,buffer);
146     if (package->progids[index].ParentIndex < 0 && buffer)
147         FIXME("Unknown parent ProgID %s\n",debugstr_w(buffer));
148
149     buffer = MSI_RecordGetString(row,3);
150     package->progids[index].ClassIndex = load_given_class(package,buffer);
151     if (package->progids[index].ClassIndex< 0 && buffer)
152         FIXME("Unknown class %s\n",debugstr_w(buffer));
153
154     package->progids[index].Description = load_dynamic_stringW(row,4);
155
156     if (!MSI_RecordIsNull(row,6))
157     {
158         INT icon_index = MSI_RecordGetInteger(row,6); 
159         LPWSTR FileName = load_dynamic_stringW(row,5);
160         LPWSTR FilePath;
161         static const WCHAR fmt[] = {'%','s',',','%','i',0};
162
163         build_icon_path(package,FileName,&FilePath);
164        
165         package->progids[index].IconPath = 
166                 HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+10)*
167                                 sizeof(WCHAR));
168
169         sprintfW(package->progids[index].IconPath,fmt,FilePath,icon_index);
170
171         HeapFree(GetProcessHeap(),0,FilePath);
172         HeapFree(GetProcessHeap(),0,FileName);
173     }
174     else
175     {
176         buffer = MSI_RecordGetString(row,5);
177         if (buffer)
178             build_icon_path(package,buffer,&(package->progids[index].IconPath));
179     }
180
181     package->progids[index].CurVerIndex = -1;
182     package->progids[index].VersionIndIndex = -1;
183
184     /* if we have a parent then we may be that parents CurVer */
185     if (package->progids[index].ParentIndex >= 0 && 
186         package->progids[index].ParentIndex != index)
187     {
188         int pindex = package->progids[index].ParentIndex;
189         while (package->progids[pindex].ParentIndex>= 0 && 
190                package->progids[pindex].ParentIndex != pindex)
191             pindex = package->progids[pindex].ParentIndex;
192
193         FIXME("BAD BAD need to determing if we are really the CurVer\n");
194
195         package->progids[index].CurVerIndex = pindex;
196         package->progids[pindex].VersionIndIndex = index;
197     }
198     
199     return index;
200 }
201
202 static INT load_given_progid(MSIPACKAGE *package, LPCWSTR progid)
203 {
204     INT rc;
205     MSIRECORD *row;
206     INT i;
207     static const WCHAR ExecSeqQuery[] =
208         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
209          '`','P','r','o','g','I','d','`',' ','W','H','E','R','E',' ',
210          '`','P','r','o','g','I','d','`',' ','=',' ','\'','%','s','\'',0};
211
212     if (!progid)
213         return -1;
214
215     /* check for progids already loaded */
216     for (i = 0; i < package->loaded_progids; i++)
217         if (strcmpiW(package->progids[i].ProgID,progid)==0)
218         {
219             TRACE("found progid %s at index %i\n",debugstr_w(progid), i);
220             return i;
221         }
222     
223     row = MSI_QueryGetRecord(package->db, ExecSeqQuery, progid);
224     if(!row)
225         return -1;
226
227     rc = load_progid(package, row);
228     msiobj_release(&row->hdr);
229
230     return rc;
231 }
232
233 static INT load_class(MSIPACKAGE* package, MSIRECORD *row)
234 {
235     DWORD index = package->loaded_classes;
236     DWORD sz,i;
237     LPCWSTR buffer;
238
239     /* fill in the data */
240
241     package->loaded_classes++;
242     if (package->loaded_classes== 1)
243         package->classes = HeapAlloc(GetProcessHeap(),0,sizeof(MSICLASS));
244     else
245         package->classes = HeapReAlloc(GetProcessHeap(),0,
246             package->classes, package->loaded_classes * sizeof(MSICLASS));
247
248     memset(&package->classes[index],0,sizeof(MSICLASS));
249
250     sz = IDENTIFIER_SIZE;
251     MSI_RecordGetStringW(row, 1, package->classes[index].CLSID, &sz);
252     TRACE("loading class %s\n",debugstr_w(package->classes[index].CLSID));
253     sz = IDENTIFIER_SIZE;
254     MSI_RecordGetStringW(row, 2, package->classes[index].Context, &sz);
255     buffer = MSI_RecordGetString(row,3);
256     package->classes[index].Component = get_loaded_component(package, buffer);
257
258     package->classes[index].ProgIDText = load_dynamic_stringW(row,4);
259     package->classes[index].ProgIDIndex = 
260                 load_given_progid(package, package->classes[index].ProgIDText);
261
262     package->classes[index].Description = load_dynamic_stringW(row,5);
263
264     buffer = MSI_RecordGetString(row,6);
265     if (buffer)
266         package->classes[index].AppIDIndex = 
267                 load_given_appid(package, buffer);
268     else
269         package->classes[index].AppIDIndex = -1;
270
271     package->classes[index].FileTypeMask = load_dynamic_stringW(row,7);
272
273     if (!MSI_RecordIsNull(row,9))
274     {
275
276         INT icon_index = MSI_RecordGetInteger(row,9); 
277         LPWSTR FileName = load_dynamic_stringW(row,8);
278         LPWSTR FilePath;
279         static const WCHAR fmt[] = {'%','s',',','%','i',0};
280
281         build_icon_path(package,FileName,&FilePath);
282        
283         package->classes[index].IconPath = 
284                 HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+5)*
285                                 sizeof(WCHAR));
286
287         sprintfW(package->classes[index].IconPath,fmt,FilePath,icon_index);
288
289         HeapFree(GetProcessHeap(),0,FilePath);
290         HeapFree(GetProcessHeap(),0,FileName);
291     }
292     else
293     {
294         buffer = MSI_RecordGetString(row,8);
295         if (buffer)
296             build_icon_path(package,buffer,&(package->classes[index].IconPath));
297     }
298
299     if (!MSI_RecordIsNull(row,10))
300     {
301         i = MSI_RecordGetInteger(row,10);
302         if (i != MSI_NULL_INTEGER && i > 0 &&  i < 4)
303         {
304             static const WCHAR ole2[] = {'o','l','e','2','.','d','l','l',0};
305             static const WCHAR ole32[] = {'o','l','e','3','2','.','d','l','l',0};
306
307             switch(i)
308             {
309                 case 1:
310                     package->classes[index].DefInprocHandler = strdupW(ole2);
311                     break;
312                 case 2:
313                     package->classes[index].DefInprocHandler32 = strdupW(ole32);
314                     break;
315                 case 3:
316                     package->classes[index].DefInprocHandler = strdupW(ole2);
317                     package->classes[index].DefInprocHandler32 = strdupW(ole32);
318                     break;
319             }
320         }
321         else
322         {
323             package->classes[index].DefInprocHandler32 = load_dynamic_stringW(
324                             row, 10);
325             reduce_to_longfilename(package->classes[index].DefInprocHandler32);
326         }
327     }
328     buffer = MSI_RecordGetString(row,11);
329     deformat_string(package,buffer,&package->classes[index].Argument);
330
331     buffer = MSI_RecordGetString(row,12);
332     package->classes[index].Feature = get_loaded_feature(package,buffer);
333
334     package->classes[index].Attributes = MSI_RecordGetInteger(row,13);
335     
336     return index;
337 }
338
339 /*
340  * the Class table has 3 primary keys. Generally it is only 
341  * referenced through the first CLSID key. However when loading
342  * all of the classes we need to make sure we do not ignore rows
343  * with other Context and ComponentIndexs 
344  */
345 static INT load_given_class(MSIPACKAGE *package, LPCWSTR classid)
346 {
347     INT rc;
348     MSIRECORD *row;
349     INT i;
350     static const WCHAR ExecSeqQuery[] =
351         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
352          '`','C','l','a','s','s','`',' ','W','H','E','R','E',' ',
353          '`','C','L','S','I','D','`',' ','=',' ','\'','%','s','\'',0};
354
355
356     if (!classid)
357         return -1;
358     
359     /* check for classes already loaded */
360     for (i = 0; i < package->loaded_classes; i++)
361         if (strcmpiW(package->classes[i].CLSID,classid)==0)
362         {
363             TRACE("found class %s at index %i\n",debugstr_w(classid), i);
364             return i;
365         }
366     
367     row = MSI_QueryGetRecord(package->db, ExecSeqQuery, classid);
368     if (!row)
369         return -1;
370
371     rc = load_class(package, row);
372     msiobj_release(&row->hdr);
373
374     return rc;
375 }
376
377 static INT load_given_extension(MSIPACKAGE *package, LPCWSTR extension);
378
379 static INT load_mime(MSIPACKAGE* package, MSIRECORD *row)
380 {
381     DWORD index = package->loaded_mimes;
382     DWORD sz;
383     LPCWSTR buffer;
384
385     /* fill in the data */
386
387     package->loaded_mimes++;
388     if (package->loaded_mimes== 1)
389         package->mimes= HeapAlloc(GetProcessHeap(),0,sizeof(MSIMIME));
390     else
391         package->mimes= HeapReAlloc(GetProcessHeap(),0,
392             package->mimes, package->loaded_mimes* 
393             sizeof(MSIMIME));
394
395     memset(&package->mimes[index],0,sizeof(MSIMIME));
396
397     package->mimes[index].ContentType = load_dynamic_stringW(row,1); 
398     TRACE("loading mime %s\n",debugstr_w(package->mimes[index].ContentType));
399
400     buffer = MSI_RecordGetString(row,2);
401     package->mimes[index].ExtensionIndex = load_given_extension(package,
402                     buffer);
403
404     sz = IDENTIFIER_SIZE;
405     MSI_RecordGetStringW(row,3,package->mimes[index].CLSID,&sz);
406     package->mimes[index].ClassIndex= load_given_class(package,
407                     package->mimes[index].CLSID);
408     
409     return index;
410 }
411
412 static INT load_given_mime(MSIPACKAGE *package, LPCWSTR mime)
413 {
414     INT rc;
415     MSIRECORD *row;
416     INT i;
417     static const WCHAR ExecSeqQuery[] =
418         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
419          '`','M','I','M','E','`',' ','W','H','E','R','E',' ',
420          '`','C','o','n','t','e','n','t','T','y','p','e','`',' ','=',' ',
421          '\'','%','s','\'',0};
422
423     if (!mime)
424         return -1;
425     
426     /* check for mime already loaded */
427     for (i = 0; i < package->loaded_mimes; i++)
428         if (strcmpiW(package->mimes[i].ContentType,mime)==0)
429         {
430             TRACE("found mime %s at index %i\n",debugstr_w(mime), i);
431             return i;
432         }
433     
434     row = MSI_QueryGetRecord(package->db, ExecSeqQuery, mime);
435     if (!row)
436         return -1;
437
438     rc = load_mime(package, row);
439     msiobj_release(&row->hdr);
440
441     return rc;
442 }
443
444 static INT load_extension(MSIPACKAGE* package, MSIRECORD *row)
445 {
446     DWORD index = package->loaded_extensions;
447     DWORD sz;
448     LPCWSTR buffer;
449
450     /* fill in the data */
451
452     package->loaded_extensions++;
453     if (package->loaded_extensions == 1)
454         package->extensions = HeapAlloc(GetProcessHeap(),0,sizeof(MSIEXTENSION));
455     else
456         package->extensions = HeapReAlloc(GetProcessHeap(),0,
457             package->extensions, package->loaded_extensions* 
458             sizeof(MSIEXTENSION));
459
460     memset(&package->extensions[index],0,sizeof(MSIEXTENSION));
461
462     sz = 256;
463     MSI_RecordGetStringW(row,1,package->extensions[index].Extension,&sz);
464     TRACE("loading extension %s\n",
465                     debugstr_w(package->extensions[index].Extension));
466
467     buffer = MSI_RecordGetString(row,2);
468     package->extensions[index].Component = get_loaded_component(package,buffer);
469
470     package->extensions[index].ProgIDText = load_dynamic_stringW(row,3);
471     package->extensions[index].ProgIDIndex = load_given_progid(package,
472                     package->extensions[index].ProgIDText);
473
474     buffer = MSI_RecordGetString(row,4);
475     package->extensions[index].MIMEIndex = load_given_mime(package,buffer);
476
477     buffer = MSI_RecordGetString(row,5);
478     package->extensions[index].Feature = get_loaded_feature(package,buffer);
479
480     return index;
481 }
482
483 /*
484  * While the extension table has 2 primary keys, this function is only looking
485  * at the Extension key which is what is referenced as a forign key 
486  */
487 static INT load_given_extension(MSIPACKAGE *package, LPCWSTR extension)
488 {
489     INT rc;
490     MSIRECORD *row;
491     INT i;
492     static const WCHAR ExecSeqQuery[] =
493         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
494          '`','E','x','t','e','n','s','i','o','n','`',' ',
495          'W','H','E','R','E',' ',
496          '`','E','x','t','e','n','s','i','o','n','`',' ','=',' ',
497          '\'','%','s','\'',0};
498
499     if (!extension)
500         return -1;
501
502     /* check for extensions already loaded */
503     for (i = 0; i < package->loaded_extensions; i++)
504         if (strcmpiW(package->extensions[i].Extension,extension)==0)
505         {
506             TRACE("extension %s already loaded at %i\n",debugstr_w(extension),
507                             i);
508             return i;
509         }
510     
511     row = MSI_QueryGetRecord(package->db, ExecSeqQuery, extension);
512     if (!row)
513         return -1;
514
515     rc = load_extension(package, row);
516     msiobj_release(&row->hdr);
517
518     return rc;
519 }
520
521 static UINT iterate_load_verb(MSIRECORD *row, LPVOID param)
522 {
523     MSIPACKAGE* package = (MSIPACKAGE*)param;
524     DWORD index = package->loaded_verbs;
525     LPCWSTR buffer;
526
527     /* fill in the data */
528
529     package->loaded_verbs++;
530     if (package->loaded_verbs == 1)
531         package->verbs = HeapAlloc(GetProcessHeap(),0,sizeof(MSIVERB));
532     else
533         package->verbs = HeapReAlloc(GetProcessHeap(),0,
534             package->verbs , package->loaded_verbs * sizeof(MSIVERB));
535
536     memset(&package->verbs[index],0,sizeof(MSIVERB));
537
538     buffer = MSI_RecordGetString(row,1);
539     package->verbs[index].ExtensionIndex = load_given_extension(package,buffer);
540     if (package->verbs[index].ExtensionIndex < 0 && buffer)
541         ERR("Verb unable to find loaded extension %s\n", debugstr_w(buffer));
542
543     package->verbs[index].Verb = load_dynamic_stringW(row,2);
544     TRACE("loading verb %s\n",debugstr_w(package->verbs[index].Verb));
545     package->verbs[index].Sequence = MSI_RecordGetInteger(row,3);
546
547     buffer = MSI_RecordGetString(row,4);
548     deformat_string(package,buffer,&package->verbs[index].Command);
549
550     buffer = MSI_RecordGetString(row,5);
551     deformat_string(package,buffer,&package->verbs[index].Argument);
552
553     /* assosiate the verb with the correct extension */
554     if (package->verbs[index].ExtensionIndex >= 0)
555     {
556         MSIEXTENSION* extension = &package->extensions[package->verbs[index].
557                 ExtensionIndex];
558         int count = extension->VerbCount;
559
560         if (count >= 99)
561             FIXME("Exceeding max verb count! Increase that limit!!!\n");
562         else
563         {
564             extension->VerbCount++;
565             extension->Verbs[count] = index;
566         }
567     }
568     
569     return ERROR_SUCCESS;
570 }
571
572 static UINT iterate_all_classes(MSIRECORD *rec, LPVOID param)
573 {
574     MSICOMPONENT *comp;
575     LPCWSTR clsid;
576     LPCWSTR context;
577     LPCWSTR buffer;
578     MSIPACKAGE* package =(MSIPACKAGE*)param;
579     INT i;
580     BOOL match = FALSE;
581
582     clsid = MSI_RecordGetString(rec,1);
583     context = MSI_RecordGetString(rec,2);
584     buffer = MSI_RecordGetString(rec,3);
585     comp = get_loaded_component(package,buffer);
586
587     for (i = 0; i < package->loaded_classes; i++)
588     {
589         if (strcmpiW(clsid,package->classes[i].CLSID))
590             continue;
591         if (strcmpW(context,package->classes[i].Context))
592             continue;
593         if (comp == package->classes[i].Component)
594         {
595             match = TRUE;
596             break;
597         }
598     }
599     
600     if (!match)
601         load_class(package, rec);
602
603     return ERROR_SUCCESS;
604 }
605
606 static VOID load_all_classes(MSIPACKAGE *package)
607 {
608     UINT rc = ERROR_SUCCESS;
609     MSIQUERY *view;
610
611     static const WCHAR ExecSeqQuery[] =
612         {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
613          '`','C','l','a','s','s','`',0};
614
615     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
616     if (rc != ERROR_SUCCESS)
617         return;
618
619     rc = MSI_IterateRecords(view, NULL, iterate_all_classes, package);
620     msiobj_release(&view->hdr);
621 }
622
623 static UINT iterate_all_extensions(MSIRECORD *rec, LPVOID param)
624 {
625     MSICOMPONENT *comp;
626     LPCWSTR buffer;
627     LPCWSTR extension;
628     MSIPACKAGE* package =(MSIPACKAGE*)param;
629     BOOL match = FALSE;
630     INT i;
631
632     extension = MSI_RecordGetString(rec,1);
633     buffer = MSI_RecordGetString(rec,2);
634     comp = get_loaded_component(package,buffer);
635
636     for (i = 0; i < package->loaded_extensions; i++)
637     {
638         if (strcmpiW(extension,package->extensions[i].Extension))
639             continue;
640         if (comp == package->extensions[i].Component)
641         {
642             match = TRUE;
643             break;
644         }
645     }
646
647     if (!match)
648         load_extension(package, rec);
649
650     return ERROR_SUCCESS;
651 }
652
653 static VOID load_all_extensions(MSIPACKAGE *package)
654 {
655     UINT rc = ERROR_SUCCESS;
656     MSIQUERY *view;
657
658     static const WCHAR ExecSeqQuery[] =
659         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
660          '`','E','x','t','e','n','s','i','o','n','`',0};
661
662     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
663     if (rc != ERROR_SUCCESS)
664         return;
665
666     rc = MSI_IterateRecords(view, NULL, iterate_all_extensions, package);
667     msiobj_release(&view->hdr);
668 }
669
670 static UINT iterate_all_progids(MSIRECORD *rec, LPVOID param)
671 {
672     LPCWSTR buffer;
673     MSIPACKAGE* package =(MSIPACKAGE*)param;
674
675     buffer = MSI_RecordGetString(rec,1);
676     load_given_progid(package,buffer);
677     return ERROR_SUCCESS;
678 }
679
680 static VOID load_all_progids(MSIPACKAGE *package)
681 {
682     UINT rc = ERROR_SUCCESS;
683     MSIQUERY *view;
684
685     static const WCHAR ExecSeqQuery[] =
686         {'S','E','L','E','C','T',' ','`','P','r','o','g','I','d','`',' ',
687          'F','R','O','M',' ', '`','P','r','o','g','I','d','`',0};
688
689     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
690     if (rc != ERROR_SUCCESS)
691         return;
692
693     rc = MSI_IterateRecords(view, NULL, iterate_all_progids, package);
694     msiobj_release(&view->hdr);
695 }
696
697 static VOID load_all_verbs(MSIPACKAGE *package)
698 {
699     UINT rc = ERROR_SUCCESS;
700     MSIQUERY *view;
701
702     static const WCHAR ExecSeqQuery[] =
703         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
704          '`','V','e','r','b','`',0};
705
706     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
707     if (rc != ERROR_SUCCESS)
708         return;
709
710     rc = MSI_IterateRecords(view, NULL, iterate_load_verb, package);
711     msiobj_release(&view->hdr);
712 }
713
714 static UINT iterate_all_mimes(MSIRECORD *rec, LPVOID param)
715 {
716     LPCWSTR buffer;
717     MSIPACKAGE* package =(MSIPACKAGE*)param;
718
719     buffer = MSI_RecordGetString(rec,1);
720     load_given_mime(package,buffer);
721     return ERROR_SUCCESS;
722 }
723
724 static VOID load_all_mimes(MSIPACKAGE *package)
725 {
726     UINT rc = ERROR_SUCCESS;
727     MSIQUERY *view;
728
729     static const WCHAR ExecSeqQuery[] =
730         {'S','E','L','E','C','T',' ',
731          '`','C','o','n','t','e','n','t','T','y','p','e','`',
732          ' ','F','R','O','M',' ',
733          '`','M','I','M','E','`',0};
734
735     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
736     if (rc != ERROR_SUCCESS)
737         return;
738
739     rc = MSI_IterateRecords(view, NULL, iterate_all_mimes, package);
740     msiobj_release(&view->hdr);
741 }
742
743 static void load_classes_and_such(MSIPACKAGE *package)
744 {
745     TRACE("Loading all the class info and related tables\n");
746
747     /* check if already loaded */
748     if (package->classes || package->extensions || package->progids || 
749         package->verbs || package->mimes)
750         return;
751
752     load_all_classes(package);
753     load_all_extensions(package);
754     load_all_progids(package);
755     /* these loads must come after the other loads */
756     load_all_verbs(package);
757     load_all_mimes(package);
758 }
759
760 static void mark_progid_for_install(MSIPACKAGE* package, INT index)
761 {
762     MSIPROGID* progid;
763     int i;
764
765     if (index < 0 || index >= package->loaded_progids)
766         return;
767
768     progid = &package->progids[index];
769
770     if (progid->InstallMe == TRUE)
771         return;
772
773     progid->InstallMe = TRUE;
774
775     /* all children if this is a parent also install */
776    for (i = 0; i < package->loaded_progids; i++)
777         if (package->progids[i].ParentIndex == index)
778             mark_progid_for_install(package,i);
779 }
780
781 static void mark_mime_for_install(MSIPACKAGE* package, INT index)
782 {
783     MSIMIME* mime;
784
785     if (index < 0 || index >= package->loaded_mimes)
786         return;
787
788     mime = &package->mimes[index];
789
790     if (mime->InstallMe == TRUE)
791         return;
792
793     mime->InstallMe = TRUE;
794 }
795
796 static UINT register_appid(MSIPACKAGE *package, int appidIndex, LPCWSTR app )
797 {
798     static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
799     HKEY hkey2,hkey3;
800
801     if (!package)
802         return ERROR_INVALID_HANDLE;
803
804     RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);
805     RegCreateKeyW(hkey2,package->appids[appidIndex].AppID,&hkey3);
806     RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app,
807                    (strlenW(app)+1)*sizeof(WCHAR));
808
809     if (package->appids[appidIndex].RemoteServerName)
810     {
811         UINT size; 
812         static const WCHAR szRemoteServerName[] =
813              {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',
814               0};
815
816         size = (strlenW(package->appids[appidIndex].RemoteServerName)+1) * 
817                 sizeof(WCHAR);
818
819         RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,
820                         (LPVOID)package->appids[appidIndex].RemoteServerName,
821                         size);
822     }
823
824     if (package->appids[appidIndex].LocalServer)
825     {
826         static const WCHAR szLocalService[] =
827              {'L','o','c','a','l','S','e','r','v','i','c','e',0};
828         UINT size;
829         size = (strlenW(package->appids[appidIndex].LocalServer)+1) * 
830                 sizeof(WCHAR);
831
832         RegSetValueExW(hkey3,szLocalService,0,REG_SZ,
833                         (LPVOID)package->appids[appidIndex].LocalServer,size);
834     }
835
836     if (package->appids[appidIndex].ServiceParameters)
837     {
838         static const WCHAR szService[] =
839              {'S','e','r','v','i','c','e',
840               'P','a','r','a','m','e','t','e','r','s',0};
841         UINT size;
842         size = (strlenW(package->appids[appidIndex].ServiceParameters)+1) * 
843                 sizeof(WCHAR);
844         RegSetValueExW(hkey3,szService,0,REG_SZ,
845                         (LPVOID)package->appids[appidIndex].ServiceParameters,
846                         size);
847     }
848
849     if (package->appids[appidIndex].DllSurrogate)
850     {
851         static const WCHAR szDLL[] =
852              {'D','l','l','S','u','r','r','o','g','a','t','e',0};
853         UINT size;
854         size = (strlenW(package->appids[appidIndex].DllSurrogate)+1) * 
855                 sizeof(WCHAR);
856         RegSetValueExW(hkey3,szDLL,0,REG_SZ,
857                         (LPVOID)package->appids[appidIndex].DllSurrogate,size);
858     }
859
860     if (package->appids[appidIndex].ActivateAtStorage)
861     {
862         static const WCHAR szActivate[] =
863              {'A','c','t','i','v','a','t','e','A','s',
864               'S','t','o','r','a','g','e',0};
865         static const WCHAR szY[] = {'Y',0};
866
867         RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4);
868     }
869
870     if (package->appids[appidIndex].RunAsInteractiveUser)
871     {
872         static const WCHAR szRunAs[] = {'R','u','n','A','s',0};
873         static const WCHAR szUser[] = 
874              {'I','n','t','e','r','a','c','t','i','v','e',' ',
875               'U','s','e','r',0};
876
877         RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,sizeof(szUser));
878     }
879
880     RegCloseKey(hkey3);
881     RegCloseKey(hkey2);
882     return ERROR_SUCCESS;
883 }
884
885 UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
886 {
887     /* 
888      * Again I am assuming the words, "Whose key file represents" when referring
889      * to a Component as to meaning that Components KeyPath file
890      */
891     
892     UINT rc;
893     MSIRECORD *uirow;
894     static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
895     static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 };
896     static const WCHAR szVIProgID[] = { 'V','e','r','s','i','o','n','I','n','d','e','p','e','n','d','e','n','t','P','r','o','g','I','D',0 };
897     static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
898     static const WCHAR szSpace[] = {' ',0};
899     static const WCHAR szInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
900     static const WCHAR szFileType_fmt[] = {'F','i','l','e','T','y','p','e','\\','%','s','\\','%','i',0};
901     HKEY hkey,hkey2,hkey3;
902     BOOL install_on_demand = FALSE;
903     int i;
904
905     if (!package)
906         return ERROR_INVALID_HANDLE;
907
908     load_classes_and_such(package);
909     rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);
910     if (rc != ERROR_SUCCESS)
911         return ERROR_FUNCTION_FAILED;
912
913     /* install_on_demand should be set if OLE supports install on demand OLE
914      * servers. For now i am defaulting to FALSE because i do not know how to
915      * check, and i am told our builtin OLE does not support it
916      */
917     
918     for (i = 0; i < package->loaded_classes; i++)
919     {
920         MSICOMPONENT *comp;
921         MSIFILE *file;
922         DWORD size, sz;
923         LPWSTR argument;
924         MSIFEATURE *feature;
925
926         comp = package->classes[i].Component;
927         if ( !comp )
928             continue;
929
930         feature = package->classes[i].Feature;
931
932         /* 
933          * yes. MSDN says that these are based on _Feature_ not on
934          * Component.  So verify the feature is to be installed
935          */
936         if ((!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL )) &&
937              !(install_on_demand &&
938                ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED )))
939         {
940             TRACE("Skipping class %s reg due to disabled feature %s\n", 
941                             debugstr_w(package->classes[i].CLSID), 
942                             debugstr_w(feature->Feature));
943
944             continue;
945         }
946
947         TRACE("Registering index %i  class %s\n",i,
948                         debugstr_w(package->classes[i].CLSID));
949
950         package->classes[i].Installed = TRUE;
951         if (package->classes[i].ProgIDIndex >= 0)
952             mark_progid_for_install(package, package->classes[i].ProgIDIndex);
953
954         RegCreateKeyW(hkey,package->classes[i].CLSID,&hkey2);
955
956         if (package->classes[i].Description)
957             RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)package->classes[i].
958                             Description, (strlenW(package->classes[i].
959                                      Description)+1)*sizeof(WCHAR));
960
961         RegCreateKeyW(hkey2,package->classes[i].Context,&hkey3);
962         file = get_loaded_file( package, comp->KeyPath );
963
964
965         /* the context server is a short path name 
966          * except for if it is InprocServer32... 
967          */
968         if (strcmpiW(package->classes[i].Context,szInprocServer32)!=0)
969         {
970             sz = 0;
971             sz = GetShortPathNameW( file->TargetPath, NULL, 0 );
972             if (sz == 0)
973             {
974                 ERR("Unable to find short path for CLSID COM Server\n");
975                 argument = NULL;
976             }
977             else
978             {
979                 size = sz * sizeof(WCHAR);
980
981                 if (package->classes[i].Argument)
982                 {
983                     size += strlenW(package->classes[i].Argument) * 
984                             sizeof(WCHAR);
985                     size += sizeof(WCHAR);
986                 }
987
988                 argument = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR));
989                 GetShortPathNameW( file->TargetPath, argument, sz );
990
991                 if (package->classes[i].Argument)
992                 {
993                     strcatW(argument,szSpace);
994                     strcatW(argument,package->classes[i].Argument);
995                 }
996             }
997         }
998         else
999         {
1000             size = lstrlenW( file->TargetPath ) * sizeof(WCHAR);
1001
1002             if (package->classes[i].Argument)
1003             {
1004                 size += strlenW(package->classes[i].Argument) * sizeof(WCHAR);
1005                 size += sizeof(WCHAR);
1006             }
1007
1008             argument = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR));
1009             strcpyW( argument, file->TargetPath );
1010
1011             if (package->classes[i].Argument)
1012             {
1013                 strcatW(argument,szSpace);
1014                 strcatW(argument,package->classes[i].Argument);
1015             }
1016         }
1017
1018         if (argument)
1019         {
1020             RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size);
1021             HeapFree(GetProcessHeap(),0,argument);
1022         }
1023
1024         RegCloseKey(hkey3);
1025
1026         if (package->classes[i].ProgIDIndex >= 0 || 
1027             package->classes[i].ProgIDText)
1028         {
1029             LPCWSTR progid;
1030
1031             if (package->classes[i].ProgIDIndex >= 0)
1032                 progid = package->progids[
1033                         package->classes[i].ProgIDIndex].ProgID;
1034             else
1035                 progid = package->classes[i].ProgIDText;
1036
1037             RegCreateKeyW(hkey2,szProgID,&hkey3);
1038             RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)progid,
1039                             (strlenW(progid)+1) *sizeof(WCHAR));
1040             RegCloseKey(hkey3);
1041
1042             if (package->classes[i].ProgIDIndex >= 0 &&
1043                 package->progids[package->classes[i].ProgIDIndex].
1044                                 VersionIndIndex >= 0)
1045             {
1046                 LPWSTR viprogid = strdupW(package->progids[package->progids[
1047                         package->classes[i].ProgIDIndex].VersionIndIndex].
1048                         ProgID);
1049                 RegCreateKeyW(hkey2,szVIProgID,&hkey3);
1050                 RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)viprogid,
1051                             (strlenW(viprogid)+1) *sizeof(WCHAR));
1052                 RegCloseKey(hkey3);
1053                 HeapFree(GetProcessHeap(), 0, viprogid);
1054             }
1055         }
1056
1057         if (package->classes[i].AppIDIndex >= 0)
1058         { 
1059             RegSetValueExW(hkey2,szAppID,0,REG_SZ,
1060              (LPVOID)package->appids[package->classes[i].AppIDIndex].AppID,
1061              (strlenW(package->appids[package->classes[i].AppIDIndex].AppID)+1)
1062              *sizeof(WCHAR));
1063
1064             register_appid(package,package->classes[i].AppIDIndex,
1065                             package->classes[i].Description);
1066         }
1067
1068         if (package->classes[i].IconPath)
1069         {
1070             static const WCHAR szDefaultIcon[] = 
1071                 {'D','e','f','a','u','l','t','I','c','o','n',0};
1072
1073             RegCreateKeyW(hkey2,szDefaultIcon,&hkey3);
1074
1075             RegSetValueExW(hkey3,NULL,0,REG_SZ,
1076                            (LPVOID)package->classes[i].IconPath,
1077                            (strlenW(package->classes[i].IconPath)+1) * 
1078                            sizeof(WCHAR));
1079
1080             RegCloseKey(hkey3);
1081         }
1082
1083         if (package->classes[i].DefInprocHandler)
1084         {
1085             static const WCHAR szInproc[] =
1086                 {'I','n','p','r','o','c','H','a','n','d','l','e','r',0};
1087
1088             size = (strlenW(package->classes[i].DefInprocHandler) + 1) * 
1089                     sizeof(WCHAR);
1090             RegCreateKeyW(hkey2,szInproc,&hkey3);
1091             RegSetValueExW(hkey3,NULL,0,REG_SZ, 
1092                             (LPVOID)package->classes[i].DefInprocHandler, size);
1093             RegCloseKey(hkey3);
1094         }
1095
1096         if (package->classes[i].DefInprocHandler32)
1097         {
1098             static const WCHAR szInproc32[] =
1099                 {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',
1100                  0};
1101             size = (strlenW(package->classes[i].DefInprocHandler32) + 1) * 
1102                     sizeof(WCHAR);
1103
1104             RegCreateKeyW(hkey2,szInproc32,&hkey3);
1105             RegSetValueExW(hkey3,NULL,0,REG_SZ, 
1106                            (LPVOID)package->classes[i].DefInprocHandler32,size);
1107             RegCloseKey(hkey3);
1108         }
1109         
1110         RegCloseKey(hkey2);
1111
1112         /* if there is a FileTypeMask, register the FileType */
1113         if (package->classes[i].FileTypeMask)
1114         {
1115             LPWSTR ptr, ptr2;
1116             LPWSTR keyname;
1117             INT index = 0;
1118             ptr = package->classes[i].FileTypeMask;
1119             while (ptr && *ptr)
1120             {
1121                 ptr2 = strchrW(ptr,';');
1122                 if (ptr2)
1123                     *ptr2 = 0;
1124                 keyname = HeapAlloc(GetProcessHeap(),0,(strlenW(szFileType_fmt)+
1125                                         strlenW(package->classes[i].CLSID) + 4)
1126                                 * sizeof(WCHAR));
1127                 sprintfW(keyname,szFileType_fmt, package->classes[i].CLSID, 
1128                         index);
1129
1130                 RegCreateKeyW(HKEY_CLASSES_ROOT,keyname,&hkey2);
1131                 RegSetValueExW(hkey2,NULL,0,REG_SZ, (LPVOID)ptr,
1132                         strlenW(ptr)*sizeof(WCHAR));
1133                 RegCloseKey(hkey2);
1134                 HeapFree(GetProcessHeap(), 0, keyname);
1135
1136                 if (ptr2)
1137                     ptr = ptr2+1;
1138                 else
1139                     ptr = NULL;
1140
1141                 index ++;
1142             }
1143         }
1144         
1145         uirow = MSI_CreateRecord(1);
1146
1147         MSI_RecordSetStringW(uirow,1,package->classes[i].CLSID);
1148         ui_actiondata(package,szRegisterClassInfo,uirow);
1149         msiobj_release(&uirow->hdr);
1150     }
1151
1152     RegCloseKey(hkey);
1153     return rc;
1154 }
1155
1156 static UINT register_progid_base(MSIPACKAGE* package, MSIPROGID* progid,
1157                                  LPWSTR clsid)
1158 {
1159     static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
1160     static const WCHAR szDefaultIcon[] =
1161         {'D','e','f','a','u','l','t','I','c','o','n',0};
1162     HKEY hkey,hkey2;
1163
1164     RegCreateKeyW(HKEY_CLASSES_ROOT,progid->ProgID,&hkey);
1165
1166     if (progid->Description)
1167     {
1168         RegSetValueExW(hkey,NULL,0,REG_SZ,
1169                         (LPVOID)progid->Description, 
1170                         (strlenW(progid->Description)+1) *
1171                        sizeof(WCHAR));
1172     }
1173
1174     if (progid->ClassIndex >= 0)
1175     {   
1176         RegCreateKeyW(hkey,szCLSID,&hkey2);
1177         RegSetValueExW(hkey2,NULL,0,REG_SZ,
1178                         (LPVOID)package->classes[progid->ClassIndex].CLSID, 
1179                         (strlenW(package->classes[progid->ClassIndex].CLSID)+1)
1180                         * sizeof(WCHAR));
1181
1182         if (clsid)
1183             strcpyW(clsid,package->classes[progid->ClassIndex].CLSID);
1184
1185         RegCloseKey(hkey2);
1186     }
1187     else
1188     {
1189         FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
1190     }
1191
1192     if (progid->IconPath)
1193     {
1194         RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
1195
1196         RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)progid->IconPath,
1197                            (strlenW(progid->IconPath)+1) * sizeof(WCHAR));
1198         RegCloseKey(hkey2);
1199     }
1200     return ERROR_SUCCESS;
1201 }
1202
1203 static UINT register_progid(MSIPACKAGE *package, MSIPROGID* progid, 
1204                 LPWSTR clsid)
1205 {
1206     UINT rc = ERROR_SUCCESS; 
1207
1208     if (progid->ParentIndex < 0)
1209         rc = register_progid_base(package, progid, clsid);
1210     else
1211     {
1212         DWORD disp;
1213         HKEY hkey,hkey2;
1214         static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
1215         static const WCHAR szDefaultIcon[] =
1216             {'D','e','f','a','u','l','t','I','c','o','n',0};
1217         static const WCHAR szCurVer[] =
1218             {'C','u','r','V','e','r',0};
1219
1220         /* check if already registered */
1221         RegCreateKeyExW(HKEY_CLASSES_ROOT, progid->ProgID, 0, NULL, 0,
1222                         KEY_ALL_ACCESS, NULL, &hkey, &disp );
1223         if (disp == REG_OPENED_EXISTING_KEY)
1224         {
1225             TRACE("Key already registered\n");
1226             RegCloseKey(hkey);
1227             return rc;
1228         }
1229
1230         TRACE("Registering Parent %s index %i\n",
1231                     debugstr_w(package->progids[progid->ParentIndex].ProgID), 
1232                     progid->ParentIndex);
1233         rc = register_progid(package,&package->progids[progid->ParentIndex],
1234                         clsid);
1235
1236         /* clsid is same as parent */
1237         RegCreateKeyW(hkey,szCLSID,&hkey2);
1238         RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) *
1239                        sizeof(WCHAR));
1240
1241         RegCloseKey(hkey2);
1242
1243
1244         if (progid->Description)
1245         {
1246             RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid->Description,
1247                            (strlenW(progid->Description)+1) * sizeof(WCHAR));
1248         }
1249
1250         if (progid->IconPath)
1251         {
1252             RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
1253             RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)progid->IconPath,
1254                            (strlenW(progid->IconPath)+1) * sizeof(WCHAR));
1255             RegCloseKey(hkey2);
1256         }
1257
1258         /* write out the current version */
1259         if (progid->CurVerIndex >= 0)
1260         {
1261             RegCreateKeyW(hkey,szCurVer,&hkey2);
1262             RegSetValueExW(hkey2,NULL,0,REG_SZ,
1263                 (LPVOID)package->progids[progid->CurVerIndex].ProgID,
1264                 (strlenW(package->progids[progid->CurVerIndex].ProgID)+1) * 
1265                 sizeof(WCHAR));
1266             RegCloseKey(hkey2);
1267         }
1268
1269         RegCloseKey(hkey);
1270     }
1271     return rc;
1272 }
1273
1274 UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
1275 {
1276     INT i;
1277     MSIRECORD *uirow;
1278
1279     if (!package)
1280         return ERROR_INVALID_HANDLE;
1281
1282     load_classes_and_such(package);
1283
1284     for (i = 0; i < package->loaded_progids; i++)
1285     {
1286         WCHAR clsid[0x1000];
1287
1288         /* check if this progid is to be installed */
1289         package->progids[i].InstallMe =  ((package->progids[i].InstallMe) ||
1290               (package->progids[i].ClassIndex >= 0 &&
1291               package->classes[package->progids[i].ClassIndex].Installed));
1292
1293         if (!package->progids[i].InstallMe)
1294         {
1295             TRACE("progid %s not scheduled to be installed\n",
1296                              debugstr_w(package->progids[i].ProgID));
1297             continue;
1298         }
1299        
1300         TRACE("Registering progid %s index %i\n",
1301                         debugstr_w(package->progids[i].ProgID), i);
1302
1303         register_progid(package,&package->progids[i],clsid);
1304
1305         uirow = MSI_CreateRecord(1);
1306         MSI_RecordSetStringW(uirow,1,package->progids[i].ProgID);
1307         ui_actiondata(package,szRegisterProgIdInfo,uirow);
1308         msiobj_release(&uirow->hdr);
1309     }
1310
1311     return ERROR_SUCCESS;
1312 }
1313
1314 static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid, 
1315                 MSICOMPONENT* component, MSIEXTENSION* extension,
1316                 MSIVERB* verb, INT* Sequence )
1317 {
1318     LPWSTR keyname;
1319     HKEY key;
1320     static const WCHAR szShell[] = {'s','h','e','l','l',0};
1321     static const WCHAR szCommand[] = {'c','o','m','m','a','n','d',0};
1322     static const WCHAR fmt[] = {'\"','%','s','\"',' ','%','s',0};
1323     static const WCHAR fmt2[] = {'\"','%','s','\"',0};
1324     LPWSTR command;
1325     DWORD size;
1326     LPWSTR advertise;
1327
1328     keyname = build_directory_name(4, progid, szShell, verb->Verb, szCommand);
1329
1330     TRACE("Making Key %s\n",debugstr_w(keyname));
1331     RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
1332     size = strlenW(component->FullKeypath);
1333     if (verb->Argument)
1334         size += strlenW(verb->Argument);
1335      size += 4;
1336
1337      command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR));
1338      if (verb->Argument)
1339         sprintfW(command, fmt, component->FullKeypath, verb->Argument);
1340      else
1341         sprintfW(command, fmt2, component->FullKeypath);
1342
1343      RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)command, (strlenW(command)+1)*
1344                      sizeof(WCHAR));
1345      HeapFree(GetProcessHeap(),0,command);
1346
1347      advertise = create_component_advertise_string(package, component, 
1348                                                    extension->Feature->Feature);
1349
1350      size = strlenW(advertise);
1351
1352      if (verb->Argument)
1353          size += strlenW(verb->Argument);
1354      size += 4;
1355
1356      command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR));
1357      memset(command,0,size*sizeof(WCHAR));
1358
1359      strcpyW(command,advertise);
1360      if (verb->Argument)
1361      {
1362          static const WCHAR szSpace[] = {' ',0};
1363          strcatW(command,szSpace);
1364          strcatW(command,verb->Argument);
1365      }
1366
1367      RegSetValueExW(key, szCommand, 0, REG_MULTI_SZ, (LPBYTE)command,
1368                         (strlenW(command)+2)*sizeof(WCHAR));
1369      
1370      RegCloseKey(key);
1371      HeapFree(GetProcessHeap(),0,keyname);
1372      HeapFree(GetProcessHeap(),0,advertise);
1373      HeapFree(GetProcessHeap(),0,command);
1374
1375      if (verb->Command)
1376      {
1377         keyname = build_directory_name(3, progid, szShell, verb->Verb);
1378         RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
1379         RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)verb->Command,
1380                                     (strlenW(verb->Command)+1) *sizeof(WCHAR));
1381         RegCloseKey(key);
1382         HeapFree(GetProcessHeap(),0,keyname);
1383      }
1384
1385      if (verb->Sequence != MSI_NULL_INTEGER)
1386      {
1387         if (*Sequence == MSI_NULL_INTEGER || verb->Sequence < *Sequence)
1388         {
1389             *Sequence = verb->Sequence;
1390             keyname = build_directory_name(2, progid, szShell);
1391             RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
1392             RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)verb->Verb,
1393                             (strlenW(verb->Verb)+1) *sizeof(WCHAR));
1394             RegCloseKey(key);
1395             HeapFree(GetProcessHeap(),0,keyname);
1396         }
1397     }
1398     return ERROR_SUCCESS;
1399 }
1400
1401 UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
1402 {
1403     static const WCHAR szContentType[] = 
1404         {'C','o','n','t','e','n','t',' ','T','y','p','e',0 };
1405     HKEY hkey;
1406     INT i;
1407     MSIRECORD *uirow;
1408     BOOL install_on_demand = TRUE;
1409
1410     if (!package)
1411         return ERROR_INVALID_HANDLE;
1412
1413     load_classes_and_such(package);
1414
1415     /* We need to set install_on_demand based on if the shell handles advertised
1416      * shortcuts and the like. Because Mike McCormack is working on this i am
1417      * going to default to TRUE
1418      */
1419     
1420     for (i = 0; i < package->loaded_extensions; i++)
1421     {
1422         WCHAR extension[257];
1423         MSIFEATURE *feature;
1424      
1425         if (!package->extensions[i].Component)
1426             continue;
1427
1428         feature = package->extensions[i].Feature;
1429
1430         /* 
1431          * yes. MSDN says that these are based on _Feature_ not on
1432          * Component.  So verify the feature is to be installed
1433          */
1434         if ((!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL )) &&
1435              !(install_on_demand &&
1436                ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED )))
1437         {
1438             TRACE("Skipping extension  %s reg due to disabled feature %s\n",
1439                             debugstr_w(package->extensions[i].Extension),
1440                             debugstr_w(feature->Feature));
1441
1442             continue;
1443         }
1444
1445         TRACE("Registering extension %s index %i\n",
1446                         debugstr_w(package->extensions[i].Extension), i);
1447
1448         package->extensions[i].Installed = TRUE;
1449
1450         /* this is only registered if the extension has at least 1 verb
1451          * according to MSDN
1452          */
1453         if (package->extensions[i].ProgIDIndex >= 0 &&
1454                 package->extensions[i].VerbCount > 0)
1455            mark_progid_for_install(package, package->extensions[i].ProgIDIndex);
1456
1457         if (package->extensions[i].MIMEIndex >= 0)
1458            mark_mime_for_install(package, package->extensions[i].MIMEIndex);
1459
1460         extension[0] = '.';
1461         extension[1] = 0;
1462         strcatW(extension,package->extensions[i].Extension);
1463
1464         RegCreateKeyW(HKEY_CLASSES_ROOT,extension,&hkey);
1465
1466         if (package->extensions[i].MIMEIndex >= 0)
1467         {
1468             RegSetValueExW(hkey,szContentType,0,REG_SZ,
1469                             (LPVOID)package->mimes[package->extensions[i].
1470                                 MIMEIndex].ContentType,
1471                            (strlenW(package->mimes[package->extensions[i].
1472                                     MIMEIndex].ContentType)+1)*sizeof(WCHAR));
1473         }
1474
1475         if (package->extensions[i].ProgIDIndex >= 0 || 
1476             package->extensions[i].ProgIDText)
1477         {
1478             static const WCHAR szSN[] = 
1479                 {'\\','S','h','e','l','l','N','e','w',0};
1480             HKEY hkey2;
1481             LPWSTR newkey;
1482             LPCWSTR progid;
1483             INT v;
1484             INT Sequence = MSI_NULL_INTEGER;
1485             
1486             if (package->extensions[i].ProgIDIndex >= 0)
1487                 progid = package->progids[package->extensions[i].
1488                     ProgIDIndex].ProgID;
1489             else
1490                 progid = package->extensions[i].ProgIDText;
1491
1492             RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid,
1493                            (strlenW(progid)+1)*sizeof(WCHAR));
1494
1495             newkey = HeapAlloc(GetProcessHeap(),0,
1496                            (strlenW(progid)+strlenW(szSN)+1) * sizeof(WCHAR)); 
1497
1498             strcpyW(newkey,progid);
1499             strcatW(newkey,szSN);
1500             RegCreateKeyW(hkey,newkey,&hkey2);
1501             RegCloseKey(hkey2);
1502
1503             HeapFree(GetProcessHeap(),0,newkey);
1504
1505             /* do all the verbs */
1506             for (v = 0; v < package->extensions[i].VerbCount; v++)
1507                 register_verb(package, progid, 
1508                               package->extensions[i].Component,
1509                               &package->extensions[i],
1510                               &package->verbs[package->extensions[i].Verbs[v]], 
1511                               &Sequence);
1512         }
1513         
1514         RegCloseKey(hkey);
1515
1516         uirow = MSI_CreateRecord(1);
1517         MSI_RecordSetStringW(uirow,1,package->extensions[i].Extension);
1518         ui_actiondata(package,szRegisterExtensionInfo,uirow);
1519         msiobj_release(&uirow->hdr);
1520     }
1521
1522     return ERROR_SUCCESS;
1523 }
1524
1525 UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package)
1526 {
1527     static const WCHAR szExten[] = 
1528         {'E','x','t','e','n','s','i','o','n',0 };
1529     HKEY hkey;
1530     INT i;
1531     MSIRECORD *uirow;
1532
1533     if (!package)
1534         return ERROR_INVALID_HANDLE;
1535
1536     load_classes_and_such(package);
1537
1538     for (i = 0; i < package->loaded_mimes; i++)
1539     {
1540         WCHAR extension[257];
1541         LPCWSTR exten;
1542         LPCWSTR mime;
1543         static const WCHAR fmt[] = 
1544             {'M','I','M','E','\\','D','a','t','a','b','a','s','e','\\',
1545              'C','o','n','t','e','n','t',' ','T','y','p','e','\\', '%','s',0};
1546         LPWSTR key;
1547
1548         /* 
1549          * check if the MIME is to be installed. Either as requesed by an
1550          * extension or Class
1551          */
1552         package->mimes[i].InstallMe =  ((package->mimes[i].InstallMe) ||
1553               (package->mimes[i].ClassIndex >= 0 &&
1554               package->classes[package->mimes[i].ClassIndex].Installed) ||
1555               (package->mimes[i].ExtensionIndex >=0 &&
1556               package->extensions[package->mimes[i].ExtensionIndex].Installed));
1557
1558         if (!package->mimes[i].InstallMe)
1559         {
1560             TRACE("MIME %s not scheduled to be installed\n",
1561                              debugstr_w(package->mimes[i].ContentType));
1562             continue;
1563         }
1564         
1565         mime = package->mimes[i].ContentType;
1566         exten = package->extensions[package->mimes[i].ExtensionIndex].Extension;
1567         extension[0] = '.';
1568         extension[1] = 0;
1569         strcatW(extension,exten);
1570
1571         key = HeapAlloc(GetProcessHeap(),0,(strlenW(mime)+strlenW(fmt)+1) *
1572                                             sizeof(WCHAR));
1573         sprintfW(key,fmt,mime);
1574         RegCreateKeyW(HKEY_CLASSES_ROOT,key,&hkey);
1575         RegSetValueExW(hkey,szExten,0,REG_SZ,(LPVOID)extension,
1576                            (strlenW(extension)+1)*sizeof(WCHAR));
1577
1578         HeapFree(GetProcessHeap(),0,key);
1579
1580         if (package->mimes[i].CLSID[0])
1581         {
1582             FIXME("Handle non null for field 3\n");
1583         }
1584
1585         RegCloseKey(hkey);
1586
1587         uirow = MSI_CreateRecord(2);
1588         MSI_RecordSetStringW(uirow,1,package->mimes[i].ContentType);
1589         MSI_RecordSetStringW(uirow,2,exten);
1590         ui_actiondata(package,szRegisterMIMEInfo,uirow);
1591         msiobj_release(&uirow->hdr);
1592     }
1593
1594     return ERROR_SUCCESS;
1595 }