Fix some gcc 4.0 warnings.
[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].FeatureIndex = 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].FeatureIndex = 
479             get_loaded_feature(package,buffer);
480
481     return index;
482 }
483
484 /*
485  * While the extension table has 2 primary keys, this function is only looking
486  * at the Extension key which is what is referenced as a forign key 
487  */
488 static INT load_given_extension(MSIPACKAGE *package, LPCWSTR extension)
489 {
490     INT rc;
491     MSIRECORD *row;
492     INT i;
493     static const WCHAR ExecSeqQuery[] =
494         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
495          '`','E','x','t','e','n','s','i','o','n','`',' ',
496          'W','H','E','R','E',' ',
497          '`','E','x','t','e','n','s','i','o','n','`',' ','=',' ',
498          '\'','%','s','\'',0};
499
500     if (!extension)
501         return -1;
502
503     /* check for extensions already loaded */
504     for (i = 0; i < package->loaded_extensions; i++)
505         if (strcmpiW(package->extensions[i].Extension,extension)==0)
506         {
507             TRACE("extension %s already loaded at %i\n",debugstr_w(extension),
508                             i);
509             return i;
510         }
511     
512     row = MSI_QueryGetRecord(package->db, ExecSeqQuery, extension);
513     if (!row)
514         return -1;
515
516     rc = load_extension(package, row);
517     msiobj_release(&row->hdr);
518
519     return rc;
520 }
521
522 static UINT iterate_load_verb(MSIRECORD *row, LPVOID param)
523 {
524     MSIPACKAGE* package = (MSIPACKAGE*)param;
525     DWORD index = package->loaded_verbs;
526     LPCWSTR buffer;
527
528     /* fill in the data */
529
530     package->loaded_verbs++;
531     if (package->loaded_verbs == 1)
532         package->verbs = HeapAlloc(GetProcessHeap(),0,sizeof(MSIVERB));
533     else
534         package->verbs = HeapReAlloc(GetProcessHeap(),0,
535             package->verbs , package->loaded_verbs * sizeof(MSIVERB));
536
537     memset(&package->verbs[index],0,sizeof(MSIVERB));
538
539     buffer = MSI_RecordGetString(row,1);
540     package->verbs[index].ExtensionIndex = load_given_extension(package,buffer);
541     if (package->verbs[index].ExtensionIndex < 0 && buffer)
542         ERR("Verb unable to find loaded extension %s\n", debugstr_w(buffer));
543
544     package->verbs[index].Verb = load_dynamic_stringW(row,2);
545     TRACE("loading verb %s\n",debugstr_w(package->verbs[index].Verb));
546     package->verbs[index].Sequence = MSI_RecordGetInteger(row,3);
547
548     buffer = MSI_RecordGetString(row,4);
549     deformat_string(package,buffer,&package->verbs[index].Command);
550
551     buffer = MSI_RecordGetString(row,5);
552     deformat_string(package,buffer,&package->verbs[index].Argument);
553
554     /* assosiate the verb with the correct extension */
555     if (package->verbs[index].ExtensionIndex >= 0)
556     {
557         MSIEXTENSION* extension = &package->extensions[package->verbs[index].
558                 ExtensionIndex];
559         int count = extension->VerbCount;
560
561         if (count >= 99)
562             FIXME("Exceeding max verb count! Increase that limit!!!\n");
563         else
564         {
565             extension->VerbCount++;
566             extension->Verbs[count] = index;
567         }
568     }
569     
570     return ERROR_SUCCESS;
571 }
572
573 static UINT iterate_all_classes(MSIRECORD *rec, LPVOID param)
574 {
575     MSICOMPONENT *comp;
576     LPCWSTR clsid;
577     LPCWSTR context;
578     LPCWSTR buffer;
579     MSIPACKAGE* package =(MSIPACKAGE*)param;
580     INT i;
581     BOOL match = FALSE;
582
583     clsid = MSI_RecordGetString(rec,1);
584     context = MSI_RecordGetString(rec,2);
585     buffer = MSI_RecordGetString(rec,3);
586     comp = get_loaded_component(package,buffer);
587
588     for (i = 0; i < package->loaded_classes; i++)
589     {
590         if (strcmpiW(clsid,package->classes[i].CLSID))
591             continue;
592         if (strcmpW(context,package->classes[i].Context))
593             continue;
594         if (comp == package->classes[i].Component)
595         {
596             match = TRUE;
597             break;
598         }
599     }
600     
601     if (!match)
602         load_class(package, rec);
603
604     return ERROR_SUCCESS;
605 }
606
607 static VOID load_all_classes(MSIPACKAGE *package)
608 {
609     UINT rc = ERROR_SUCCESS;
610     MSIQUERY *view;
611
612     static const WCHAR ExecSeqQuery[] =
613         {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
614          '`','C','l','a','s','s','`',0};
615
616     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
617     if (rc != ERROR_SUCCESS)
618         return;
619
620     rc = MSI_IterateRecords(view, NULL, iterate_all_classes, package);
621     msiobj_release(&view->hdr);
622 }
623
624 static UINT iterate_all_extensions(MSIRECORD *rec, LPVOID param)
625 {
626     MSICOMPONENT *comp;
627     LPCWSTR buffer;
628     LPCWSTR extension;
629     MSIPACKAGE* package =(MSIPACKAGE*)param;
630     BOOL match = FALSE;
631     INT i;
632
633     extension = MSI_RecordGetString(rec,1);
634     buffer = MSI_RecordGetString(rec,2);
635     comp = get_loaded_component(package,buffer);
636
637     for (i = 0; i < package->loaded_extensions; i++)
638     {
639         if (strcmpiW(extension,package->extensions[i].Extension))
640             continue;
641         if (comp == package->extensions[i].Component)
642         {
643             match = TRUE;
644             break;
645         }
646     }
647
648     if (!match)
649         load_extension(package, rec);
650
651     return ERROR_SUCCESS;
652 }
653
654 static VOID load_all_extensions(MSIPACKAGE *package)
655 {
656     UINT rc = ERROR_SUCCESS;
657     MSIQUERY *view;
658
659     static const WCHAR ExecSeqQuery[] =
660         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
661          '`','E','x','t','e','n','s','i','o','n','`',0};
662
663     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
664     if (rc != ERROR_SUCCESS)
665         return;
666
667     rc = MSI_IterateRecords(view, NULL, iterate_all_extensions, package);
668     msiobj_release(&view->hdr);
669 }
670
671 static UINT iterate_all_progids(MSIRECORD *rec, LPVOID param)
672 {
673     LPCWSTR buffer;
674     MSIPACKAGE* package =(MSIPACKAGE*)param;
675
676     buffer = MSI_RecordGetString(rec,1);
677     load_given_progid(package,buffer);
678     return ERROR_SUCCESS;
679 }
680
681 static VOID load_all_progids(MSIPACKAGE *package)
682 {
683     UINT rc = ERROR_SUCCESS;
684     MSIQUERY *view;
685
686     static const WCHAR ExecSeqQuery[] =
687         {'S','E','L','E','C','T',' ','`','P','r','o','g','I','d','`',' ',
688          'F','R','O','M',' ', '`','P','r','o','g','I','d','`',0};
689
690     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
691     if (rc != ERROR_SUCCESS)
692         return;
693
694     rc = MSI_IterateRecords(view, NULL, iterate_all_progids, package);
695     msiobj_release(&view->hdr);
696 }
697
698 static VOID load_all_verbs(MSIPACKAGE *package)
699 {
700     UINT rc = ERROR_SUCCESS;
701     MSIQUERY *view;
702
703     static const WCHAR ExecSeqQuery[] =
704         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
705          '`','V','e','r','b','`',0};
706
707     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
708     if (rc != ERROR_SUCCESS)
709         return;
710
711     rc = MSI_IterateRecords(view, NULL, iterate_load_verb, package);
712     msiobj_release(&view->hdr);
713 }
714
715 static UINT iterate_all_mimes(MSIRECORD *rec, LPVOID param)
716 {
717     LPCWSTR buffer;
718     MSIPACKAGE* package =(MSIPACKAGE*)param;
719
720     buffer = MSI_RecordGetString(rec,1);
721     load_given_mime(package,buffer);
722     return ERROR_SUCCESS;
723 }
724
725 static VOID load_all_mimes(MSIPACKAGE *package)
726 {
727     UINT rc = ERROR_SUCCESS;
728     MSIQUERY *view;
729
730     static const WCHAR ExecSeqQuery[] =
731         {'S','E','L','E','C','T',' ',
732          '`','C','o','n','t','e','n','t','T','y','p','e','`',
733          ' ','F','R','O','M',' ',
734          '`','M','I','M','E','`',0};
735
736     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
737     if (rc != ERROR_SUCCESS)
738         return;
739
740     rc = MSI_IterateRecords(view, NULL, iterate_all_mimes, package);
741     msiobj_release(&view->hdr);
742 }
743
744 static void load_classes_and_such(MSIPACKAGE *package)
745 {
746     TRACE("Loading all the class info and related tables\n");
747
748     /* check if already loaded */
749     if (package->classes || package->extensions || package->progids || 
750         package->verbs || package->mimes)
751         return;
752
753     load_all_classes(package);
754     load_all_extensions(package);
755     load_all_progids(package);
756     /* these loads must come after the other loads */
757     load_all_verbs(package);
758     load_all_mimes(package);
759 }
760
761 static void mark_progid_for_install(MSIPACKAGE* package, INT index)
762 {
763     MSIPROGID* progid;
764     int i;
765
766     if (index < 0 || index >= package->loaded_progids)
767         return;
768
769     progid = &package->progids[index];
770
771     if (progid->InstallMe == TRUE)
772         return;
773
774     progid->InstallMe = TRUE;
775
776     /* all children if this is a parent also install */
777    for (i = 0; i < package->loaded_progids; i++)
778         if (package->progids[i].ParentIndex == index)
779             mark_progid_for_install(package,i);
780 }
781
782 static void mark_mime_for_install(MSIPACKAGE* package, INT index)
783 {
784     MSIMIME* mime;
785
786     if (index < 0 || index >= package->loaded_mimes)
787         return;
788
789     mime = &package->mimes[index];
790
791     if (mime->InstallMe == TRUE)
792         return;
793
794     mime->InstallMe = TRUE;
795 }
796
797 static UINT register_appid(MSIPACKAGE *package, int appidIndex, LPCWSTR app )
798 {
799     static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
800     HKEY hkey2,hkey3;
801
802     if (!package)
803         return ERROR_INVALID_HANDLE;
804
805     RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);
806     RegCreateKeyW(hkey2,package->appids[appidIndex].AppID,&hkey3);
807     RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app,
808                    (strlenW(app)+1)*sizeof(WCHAR));
809
810     if (package->appids[appidIndex].RemoteServerName)
811     {
812         UINT size; 
813         static const WCHAR szRemoteServerName[] =
814              {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',
815               0};
816
817         size = (strlenW(package->appids[appidIndex].RemoteServerName)+1) * 
818                 sizeof(WCHAR);
819
820         RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,
821                         (LPVOID)package->appids[appidIndex].RemoteServerName,
822                         size);
823     }
824
825     if (package->appids[appidIndex].LocalServer)
826     {
827         static const WCHAR szLocalService[] =
828              {'L','o','c','a','l','S','e','r','v','i','c','e',0};
829         UINT size;
830         size = (strlenW(package->appids[appidIndex].LocalServer)+1) * 
831                 sizeof(WCHAR);
832
833         RegSetValueExW(hkey3,szLocalService,0,REG_SZ,
834                         (LPVOID)package->appids[appidIndex].LocalServer,size);
835     }
836
837     if (package->appids[appidIndex].ServiceParameters)
838     {
839         static const WCHAR szService[] =
840              {'S','e','r','v','i','c','e',
841               'P','a','r','a','m','e','t','e','r','s',0};
842         UINT size;
843         size = (strlenW(package->appids[appidIndex].ServiceParameters)+1) * 
844                 sizeof(WCHAR);
845         RegSetValueExW(hkey3,szService,0,REG_SZ,
846                         (LPVOID)package->appids[appidIndex].ServiceParameters,
847                         size);
848     }
849
850     if (package->appids[appidIndex].DllSurrogate)
851     {
852         static const WCHAR szDLL[] =
853              {'D','l','l','S','u','r','r','o','g','a','t','e',0};
854         UINT size;
855         size = (strlenW(package->appids[appidIndex].DllSurrogate)+1) * 
856                 sizeof(WCHAR);
857         RegSetValueExW(hkey3,szDLL,0,REG_SZ,
858                         (LPVOID)package->appids[appidIndex].DllSurrogate,size);
859     }
860
861     if (package->appids[appidIndex].ActivateAtStorage)
862     {
863         static const WCHAR szActivate[] =
864              {'A','c','t','i','v','a','t','e','A','s',
865               'S','t','o','r','a','g','e',0};
866         static const WCHAR szY[] = {'Y',0};
867
868         RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4);
869     }
870
871     if (package->appids[appidIndex].RunAsInteractiveUser)
872     {
873         static const WCHAR szRunAs[] = {'R','u','n','A','s',0};
874         static const WCHAR szUser[] = 
875              {'I','n','t','e','r','a','c','t','i','v','e',' ',
876               'U','s','e','r',0};
877
878         RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,sizeof(szUser));
879     }
880
881     RegCloseKey(hkey3);
882     RegCloseKey(hkey2);
883     return ERROR_SUCCESS;
884 }
885
886 UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
887 {
888     /* 
889      * Again I am assuming the words, "Whose key file represents" when referring
890      * to a Component as to meaning that Components KeyPath file
891      */
892     
893     UINT rc;
894     MSIRECORD *uirow;
895     static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
896     static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 };
897     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 };
898     static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
899     static const WCHAR szSpace[] = {' ',0};
900     static const WCHAR szInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
901     static const WCHAR szFileType_fmt[] = {'F','i','l','e','T','y','p','e','\\','%','s','\\','%','i',0};
902     HKEY hkey,hkey2,hkey3;
903     BOOL install_on_demand = FALSE;
904     int i;
905
906     if (!package)
907         return ERROR_INVALID_HANDLE;
908
909     load_classes_and_such(package);
910     rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);
911     if (rc != ERROR_SUCCESS)
912         return ERROR_FUNCTION_FAILED;
913
914     /* install_on_demand should be set if OLE supports install on demand OLE
915      * servers. For now i am defaulting to FALSE because i do not know how to
916      * check, and i am told our builtin OLE does not support it
917      */
918     
919     for (i = 0; i < package->loaded_classes; i++)
920     {
921         MSICOMPONENT *comp;
922         INT index, f_index;
923         DWORD size, sz;
924         LPWSTR argument;
925
926         comp = package->classes[i].Component;
927         if ( !comp )
928             continue;
929
930         f_index = package->classes[i].FeatureIndex;
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(package, f_index,
937                                 INSTALLSTATE_LOCAL)) &&
938              !(install_on_demand && ACTION_VerifyFeatureForAction(package,
939                              f_index, INSTALLSTATE_ADVERTISED)))
940         {
941             TRACE("Skipping class %s reg due to disabled feature %s\n", 
942                             debugstr_w(package->classes[i].CLSID), 
943                             debugstr_w(package->features[f_index].Feature));
944
945             continue;
946         }
947
948         TRACE("Registering index %i  class %s\n",i,
949                         debugstr_w(package->classes[i].CLSID));
950
951         package->classes[i].Installed = TRUE;
952         if (package->classes[i].ProgIDIndex >= 0)
953             mark_progid_for_install(package, package->classes[i].ProgIDIndex);
954
955         RegCreateKeyW(hkey,package->classes[i].CLSID,&hkey2);
956
957         if (package->classes[i].Description)
958             RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)package->classes[i].
959                             Description, (strlenW(package->classes[i].
960                                      Description)+1)*sizeof(WCHAR));
961
962         RegCreateKeyW(hkey2,package->classes[i].Context,&hkey3);
963         index = get_loaded_file( package, comp->KeyPath );
964
965
966         /* the context server is a short path name 
967          * except for if it is InprocServer32... 
968          */
969         if (strcmpiW(package->classes[i].Context,szInprocServer32)!=0)
970         {
971             sz = 0;
972             sz = GetShortPathNameW(package->files[index].TargetPath, NULL, 0);
973             if (sz == 0)
974             {
975                 ERR("Unable to find short path for CLSID COM Server\n");
976                 argument = NULL;
977             }
978             else
979             {
980                 size = sz * sizeof(WCHAR);
981
982                 if (package->classes[i].Argument)
983                 {
984                     size += strlenW(package->classes[i].Argument) * 
985                             sizeof(WCHAR);
986                     size += sizeof(WCHAR);
987                 }
988
989                 argument = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR));
990                 GetShortPathNameW(package->files[index].TargetPath, argument, 
991                                 sz);
992
993                 if (package->classes[i].Argument)
994                 {
995                     strcatW(argument,szSpace);
996                     strcatW(argument,package->classes[i].Argument);
997                 }
998             }
999         }
1000         else
1001         {
1002             size = lstrlenW(package->files[index].TargetPath) * sizeof(WCHAR);
1003
1004             if (package->classes[i].Argument)
1005             {
1006                 size += strlenW(package->classes[i].Argument) * sizeof(WCHAR);
1007                 size += sizeof(WCHAR);
1008             }
1009
1010             argument = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR));
1011             strcpyW(argument, package->files[index].TargetPath);
1012
1013             if (package->classes[i].Argument)
1014             {
1015                 strcatW(argument,szSpace);
1016                 strcatW(argument,package->classes[i].Argument);
1017             }
1018         }
1019
1020         if (argument)
1021         {
1022             RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size);
1023             HeapFree(GetProcessHeap(),0,argument);
1024         }
1025
1026         RegCloseKey(hkey3);
1027
1028         if (package->classes[i].ProgIDIndex >= 0 || 
1029             package->classes[i].ProgIDText)
1030         {
1031             LPCWSTR progid;
1032
1033             if (package->classes[i].ProgIDIndex >= 0)
1034                 progid = package->progids[
1035                         package->classes[i].ProgIDIndex].ProgID;
1036             else
1037                 progid = package->classes[i].ProgIDText;
1038
1039             RegCreateKeyW(hkey2,szProgID,&hkey3);
1040             RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)progid,
1041                             (strlenW(progid)+1) *sizeof(WCHAR));
1042             RegCloseKey(hkey3);
1043
1044             if (package->classes[i].ProgIDIndex >= 0 &&
1045                 package->progids[package->classes[i].ProgIDIndex].
1046                                 VersionIndIndex >= 0)
1047             {
1048                 LPWSTR viprogid = strdupW(package->progids[package->progids[
1049                         package->classes[i].ProgIDIndex].VersionIndIndex].
1050                         ProgID);
1051                 RegCreateKeyW(hkey2,szVIProgID,&hkey3);
1052                 RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)viprogid,
1053                             (strlenW(viprogid)+1) *sizeof(WCHAR));
1054                 RegCloseKey(hkey3);
1055                 HeapFree(GetProcessHeap(), 0, viprogid);
1056             }
1057         }
1058
1059         if (package->classes[i].AppIDIndex >= 0)
1060         { 
1061             RegSetValueExW(hkey2,szAppID,0,REG_SZ,
1062              (LPVOID)package->appids[package->classes[i].AppIDIndex].AppID,
1063              (strlenW(package->appids[package->classes[i].AppIDIndex].AppID)+1)
1064              *sizeof(WCHAR));
1065
1066             register_appid(package,package->classes[i].AppIDIndex,
1067                             package->classes[i].Description);
1068         }
1069
1070         if (package->classes[i].IconPath)
1071         {
1072             static const WCHAR szDefaultIcon[] = 
1073                 {'D','e','f','a','u','l','t','I','c','o','n',0};
1074
1075             RegCreateKeyW(hkey2,szDefaultIcon,&hkey3);
1076
1077             RegSetValueExW(hkey3,NULL,0,REG_SZ,
1078                            (LPVOID)package->classes[i].IconPath,
1079                            (strlenW(package->classes[i].IconPath)+1) * 
1080                            sizeof(WCHAR));
1081
1082             RegCloseKey(hkey3);
1083         }
1084
1085         if (package->classes[i].DefInprocHandler)
1086         {
1087             static const WCHAR szInproc[] =
1088                 {'I','n','p','r','o','c','H','a','n','d','l','e','r',0};
1089
1090             size = (strlenW(package->classes[i].DefInprocHandler) + 1) * 
1091                     sizeof(WCHAR);
1092             RegCreateKeyW(hkey2,szInproc,&hkey3);
1093             RegSetValueExW(hkey3,NULL,0,REG_SZ, 
1094                             (LPVOID)package->classes[i].DefInprocHandler, size);
1095             RegCloseKey(hkey3);
1096         }
1097
1098         if (package->classes[i].DefInprocHandler32)
1099         {
1100             static const WCHAR szInproc32[] =
1101                 {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',
1102                  0};
1103             size = (strlenW(package->classes[i].DefInprocHandler32) + 1) * 
1104                     sizeof(WCHAR);
1105
1106             RegCreateKeyW(hkey2,szInproc32,&hkey3);
1107             RegSetValueExW(hkey3,NULL,0,REG_SZ, 
1108                            (LPVOID)package->classes[i].DefInprocHandler32,size);
1109             RegCloseKey(hkey3);
1110         }
1111         
1112         RegCloseKey(hkey2);
1113
1114         /* if there is a FileTypeMask, register the FileType */
1115         if (package->classes[i].FileTypeMask)
1116         {
1117             LPWSTR ptr, ptr2;
1118             LPWSTR keyname;
1119             INT index = 0;
1120             ptr = package->classes[i].FileTypeMask;
1121             while (ptr && *ptr)
1122             {
1123                 ptr2 = strchrW(ptr,';');
1124                 if (ptr2)
1125                     *ptr2 = 0;
1126                 keyname = HeapAlloc(GetProcessHeap(),0,(strlenW(szFileType_fmt)+
1127                                         strlenW(package->classes[i].CLSID) + 4)
1128                                 * sizeof(WCHAR));
1129                 sprintfW(keyname,szFileType_fmt, package->classes[i].CLSID, 
1130                         index);
1131
1132                 RegCreateKeyW(HKEY_CLASSES_ROOT,keyname,&hkey2);
1133                 RegSetValueExW(hkey2,NULL,0,REG_SZ, (LPVOID)ptr,
1134                         strlenW(ptr)*sizeof(WCHAR));
1135                 RegCloseKey(hkey2);
1136                 HeapFree(GetProcessHeap(), 0, keyname);
1137
1138                 if (ptr2)
1139                     ptr = ptr2+1;
1140                 else
1141                     ptr = NULL;
1142
1143                 index ++;
1144             }
1145         }
1146         
1147         uirow = MSI_CreateRecord(1);
1148
1149         MSI_RecordSetStringW(uirow,1,package->classes[i].CLSID);
1150         ui_actiondata(package,szRegisterClassInfo,uirow);
1151         msiobj_release(&uirow->hdr);
1152     }
1153
1154     RegCloseKey(hkey);
1155     return rc;
1156 }
1157
1158 static UINT register_progid_base(MSIPACKAGE* package, MSIPROGID* progid,
1159                                  LPWSTR clsid)
1160 {
1161     static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
1162     static const WCHAR szDefaultIcon[] =
1163         {'D','e','f','a','u','l','t','I','c','o','n',0};
1164     HKEY hkey,hkey2;
1165
1166     RegCreateKeyW(HKEY_CLASSES_ROOT,progid->ProgID,&hkey);
1167
1168     if (progid->Description)
1169     {
1170         RegSetValueExW(hkey,NULL,0,REG_SZ,
1171                         (LPVOID)progid->Description, 
1172                         (strlenW(progid->Description)+1) *
1173                        sizeof(WCHAR));
1174     }
1175
1176     if (progid->ClassIndex >= 0)
1177     {   
1178         RegCreateKeyW(hkey,szCLSID,&hkey2);
1179         RegSetValueExW(hkey2,NULL,0,REG_SZ,
1180                         (LPVOID)package->classes[progid->ClassIndex].CLSID, 
1181                         (strlenW(package->classes[progid->ClassIndex].CLSID)+1)
1182                         * sizeof(WCHAR));
1183
1184         if (clsid)
1185             strcpyW(clsid,package->classes[progid->ClassIndex].CLSID);
1186
1187         RegCloseKey(hkey2);
1188     }
1189     else
1190     {
1191         FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
1192     }
1193
1194     if (progid->IconPath)
1195     {
1196         RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
1197
1198         RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)progid->IconPath,
1199                            (strlenW(progid->IconPath)+1) * sizeof(WCHAR));
1200         RegCloseKey(hkey2);
1201     }
1202     return ERROR_SUCCESS;
1203 }
1204
1205 static UINT register_progid(MSIPACKAGE *package, MSIPROGID* progid, 
1206                 LPWSTR clsid)
1207 {
1208     UINT rc = ERROR_SUCCESS; 
1209
1210     if (progid->ParentIndex < 0)
1211         rc = register_progid_base(package, progid, clsid);
1212     else
1213     {
1214         DWORD disp;
1215         HKEY hkey,hkey2;
1216         static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
1217         static const WCHAR szDefaultIcon[] =
1218             {'D','e','f','a','u','l','t','I','c','o','n',0};
1219         static const WCHAR szCurVer[] =
1220             {'C','u','r','V','e','r',0};
1221
1222         /* check if already registered */
1223         RegCreateKeyExW(HKEY_CLASSES_ROOT, progid->ProgID, 0, NULL, 0,
1224                         KEY_ALL_ACCESS, NULL, &hkey, &disp );
1225         if (disp == REG_OPENED_EXISTING_KEY)
1226         {
1227             TRACE("Key already registered\n");
1228             RegCloseKey(hkey);
1229             return rc;
1230         }
1231
1232         TRACE("Registering Parent %s index %i\n",
1233                     debugstr_w(package->progids[progid->ParentIndex].ProgID), 
1234                     progid->ParentIndex);
1235         rc = register_progid(package,&package->progids[progid->ParentIndex],
1236                         clsid);
1237
1238         /* clsid is same as parent */
1239         RegCreateKeyW(hkey,szCLSID,&hkey2);
1240         RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) *
1241                        sizeof(WCHAR));
1242
1243         RegCloseKey(hkey2);
1244
1245
1246         if (progid->Description)
1247         {
1248             RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid->Description,
1249                            (strlenW(progid->Description)+1) * sizeof(WCHAR));
1250         }
1251
1252         if (progid->IconPath)
1253         {
1254             RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
1255             RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)progid->IconPath,
1256                            (strlenW(progid->IconPath)+1) * sizeof(WCHAR));
1257             RegCloseKey(hkey2);
1258         }
1259
1260         /* write out the current version */
1261         if (progid->CurVerIndex >= 0)
1262         {
1263             RegCreateKeyW(hkey,szCurVer,&hkey2);
1264             RegSetValueExW(hkey2,NULL,0,REG_SZ,
1265                 (LPVOID)package->progids[progid->CurVerIndex].ProgID,
1266                 (strlenW(package->progids[progid->CurVerIndex].ProgID)+1) * 
1267                 sizeof(WCHAR));
1268             RegCloseKey(hkey2);
1269         }
1270
1271         RegCloseKey(hkey);
1272     }
1273     return rc;
1274 }
1275
1276 UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
1277 {
1278     INT i;
1279     MSIRECORD *uirow;
1280
1281     if (!package)
1282         return ERROR_INVALID_HANDLE;
1283
1284     load_classes_and_such(package);
1285
1286     for (i = 0; i < package->loaded_progids; i++)
1287     {
1288         WCHAR clsid[0x1000];
1289
1290         /* check if this progid is to be installed */
1291         package->progids[i].InstallMe =  ((package->progids[i].InstallMe) ||
1292               (package->progids[i].ClassIndex >= 0 &&
1293               package->classes[package->progids[i].ClassIndex].Installed));
1294
1295         if (!package->progids[i].InstallMe)
1296         {
1297             TRACE("progid %s not scheduled to be installed\n",
1298                              debugstr_w(package->progids[i].ProgID));
1299             continue;
1300         }
1301        
1302         TRACE("Registering progid %s index %i\n",
1303                         debugstr_w(package->progids[i].ProgID), i);
1304
1305         register_progid(package,&package->progids[i],clsid);
1306
1307         uirow = MSI_CreateRecord(1);
1308         MSI_RecordSetStringW(uirow,1,package->progids[i].ProgID);
1309         ui_actiondata(package,szRegisterProgIdInfo,uirow);
1310         msiobj_release(&uirow->hdr);
1311     }
1312
1313     return ERROR_SUCCESS;
1314 }
1315
1316 static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid, 
1317                 MSICOMPONENT* component, MSIEXTENSION* extension,
1318                 MSIVERB* verb, INT* Sequence )
1319 {
1320     LPWSTR keyname;
1321     HKEY key;
1322     static const WCHAR szShell[] = {'s','h','e','l','l',0};
1323     static const WCHAR szCommand[] = {'c','o','m','m','a','n','d',0};
1324     static const WCHAR fmt[] = {'\"','%','s','\"',' ','%','s',0};
1325     static const WCHAR fmt2[] = {'\"','%','s','\"',0};
1326     LPWSTR command;
1327     DWORD size;
1328     LPWSTR advertise;
1329
1330     keyname = build_directory_name(4, progid, szShell, verb->Verb, szCommand);
1331
1332     TRACE("Making Key %s\n",debugstr_w(keyname));
1333     RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
1334     size = strlenW(component->FullKeypath);
1335     if (verb->Argument)
1336         size += strlenW(verb->Argument);
1337      size += 4;
1338
1339      command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR));
1340      if (verb->Argument)
1341         sprintfW(command, fmt, component->FullKeypath, verb->Argument);
1342      else
1343         sprintfW(command, fmt2, component->FullKeypath);
1344
1345      RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)command, (strlenW(command)+1)*
1346                      sizeof(WCHAR));
1347      HeapFree(GetProcessHeap(),0,command);
1348
1349      advertise = create_component_advertise_string(package, component, 
1350                         package->features[extension->FeatureIndex].Feature);
1351
1352      size = strlenW(advertise);
1353
1354      if (verb->Argument)
1355         size += strlenW(verb->Argument);
1356      size += 4;
1357
1358      command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR));
1359      memset(command,0,size*sizeof(WCHAR));
1360
1361      strcpyW(command,advertise);
1362      if (verb->Argument)
1363      {
1364         static const WCHAR szSpace[] = {' ',0};
1365          strcatW(command,szSpace);
1366          strcatW(command,verb->Argument);
1367      }
1368
1369      RegSetValueExW(key, szCommand, 0, REG_MULTI_SZ, (LPBYTE)command,
1370                         (strlenW(command)+2)*sizeof(WCHAR));
1371      
1372      RegCloseKey(key);
1373      HeapFree(GetProcessHeap(),0,keyname);
1374      HeapFree(GetProcessHeap(),0,advertise);
1375      HeapFree(GetProcessHeap(),0,command);
1376
1377      if (verb->Command)
1378      {
1379         keyname = build_directory_name(3, progid, szShell, verb->Verb);
1380         RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
1381         RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)verb->Command,
1382                                     (strlenW(verb->Command)+1) *sizeof(WCHAR));
1383         RegCloseKey(key);
1384         HeapFree(GetProcessHeap(),0,keyname);
1385      }
1386
1387      if (verb->Sequence != MSI_NULL_INTEGER)
1388      {
1389         if (*Sequence == MSI_NULL_INTEGER || verb->Sequence < *Sequence)
1390         {
1391             *Sequence = verb->Sequence;
1392             keyname = build_directory_name(2, progid, szShell);
1393             RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
1394             RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)verb->Verb,
1395                             (strlenW(verb->Verb)+1) *sizeof(WCHAR));
1396             RegCloseKey(key);
1397             HeapFree(GetProcessHeap(),0,keyname);
1398         }
1399     }
1400     return ERROR_SUCCESS;
1401 }
1402
1403 UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
1404 {
1405     static const WCHAR szContentType[] = 
1406         {'C','o','n','t','e','n','t',' ','T','y','p','e',0 };
1407     HKEY hkey;
1408     INT i;
1409     MSIRECORD *uirow;
1410     BOOL install_on_demand = TRUE;
1411
1412     if (!package)
1413         return ERROR_INVALID_HANDLE;
1414
1415     load_classes_and_such(package);
1416
1417     /* We need to set install_on_demand based on if the shell handles advertised
1418      * shortcuts and the like. Because Mike McCormack is working on this i am
1419      * going to default to TRUE
1420      */
1421     
1422     for (i = 0; i < package->loaded_extensions; i++)
1423     {
1424         WCHAR extension[257];
1425         INT f_index;
1426      
1427         if (!package->extensions[i].Component)
1428             continue;
1429
1430         f_index = package->extensions[i].FeatureIndex;
1431
1432         /* 
1433          * yes. MSDN says that these are based on _Feature_ not on
1434          * Component.  So verify the feature is to be installed
1435          */
1436         if ((!ACTION_VerifyFeatureForAction(package, f_index,
1437                                 INSTALLSTATE_LOCAL)) &&
1438              !(install_on_demand && ACTION_VerifyFeatureForAction(package,
1439                              f_index, INSTALLSTATE_ADVERTISED)))
1440         {
1441             TRACE("Skipping extension  %s reg due to disabled feature %s\n",
1442                             debugstr_w(package->extensions[i].Extension),
1443                             debugstr_w(package->features[f_index].Feature));
1444
1445             continue;
1446         }
1447
1448         TRACE("Registering extension %s index %i\n",
1449                         debugstr_w(package->extensions[i].Extension), i);
1450
1451         package->extensions[i].Installed = TRUE;
1452
1453         /* this is only registered if the extension has at least 1 verb
1454          * according to MSDN
1455          */
1456         if (package->extensions[i].ProgIDIndex >= 0 &&
1457                 package->extensions[i].VerbCount > 0)
1458            mark_progid_for_install(package, package->extensions[i].ProgIDIndex);
1459
1460         if (package->extensions[i].MIMEIndex >= 0)
1461            mark_mime_for_install(package, package->extensions[i].MIMEIndex);
1462
1463         extension[0] = '.';
1464         extension[1] = 0;
1465         strcatW(extension,package->extensions[i].Extension);
1466
1467         RegCreateKeyW(HKEY_CLASSES_ROOT,extension,&hkey);
1468
1469         if (package->extensions[i].MIMEIndex >= 0)
1470         {
1471             RegSetValueExW(hkey,szContentType,0,REG_SZ,
1472                             (LPVOID)package->mimes[package->extensions[i].
1473                                 MIMEIndex].ContentType,
1474                            (strlenW(package->mimes[package->extensions[i].
1475                                     MIMEIndex].ContentType)+1)*sizeof(WCHAR));
1476         }
1477
1478         if (package->extensions[i].ProgIDIndex >= 0 || 
1479             package->extensions[i].ProgIDText)
1480         {
1481             static const WCHAR szSN[] = 
1482                 {'\\','S','h','e','l','l','N','e','w',0};
1483             HKEY hkey2;
1484             LPWSTR newkey;
1485             LPCWSTR progid;
1486             INT v;
1487             INT Sequence = MSI_NULL_INTEGER;
1488             
1489             if (package->extensions[i].ProgIDIndex >= 0)
1490                 progid = package->progids[package->extensions[i].
1491                     ProgIDIndex].ProgID;
1492             else
1493                 progid = package->extensions[i].ProgIDText;
1494
1495             RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid,
1496                            (strlenW(progid)+1)*sizeof(WCHAR));
1497
1498             newkey = HeapAlloc(GetProcessHeap(),0,
1499                            (strlenW(progid)+strlenW(szSN)+1) * sizeof(WCHAR)); 
1500
1501             strcpyW(newkey,progid);
1502             strcatW(newkey,szSN);
1503             RegCreateKeyW(hkey,newkey,&hkey2);
1504             RegCloseKey(hkey2);
1505
1506             HeapFree(GetProcessHeap(),0,newkey);
1507
1508             /* do all the verbs */
1509             for (v = 0; v < package->extensions[i].VerbCount; v++)
1510                 register_verb(package, progid, 
1511                               package->extensions[i].Component,
1512                               &package->extensions[i],
1513                               &package->verbs[package->extensions[i].Verbs[v]], 
1514                               &Sequence);
1515         }
1516         
1517         RegCloseKey(hkey);
1518
1519         uirow = MSI_CreateRecord(1);
1520         MSI_RecordSetStringW(uirow,1,package->extensions[i].Extension);
1521         ui_actiondata(package,szRegisterExtensionInfo,uirow);
1522         msiobj_release(&uirow->hdr);
1523     }
1524
1525     return ERROR_SUCCESS;
1526 }
1527
1528 UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package)
1529 {
1530     static const WCHAR szExten[] = 
1531         {'E','x','t','e','n','s','i','o','n',0 };
1532     HKEY hkey;
1533     INT i;
1534     MSIRECORD *uirow;
1535
1536     if (!package)
1537         return ERROR_INVALID_HANDLE;
1538
1539     load_classes_and_such(package);
1540
1541     for (i = 0; i < package->loaded_mimes; i++)
1542     {
1543         WCHAR extension[257];
1544         LPCWSTR exten;
1545         LPCWSTR mime;
1546         static const WCHAR fmt[] = 
1547             {'M','I','M','E','\\','D','a','t','a','b','a','s','e','\\',
1548              'C','o','n','t','e','n','t',' ','T','y','p','e','\\', '%','s',0};
1549         LPWSTR key;
1550
1551         /* 
1552          * check if the MIME is to be installed. Either as requesed by an
1553          * extension or Class
1554          */
1555         package->mimes[i].InstallMe =  ((package->mimes[i].InstallMe) ||
1556               (package->mimes[i].ClassIndex >= 0 &&
1557               package->classes[package->mimes[i].ClassIndex].Installed) ||
1558               (package->mimes[i].ExtensionIndex >=0 &&
1559               package->extensions[package->mimes[i].ExtensionIndex].Installed));
1560
1561         if (!package->mimes[i].InstallMe)
1562         {
1563             TRACE("MIME %s not scheduled to be installed\n",
1564                              debugstr_w(package->mimes[i].ContentType));
1565             continue;
1566         }
1567         
1568         mime = package->mimes[i].ContentType;
1569         exten = package->extensions[package->mimes[i].ExtensionIndex].Extension;
1570         extension[0] = '.';
1571         extension[1] = 0;
1572         strcatW(extension,exten);
1573
1574         key = HeapAlloc(GetProcessHeap(),0,(strlenW(mime)+strlenW(fmt)+1) *
1575                                             sizeof(WCHAR));
1576         sprintfW(key,fmt,mime);
1577         RegCreateKeyW(HKEY_CLASSES_ROOT,key,&hkey);
1578         RegSetValueExW(hkey,szExten,0,REG_SZ,(LPVOID)extension,
1579                            (strlenW(extension)+1)*sizeof(WCHAR));
1580
1581         HeapFree(GetProcessHeap(),0,key);
1582
1583         if (package->mimes[i].CLSID[0])
1584         {
1585             FIXME("Handle non null for field 3\n");
1586         }
1587
1588         RegCloseKey(hkey);
1589
1590         uirow = MSI_CreateRecord(2);
1591         MSI_RecordSetStringW(uirow,1,package->mimes[i].ContentType);
1592         MSI_RecordSetStringW(uirow,2,exten);
1593         ui_actiondata(package,szRegisterMIMEInfo,uirow);
1594         msiobj_release(&uirow->hdr);
1595     }
1596
1597     return ERROR_SUCCESS;
1598 }