- action.c is getting too big, so split out all the handling of
[wine.git] / dlls / msi / action.c
blobd0953c34f297ea3ea3c07e9038abd89b35c8cd9d
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004 Aric Stewart for CodeWeavers
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.
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.
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
22 * Pages I need
24 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
26 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
29 #include <stdarg.h>
30 #include <stdio.h>
32 #define COBJMACROS
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "winreg.h"
38 #include "wine/debug.h"
39 #include "fdi.h"
40 #include "msi.h"
41 #include "msiquery.h"
42 #include "msvcrt/fcntl.h"
43 #include "objbase.h"
44 #include "objidl.h"
45 #include "msipriv.h"
46 #include "winnls.h"
47 #include "winuser.h"
48 #include "shlobj.h"
49 #include "wine/unicode.h"
50 #include "ver.h"
51 #include "action.h"
53 #define REG_PROGRESS_VALUE 13200
54 #define COMPONENT_PROGRESS_VALUE 24000
56 WINE_DEFAULT_DEBUG_CHANNEL(msi);
59 * Prototypes
61 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
62 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
64 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq);
65 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action);
67 static UINT ACTION_LaunchConditions(MSIPACKAGE *package);
68 static UINT ACTION_CostInitialize(MSIPACKAGE *package);
69 static UINT ACTION_CreateFolders(MSIPACKAGE *package);
70 static UINT ACTION_CostFinalize(MSIPACKAGE *package);
71 static UINT ACTION_FileCost(MSIPACKAGE *package);
72 static UINT ACTION_InstallFiles(MSIPACKAGE *package);
73 static UINT ACTION_DuplicateFiles(MSIPACKAGE *package);
74 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package);
75 static UINT ACTION_InstallInitialize(MSIPACKAGE *package);
76 static UINT ACTION_InstallValidate(MSIPACKAGE *package);
77 static UINT ACTION_ProcessComponents(MSIPACKAGE *package);
78 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package);
79 static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package);
80 static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package);
81 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package);
82 static UINT ACTION_PublishProduct(MSIPACKAGE *package);
83 static UINT ACTION_WriteIniValues(MSIPACKAGE *package);
84 static UINT ACTION_SelfRegModules(MSIPACKAGE *package);
85 static UINT ACTION_PublishFeatures(MSIPACKAGE *package);
86 static UINT ACTION_RegisterProduct(MSIPACKAGE *package);
87 static UINT ACTION_InstallExecute(MSIPACKAGE *package);
88 static UINT ACTION_InstallFinalize(MSIPACKAGE *package);
89 static UINT ACTION_ForceReboot(MSIPACKAGE *package);
92 static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name,
93 LPWSTR *FilePath);
96 * consts and values used
98 static const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0};
99 static const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0};
100 static const WCHAR cszTargetDir[] = {'T','A','R','G','E','T','D','I','R',0};
101 static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
102 static const WCHAR cszDatabase[]={'D','A','T','A','B','A','S','E',0};
103 static const WCHAR c_collen[] = {'C',':','\\',0};
105 static const WCHAR cszbs[]={'\\',0};
107 const static WCHAR szCreateFolders[] =
108 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
109 const static WCHAR szCostFinalize[] =
110 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
111 const static WCHAR szInstallFiles[] =
112 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
113 const static WCHAR szDuplicateFiles[] =
114 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
115 const static WCHAR szWriteRegistryValues[] =
116 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
117 const static WCHAR szCostInitialize[] =
118 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
119 const static WCHAR szFileCost[] = {'F','i','l','e','C','o','s','t',0};
120 const static WCHAR szInstallInitialize[] =
121 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
122 const static WCHAR szInstallValidate[] =
123 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
124 const static WCHAR szLaunchConditions[] =
125 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
126 const static WCHAR szProcessComponents[] =
127 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
128 const static WCHAR szRegisterTypeLibraries[] =
129 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r',
130 'i','e','s',0};
131 const static WCHAR szRegisterClassInfo[] =
132 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
133 const static WCHAR szRegisterProgIdInfo[] =
134 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
135 const static WCHAR szCreateShortcuts[] =
136 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
137 const static WCHAR szPublishProduct[] =
138 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
139 const static WCHAR szWriteIniValues[] =
140 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
141 const static WCHAR szSelfRegModules[] =
142 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
143 const static WCHAR szPublishFeatures[] =
144 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
145 const static WCHAR szRegisterProduct[] =
146 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
147 const static WCHAR szInstallExecute[] =
148 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
149 const static WCHAR szInstallExecuteAgain[] =
150 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
151 const static WCHAR szInstallFinalize[] =
152 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
153 const static WCHAR szForceReboot[] =
154 {'F','o','r','c','e','R','e','b','o','o','t',0};
156 /********************************************************
157 * helper functions to get around current HACKS and such
158 ********************************************************/
159 inline static void reduce_to_longfilename(WCHAR* filename)
161 LPWSTR p = strchrW(filename,'|');
162 if (p)
163 memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR));
166 WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index)
168 UINT rc;
169 DWORD sz;
170 LPWSTR ret;
172 sz = 0;
173 if (MSI_RecordIsNull(row,index))
174 return NULL;
176 rc = MSI_RecordGetStringW(row,index,NULL,&sz);
178 /* having an empty string is different than NULL */
179 if (sz == 0)
181 ret = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR));
182 ret[0] = 0;
183 return ret;
186 sz ++;
187 ret = HeapAlloc(GetProcessHeap(),0,sz * sizeof (WCHAR));
188 rc = MSI_RecordGetStringW(row,index,ret,&sz);
189 if (rc!=ERROR_SUCCESS)
191 ERR("Unable to load dynamic string\n");
192 HeapFree(GetProcessHeap(), 0, ret);
193 ret = NULL;
195 return ret;
198 LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, UINT* rc)
200 DWORD sz = 0;
201 LPWSTR str;
202 UINT r;
204 r = MSI_GetPropertyW(package, prop, NULL, &sz);
205 if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
207 if (rc)
208 *rc = r;
209 return NULL;
211 sz++;
212 str = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
213 r = MSI_GetPropertyW(package, prop, str, &sz);
214 if (r != ERROR_SUCCESS)
216 HeapFree(GetProcessHeap(),0,str);
217 str = NULL;
219 if (rc)
220 *rc = r;
221 return str;
224 int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component )
226 int rc = -1;
227 DWORD i;
229 for (i = 0; i < package->loaded_components; i++)
231 if (strcmpW(Component,package->components[i].Component)==0)
233 rc = i;
234 break;
237 return rc;
240 int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature )
242 int rc = -1;
243 DWORD i;
245 for (i = 0; i < package->loaded_features; i++)
247 if (strcmpW(Feature,package->features[i].Feature)==0)
249 rc = i;
250 break;
253 return rc;
256 int get_loaded_file(MSIPACKAGE* package, LPCWSTR file)
258 int rc = -1;
259 DWORD i;
261 for (i = 0; i < package->loaded_files; i++)
263 if (strcmpW(file,package->files[i].File)==0)
265 rc = i;
266 break;
269 return rc;
272 int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path)
274 DWORD i;
275 DWORD index;
277 if (!package)
278 return -2;
280 for (i=0; i < package->loaded_files; i++)
281 if (strcmpW(package->files[i].File,name)==0)
282 return -1;
284 index = package->loaded_files;
285 package->loaded_files++;
286 if (package->loaded_files== 1)
287 package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
288 else
289 package->files = HeapReAlloc(GetProcessHeap(),0,
290 package->files , package->loaded_files * sizeof(MSIFILE));
292 memset(&package->files[index],0,sizeof(MSIFILE));
294 package->files[index].File = dupstrW(name);
295 package->files[index].TargetPath = dupstrW(path);
296 package->files[index].Temporary = TRUE;
298 TRACE("Tracking tempfile (%s)\n",debugstr_w(package->files[index].File));
300 return 0;
303 static void remove_tracked_tempfiles(MSIPACKAGE* package)
305 DWORD i;
307 if (!package)
308 return;
310 for (i = 0; i < package->loaded_files; i++)
312 if (package->files[i].Temporary)
314 TRACE("Cleaning up %s\n",debugstr_w(package->files[i].TargetPath));
315 DeleteFileW(package->files[i].TargetPath);
321 /* wrapper to resist a need for a full rewrite right now */
322 DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data )
324 if (ptr)
326 MSIRECORD *rec = MSI_CreateRecord(1);
327 DWORD size = 0;
328 WCHAR size_buf[2] = {' ',0};
330 MSI_RecordSetStringW(rec,0,ptr);
331 MSI_FormatRecordW(package,rec,size_buf,&size);
332 if (size > 0)
334 size++;
335 *data = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
336 MSI_FormatRecordW(package,rec,*data,&size);
337 return sizeof(WCHAR)*size;
341 *data = NULL;
342 return 0;
345 /* Called when the package is being closed */
346 void ACTION_free_package_structures( MSIPACKAGE* package)
348 INT i;
350 TRACE("Freeing package action data\n");
352 remove_tracked_tempfiles(package);
354 /* No dynamic buffers in features */
355 if (package->features && package->loaded_features > 0)
356 HeapFree(GetProcessHeap(),0,package->features);
358 for (i = 0; i < package->loaded_folders; i++)
360 HeapFree(GetProcessHeap(),0,package->folders[i].Directory);
361 HeapFree(GetProcessHeap(),0,package->folders[i].TargetDefault);
362 HeapFree(GetProcessHeap(),0,package->folders[i].SourceDefault);
363 HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);
364 HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedSource);
365 HeapFree(GetProcessHeap(),0,package->folders[i].Property);
367 if (package->folders && package->loaded_folders > 0)
368 HeapFree(GetProcessHeap(),0,package->folders);
370 /* no dynamic buffers in components */
371 if (package->components && package->loaded_components > 0)
372 HeapFree(GetProcessHeap(),0,package->components);
374 for (i = 0; i < package->loaded_files; i++)
376 HeapFree(GetProcessHeap(),0,package->files[i].File);
377 HeapFree(GetProcessHeap(),0,package->files[i].FileName);
378 HeapFree(GetProcessHeap(),0,package->files[i].Version);
379 HeapFree(GetProcessHeap(),0,package->files[i].Language);
380 HeapFree(GetProcessHeap(),0,package->files[i].SourcePath);
381 HeapFree(GetProcessHeap(),0,package->files[i].TargetPath);
384 if (package->files && package->loaded_files > 0)
385 HeapFree(GetProcessHeap(),0,package->files);
387 for (i = 0; i < package->DeferredActionCount; i++)
388 HeapFree(GetProcessHeap(),0,package->DeferredAction[i]);
389 HeapFree(GetProcessHeap(),0,package->DeferredAction);
391 for (i = 0; i < package->CommitActionCount; i++)
392 HeapFree(GetProcessHeap(),0,package->CommitAction[i]);
393 HeapFree(GetProcessHeap(),0,package->CommitAction);
395 HeapFree(GetProcessHeap(),0,package->PackagePath);
398 static void ui_progress(MSIPACKAGE *package, int a, int b, int c, int d )
400 MSIRECORD * row;
402 row = MSI_CreateRecord(4);
403 MSI_RecordSetInteger(row,1,a);
404 MSI_RecordSetInteger(row,2,b);
405 MSI_RecordSetInteger(row,3,c);
406 MSI_RecordSetInteger(row,4,d);
407 MSI_ProcessMessage(package, INSTALLMESSAGE_PROGRESS, row);
408 msiobj_release(&row->hdr);
411 static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)
413 static const WCHAR Query_t[] =
414 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',
415 'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',
416 ' ','\'','%','s','\'',0};
417 WCHAR message[1024];
418 UINT rc;
419 MSIQUERY * view;
420 MSIRECORD * row = 0;
421 DWORD size;
423 if (!package->LastAction || strcmpW(package->LastAction,action))
425 rc = MSI_OpenQuery(package->db, &view, Query_t, action);
426 if (rc != ERROR_SUCCESS)
427 return;
429 rc = MSI_ViewExecute(view, 0);
430 if (rc != ERROR_SUCCESS)
432 MSI_ViewClose(view);
433 return;
435 rc = MSI_ViewFetch(view,&row);
436 if (rc != ERROR_SUCCESS)
438 MSI_ViewClose(view);
439 return;
442 if (MSI_RecordIsNull(row,3))
444 msiobj_release(&row->hdr);
445 MSI_ViewClose(view);
446 msiobj_release(&view->hdr);
447 return;
450 /* update the cached actionformat */
451 HeapFree(GetProcessHeap(),0,package->ActionFormat);
452 package->ActionFormat = load_dynamic_stringW(row,3);
454 HeapFree(GetProcessHeap(),0,package->LastAction);
455 package->LastAction = dupstrW(action);
457 msiobj_release(&row->hdr);
458 MSI_ViewClose(view);
459 msiobj_release(&view->hdr);
462 MSI_RecordSetStringW(record,0,package->ActionFormat);
463 size = 1024;
464 MSI_FormatRecordW(package,record,message,&size);
466 row = MSI_CreateRecord(1);
467 MSI_RecordSetStringW(row,1,message);
469 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
470 msiobj_release(&row->hdr);
474 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
476 static const WCHAR template_s[]=
477 {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ','%','s','.',0};
478 static const WCHAR format[] =
479 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
480 static const WCHAR Query_t[] =
481 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',
482 'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',
483 ' ','\'','%','s','\'',0};
484 WCHAR message[1024];
485 WCHAR timet[0x100];
486 UINT rc;
487 MSIQUERY * view;
488 MSIRECORD * row = 0;
489 WCHAR *ActionText=NULL;
491 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
493 rc = MSI_OpenQuery(package->db, &view, Query_t, action);
494 if (rc != ERROR_SUCCESS)
495 return;
496 rc = MSI_ViewExecute(view, 0);
497 if (rc != ERROR_SUCCESS)
499 MSI_ViewClose(view);
500 msiobj_release(&view->hdr);
501 return;
503 rc = MSI_ViewFetch(view,&row);
504 if (rc != ERROR_SUCCESS)
506 MSI_ViewClose(view);
507 msiobj_release(&view->hdr);
508 return;
511 ActionText = load_dynamic_stringW(row,2);
512 msiobj_release(&row->hdr);
513 MSI_ViewClose(view);
514 msiobj_release(&view->hdr);
516 sprintfW(message,template_s,timet,action,ActionText);
518 row = MSI_CreateRecord(1);
519 MSI_RecordSetStringW(row,1,message);
521 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
522 msiobj_release(&row->hdr);
523 HeapFree(GetProcessHeap(),0,ActionText);
526 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
527 UINT rc)
529 MSIRECORD * row;
530 static const WCHAR template_s[]=
531 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ','%','s',
532 '.',0};
533 static const WCHAR template_e[]=
534 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ','%','s',
535 '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ','%','i','.',0};
536 static const WCHAR format[] =
537 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
538 WCHAR message[1024];
539 WCHAR timet[0x100];
541 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
542 if (start)
543 sprintfW(message,template_s,timet,action);
544 else
545 sprintfW(message,template_e,timet,action,rc);
547 row = MSI_CreateRecord(1);
548 MSI_RecordSetStringW(row,1,message);
550 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
551 msiobj_release(&row->hdr);
555 * build_directory_name()
557 * This function is to save messing round with directory names
558 * It handles adding backslashes between path segments,
559 * and can add \ at the end of the directory name if told to.
561 * It takes a variable number of arguments.
562 * It always allocates a new string for the result, so make sure
563 * to free the return value when finished with it.
565 * The first arg is the number of path segments that follow.
566 * The arguments following count are a list of path segments.
567 * A path segment may be NULL.
569 * Path segments will be added with a \ separating them.
570 * A \ will not be added after the last segment, however if the
571 * last segment is NULL, then the last character will be a \
574 static LPWSTR build_directory_name(DWORD count, ...)
576 DWORD sz = 1, i;
577 LPWSTR dir;
578 va_list va;
580 va_start(va,count);
581 for(i=0; i<count; i++)
583 LPCWSTR str = va_arg(va,LPCWSTR);
584 if (str)
585 sz += strlenW(str) + 1;
587 va_end(va);
589 dir = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR));
590 dir[0]=0;
592 va_start(va,count);
593 for(i=0; i<count; i++)
595 LPCWSTR str = va_arg(va,LPCWSTR);
596 if (!str)
597 continue;
598 strcatW(dir, str);
599 if( ((i+1)!=count) && dir[strlenW(dir)-1]!='\\')
600 strcatW(dir, cszbs);
602 return dir;
606 /****************************************************
607 * TOP level entry points
608 *****************************************************/
610 UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath,
611 LPCWSTR szCommandLine)
613 DWORD sz;
614 WCHAR buffer[10];
615 UINT rc;
616 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
617 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
618 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
620 MSI_SetPropertyW(package, szAction, szInstall);
622 if (szPackagePath)
624 LPWSTR p, check, path;
626 package->PackagePath = dupstrW(szPackagePath);
627 path = dupstrW(szPackagePath);
628 p = strrchrW(path,'\\');
629 if (p)
631 p++;
632 *p=0;
635 check = load_dynamic_property(package, cszSourceDir,NULL);
636 if (!check)
637 MSI_SetPropertyW(package, cszSourceDir, path);
638 else
639 HeapFree(GetProcessHeap(), 0, check);
641 HeapFree(GetProcessHeap(), 0, path);
644 if (szCommandLine)
646 LPWSTR ptr,ptr2;
647 ptr = (LPWSTR)szCommandLine;
649 while (*ptr)
651 WCHAR *prop = NULL;
652 WCHAR *val = NULL;
654 TRACE("Looking at %s\n",debugstr_w(ptr));
656 ptr2 = strchrW(ptr,'=');
657 if (ptr2)
659 BOOL quote=FALSE;
660 DWORD len = 0;
662 while (*ptr == ' ') ptr++;
663 len = ptr2-ptr;
664 prop = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
665 strncpyW(prop,ptr,len);
666 prop[len]=0;
667 ptr2++;
669 len = 0;
670 ptr = ptr2;
671 while (*ptr && (quote || (!quote && *ptr!=' ')))
673 if (*ptr == '"')
674 quote = !quote;
675 ptr++;
676 len++;
679 if (*ptr2=='"')
681 ptr2++;
682 len -= 2;
684 val = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
685 strncpyW(val,ptr2,len);
686 val[len] = 0;
688 if (strlenW(prop) > 0)
690 TRACE("Found commandline property (%s) = (%s)\n",
691 debugstr_w(prop), debugstr_w(val));
692 MSI_SetPropertyW(package,prop,val);
694 HeapFree(GetProcessHeap(),0,val);
695 HeapFree(GetProcessHeap(),0,prop);
697 ptr++;
701 sz = 10;
702 if (MSI_GetPropertyW(package,szUILevel,buffer,&sz) == ERROR_SUCCESS)
704 if (atoiW(buffer) >= INSTALLUILEVEL_REDUCED)
706 rc = ACTION_ProcessUISequence(package);
707 if (rc == ERROR_SUCCESS)
708 rc = ACTION_ProcessExecSequence(package,TRUE);
710 else
711 rc = ACTION_ProcessExecSequence(package,FALSE);
713 else
714 rc = ACTION_ProcessExecSequence(package,FALSE);
716 /* process the ending type action */
717 if (rc == ERROR_SUCCESS)
718 rc = ACTION_PerformActionSequence(package,-1);
719 else if (rc == ERROR_FUNCTION_FAILED)
720 rc = ACTION_PerformActionSequence(package,-3);
722 /* finish up running custom actions */
723 ACTION_FinishCustomActions(package);
725 return rc;
728 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
730 MSIQUERY * view;
731 UINT rc;
732 WCHAR buffer[0x100];
733 DWORD sz = 0x100;
734 MSIRECORD * row = 0;
735 static const WCHAR ExecSeqQuery[] = {
736 's','e','l','e','c','t',' ','*',' ',
737 'f','r','o','m',' ',
738 'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
739 'S','e','q','u','e','n','c','e',' ',
740 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ',
741 '=',' ','%','i',0};
743 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
745 if (rc == ERROR_SUCCESS)
747 rc = MSI_ViewExecute(view, 0);
749 if (rc != ERROR_SUCCESS)
751 MSI_ViewClose(view);
752 msiobj_release(&view->hdr);
753 goto end;
756 TRACE("Running the actions\n");
758 rc = MSI_ViewFetch(view,&row);
759 if (rc != ERROR_SUCCESS)
761 rc = ERROR_SUCCESS;
762 goto end;
765 /* check conditions */
766 if (!MSI_RecordIsNull(row,2))
768 LPWSTR cond = NULL;
769 cond = load_dynamic_stringW(row,2);
771 if (cond)
773 /* this is a hack to skip errors in the condition code */
774 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
776 HeapFree(GetProcessHeap(),0,cond);
777 msiobj_release(&row->hdr);
778 goto end;
780 else
781 HeapFree(GetProcessHeap(),0,cond);
785 sz=0x100;
786 rc = MSI_RecordGetStringW(row,1,buffer,&sz);
787 if (rc != ERROR_SUCCESS)
789 ERR("Error is %x\n",rc);
790 msiobj_release(&row->hdr);
791 goto end;
794 rc = ACTION_PerformAction(package,buffer);
795 msiobj_release(&row->hdr);
796 end:
797 MSI_ViewClose(view);
798 msiobj_release(&view->hdr);
800 else
801 rc = ERROR_SUCCESS;
803 return rc;
806 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
808 MSIQUERY * view;
809 UINT rc;
810 static const WCHAR ExecSeqQuery[] = {
811 's','e','l','e','c','t',' ','*',' ',
812 'f','r','o','m',' ',
813 'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
814 'S','e','q','u','e','n','c','e',' ',
815 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ',
816 '>',' ','%','i',' ','o','r','d','e','r',' ',
817 'b','y',' ','S','e','q','u','e','n','c','e',0 };
818 MSIRECORD * row = 0;
819 static const WCHAR IVQuery[] = {
820 's','e','l','e','c','t',' ','S','e','q','u','e','n','c','e',' ',
821 'f','r','o','m',' ','I','n','s','t','a','l','l',
822 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e',' ',
823 'w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',' ',
824 '`','I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','`',
826 INT seq = 0;
828 /* get the sequence number */
829 if (UIran)
831 rc = MSI_DatabaseOpenViewW(package->db, IVQuery, &view);
832 if (rc != ERROR_SUCCESS)
833 return rc;
834 rc = MSI_ViewExecute(view, 0);
835 if (rc != ERROR_SUCCESS)
837 MSI_ViewClose(view);
838 msiobj_release(&view->hdr);
839 return rc;
841 rc = MSI_ViewFetch(view,&row);
842 if (rc != ERROR_SUCCESS)
844 MSI_ViewClose(view);
845 msiobj_release(&view->hdr);
846 return rc;
848 seq = MSI_RecordGetInteger(row,1);
849 msiobj_release(&row->hdr);
850 MSI_ViewClose(view);
851 msiobj_release(&view->hdr);
854 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
855 if (rc == ERROR_SUCCESS)
857 rc = MSI_ViewExecute(view, 0);
859 if (rc != ERROR_SUCCESS)
861 MSI_ViewClose(view);
862 msiobj_release(&view->hdr);
863 goto end;
866 TRACE("Running the actions\n");
868 while (1)
870 WCHAR buffer[0x100];
871 DWORD sz = 0x100;
873 rc = MSI_ViewFetch(view,&row);
874 if (rc != ERROR_SUCCESS)
876 rc = ERROR_SUCCESS;
877 break;
880 /* check conditions */
881 if (!MSI_RecordIsNull(row,2))
883 LPWSTR cond = NULL;
884 cond = load_dynamic_stringW(row,2);
886 if (cond)
888 /* this is a hack to skip errors in the condition code */
889 if (MSI_EvaluateConditionW(package, cond) ==
890 MSICONDITION_FALSE)
892 HeapFree(GetProcessHeap(),0,cond);
893 msiobj_release(&row->hdr);
894 continue;
896 else
897 HeapFree(GetProcessHeap(),0,cond);
901 sz=0x100;
902 rc = MSI_RecordGetStringW(row,1,buffer,&sz);
903 if (rc != ERROR_SUCCESS)
905 ERR("Error is %x\n",rc);
906 msiobj_release(&row->hdr);
907 break;
910 rc = ACTION_PerformAction(package,buffer);
912 if (rc == ERROR_FUNCTION_NOT_CALLED)
913 rc = ERROR_SUCCESS;
915 if (rc != ERROR_SUCCESS)
917 ERR("Execution halted due to error (%i)\n",rc);
918 msiobj_release(&row->hdr);
919 break;
922 msiobj_release(&row->hdr);
925 MSI_ViewClose(view);
926 msiobj_release(&view->hdr);
929 end:
930 return rc;
934 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
936 MSIQUERY * view;
937 UINT rc;
938 static const WCHAR ExecSeqQuery [] = {
939 's','e','l','e','c','t',' ','*',' ',
940 'f','r','o','m',' ','I','n','s','t','a','l','l',
941 'U','I','S','e','q','u','e','n','c','e',' ',
942 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ', '>',' ','0',' ',
943 'o','r','d','e','r',' ','b','y',' ','S','e','q','u','e','n','c','e',0};
945 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
947 if (rc == ERROR_SUCCESS)
949 rc = MSI_ViewExecute(view, 0);
951 if (rc != ERROR_SUCCESS)
953 MSI_ViewClose(view);
954 msiobj_release(&view->hdr);
955 goto end;
958 TRACE("Running the actions \n");
960 while (1)
962 WCHAR buffer[0x100];
963 DWORD sz = 0x100;
964 MSIRECORD * row = 0;
966 rc = MSI_ViewFetch(view,&row);
967 if (rc != ERROR_SUCCESS)
969 rc = ERROR_SUCCESS;
970 break;
973 /* check conditions */
974 if (!MSI_RecordIsNull(row,2))
976 LPWSTR cond = NULL;
977 cond = load_dynamic_stringW(row,2);
979 if (cond)
981 /* this is a hack to skip errors in the condition code */
982 if (MSI_EvaluateConditionW(package, cond) ==
983 MSICONDITION_FALSE)
985 HeapFree(GetProcessHeap(),0,cond);
986 msiobj_release(&row->hdr);
987 continue;
989 else
990 HeapFree(GetProcessHeap(),0,cond);
994 sz=0x100;
995 rc = MSI_RecordGetStringW(row,1,buffer,&sz);
996 if (rc != ERROR_SUCCESS)
998 ERR("Error is %x\n",rc);
999 msiobj_release(&row->hdr);
1000 break;
1003 rc = ACTION_PerformAction(package,buffer);
1005 if (rc == ERROR_FUNCTION_NOT_CALLED)
1006 rc = ERROR_SUCCESS;
1008 if (rc != ERROR_SUCCESS)
1010 ERR("Execution halted due to error (%i)\n",rc);
1011 msiobj_release(&row->hdr);
1012 break;
1015 msiobj_release(&row->hdr);
1018 MSI_ViewClose(view);
1019 msiobj_release(&view->hdr);
1022 end:
1023 return rc;
1026 /********************************************************
1027 * ACTION helper functions and functions that perform the actions
1028 *******************************************************/
1031 * Alot of actions are really important even if they don't do anything
1032 * explicit.. Lots of properties are set at the beginning of the installation
1033 * CostFinalize does a bunch of work to translated the directories and such
1035 * But until I get write access to the database that is hard, so I am going to
1036 * hack it to see if I can get something to run.
1038 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action)
1040 UINT rc = ERROR_SUCCESS;
1042 TRACE("Performing action (%s)\n",debugstr_w(action));
1043 ui_actioninfo(package, action, TRUE, 0);
1044 ui_actionstart(package, action);
1046 /* pre install, setup and configuration block */
1047 if (strcmpW(action,szLaunchConditions)==0)
1048 rc = ACTION_LaunchConditions(package);
1049 else if (strcmpW(action,szCostInitialize)==0)
1050 rc = ACTION_CostInitialize(package);
1051 else if (strcmpW(action,szFileCost)==0)
1052 rc = ACTION_FileCost(package);
1053 else if (strcmpW(action,szCostFinalize)==0)
1054 rc = ACTION_CostFinalize(package);
1055 else if (strcmpW(action,szInstallValidate)==0)
1056 rc = ACTION_InstallValidate(package);
1058 /* install block */
1059 else if (strcmpW(action,szProcessComponents)==0)
1060 rc = ACTION_ProcessComponents(package);
1061 else if (strcmpW(action,szInstallInitialize)==0)
1062 rc = ACTION_InstallInitialize(package);
1063 else if (strcmpW(action,szCreateFolders)==0)
1064 rc = ACTION_CreateFolders(package);
1065 else if (strcmpW(action,szInstallFiles)==0)
1066 rc = ACTION_InstallFiles(package);
1067 else if (strcmpW(action,szDuplicateFiles)==0)
1068 rc = ACTION_DuplicateFiles(package);
1069 else if (strcmpW(action,szWriteRegistryValues)==0)
1070 rc = ACTION_WriteRegistryValues(package);
1071 else if (strcmpW(action,szRegisterTypeLibraries)==0)
1072 rc = ACTION_RegisterTypeLibraries(package);
1073 else if (strcmpW(action,szRegisterClassInfo)==0)
1074 rc = ACTION_RegisterClassInfo(package);
1075 else if (strcmpW(action,szRegisterProgIdInfo)==0)
1076 rc = ACTION_RegisterProgIdInfo(package);
1077 else if (strcmpW(action,szCreateShortcuts)==0)
1078 rc = ACTION_CreateShortcuts(package);
1079 else if (strcmpW(action,szPublishProduct)==0)
1080 rc = ACTION_PublishProduct(package);
1081 else if (strcmpW(action,szWriteIniValues)==0)
1082 rc = ACTION_WriteIniValues(package);
1083 else if (strcmpW(action,szSelfRegModules)==0)
1084 rc = ACTION_SelfRegModules(package);
1085 else if (strcmpW(action,szPublishFeatures)==0)
1086 rc = ACTION_PublishFeatures(package);
1087 else if (strcmpW(action,szRegisterProduct)==0)
1088 rc = ACTION_RegisterProduct(package);
1089 else if (strcmpW(action,szInstallExecute)==0)
1090 rc = ACTION_InstallExecute(package);
1091 else if (strcmpW(action,szInstallExecuteAgain)==0)
1092 rc = ACTION_InstallExecute(package);
1093 else if (strcmpW(action,szInstallFinalize)==0)
1094 rc = ACTION_InstallFinalize(package);
1095 else if (strcmpW(action,szForceReboot)==0)
1096 rc = ACTION_ForceReboot(package);
1099 Called during iTunes but unimplemented and seem important
1101 ResolveSource (sets SourceDir)
1103 else if ((rc = ACTION_CustomAction(package,action,FALSE)) != ERROR_SUCCESS)
1105 FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action));
1106 rc = ERROR_FUNCTION_NOT_CALLED;
1109 ui_actioninfo(package, action, FALSE, rc);
1110 return rc;
1113 /***********************************************************************
1114 * create_full_pathW
1116 * Recursively create all directories in the path.
1118 * shamelessly stolen from setupapi/queue.c
1120 static BOOL create_full_pathW(const WCHAR *path)
1122 BOOL ret = TRUE;
1123 int len;
1124 WCHAR *new_path;
1126 new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) *
1127 sizeof(WCHAR));
1129 strcpyW(new_path, path);
1131 while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
1132 new_path[len - 1] = 0;
1134 while(!CreateDirectoryW(new_path, NULL))
1136 WCHAR *slash;
1137 DWORD last_error = GetLastError();
1138 if(last_error == ERROR_ALREADY_EXISTS)
1139 break;
1141 if(last_error != ERROR_PATH_NOT_FOUND)
1143 ret = FALSE;
1144 break;
1147 if(!(slash = strrchrW(new_path, '\\')))
1149 ret = FALSE;
1150 break;
1153 len = slash - new_path;
1154 new_path[len] = 0;
1155 if(!create_full_pathW(new_path))
1157 ret = FALSE;
1158 break;
1160 new_path[len] = '\\';
1163 HeapFree(GetProcessHeap(), 0, new_path);
1164 return ret;
1168 * Also we cannot enable/disable components either, so for now I am just going
1169 * to do all the directories for all the components.
1171 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1173 static const WCHAR ExecSeqQuery[] = {
1174 's','e','l','e','c','t',' ','D','i','r','e','c','t','o','r','y','_',' ',
1175 'f','r','o','m',' ','C','r','e','a','t','e','F','o','l','d','e','r',0 };
1176 UINT rc;
1177 MSIQUERY *view;
1178 MSIFOLDER *folder;
1180 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1181 if (rc != ERROR_SUCCESS)
1182 return ERROR_SUCCESS;
1184 rc = MSI_ViewExecute(view, 0);
1185 if (rc != ERROR_SUCCESS)
1187 MSI_ViewClose(view);
1188 msiobj_release(&view->hdr);
1189 return rc;
1192 while (1)
1194 WCHAR dir[0x100];
1195 LPWSTR full_path;
1196 DWORD sz;
1197 MSIRECORD *row = NULL, *uirow;
1199 rc = MSI_ViewFetch(view,&row);
1200 if (rc != ERROR_SUCCESS)
1202 rc = ERROR_SUCCESS;
1203 break;
1206 sz=0x100;
1207 rc = MSI_RecordGetStringW(row,1,dir,&sz);
1209 if (rc!= ERROR_SUCCESS)
1211 ERR("Unable to get folder id \n");
1212 msiobj_release(&row->hdr);
1213 continue;
1216 sz = MAX_PATH;
1217 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1218 if (!full_path)
1220 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1221 msiobj_release(&row->hdr);
1222 continue;
1225 TRACE("Folder is %s\n",debugstr_w(full_path));
1227 /* UI stuff */
1228 uirow = MSI_CreateRecord(1);
1229 MSI_RecordSetStringW(uirow,1,full_path);
1230 ui_actiondata(package,szCreateFolders,uirow);
1231 msiobj_release( &uirow->hdr );
1233 if (folder->State == 0)
1234 create_full_pathW(full_path);
1236 folder->State = 3;
1238 msiobj_release(&row->hdr);
1239 HeapFree(GetProcessHeap(),0,full_path);
1241 MSI_ViewClose(view);
1242 msiobj_release(&view->hdr);
1244 return rc;
1247 static int load_component(MSIPACKAGE* package, MSIRECORD * row)
1249 int index = package->loaded_components;
1250 DWORD sz;
1252 /* fill in the data */
1254 package->loaded_components++;
1255 if (package->loaded_components == 1)
1256 package->components = HeapAlloc(GetProcessHeap(),0,
1257 sizeof(MSICOMPONENT));
1258 else
1259 package->components = HeapReAlloc(GetProcessHeap(),0,
1260 package->components, package->loaded_components *
1261 sizeof(MSICOMPONENT));
1263 memset(&package->components[index],0,sizeof(MSICOMPONENT));
1265 sz = 96;
1266 MSI_RecordGetStringW(row,1,package->components[index].Component,&sz);
1268 TRACE("Loading Component %s\n",
1269 debugstr_w(package->components[index].Component));
1271 sz = 0x100;
1272 if (!MSI_RecordIsNull(row,2))
1273 MSI_RecordGetStringW(row,2,package->components[index].ComponentId,&sz);
1275 sz = 96;
1276 MSI_RecordGetStringW(row,3,package->components[index].Directory,&sz);
1278 package->components[index].Attributes = MSI_RecordGetInteger(row,4);
1280 sz = 0x100;
1281 MSI_RecordGetStringW(row,5,package->components[index].Condition,&sz);
1283 sz = 96;
1284 MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz);
1286 package->components[index].Installed = INSTALLSTATE_ABSENT;
1287 package->components[index].Action = INSTALLSTATE_UNKNOWN;
1288 package->components[index].ActionRequest = INSTALLSTATE_UNKNOWN;
1290 package->components[index].Enabled = TRUE;
1292 return index;
1295 static void load_feature(MSIPACKAGE* package, MSIRECORD * row)
1297 int index = package->loaded_features;
1298 DWORD sz;
1299 static const WCHAR Query1[] = {'S','E','L','E','C','T',' ','C','o','m','p',
1300 'o','n','e','n','t','_',' ','F','R','O','M',' ','F','e','a','t','u','r','e',
1301 'C','o','m','p','o','n','e','n','t','s',' ','W','H','E','R','E',' ','F','e',
1302 'a','t','u','r','e','_','=','\'','%','s','\'',0};
1303 static const WCHAR Query2[] = {'S','E','L','E','C','T',' ','*',' ','F','R',
1304 'O','M',' ','C','o','m','p','o','n','e','n','t',' ','W','H','E','R','E',' ','C',
1305 'o','m','p','o','n','e','n','t','=','\'','%','s','\'',0};
1306 MSIQUERY * view;
1307 MSIQUERY * view2;
1308 MSIRECORD * row2;
1309 MSIRECORD * row3;
1310 UINT rc;
1312 /* fill in the data */
1314 package->loaded_features ++;
1315 if (package->loaded_features == 1)
1316 package->features = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFEATURE));
1317 else
1318 package->features = HeapReAlloc(GetProcessHeap(),0,package->features,
1319 package->loaded_features * sizeof(MSIFEATURE));
1321 memset(&package->features[index],0,sizeof(MSIFEATURE));
1323 sz = 96;
1324 MSI_RecordGetStringW(row,1,package->features[index].Feature,&sz);
1326 TRACE("Loading feature %s\n",debugstr_w(package->features[index].Feature));
1328 sz = 96;
1329 if (!MSI_RecordIsNull(row,2))
1330 MSI_RecordGetStringW(row,2,package->features[index].Feature_Parent,&sz);
1332 sz = 0x100;
1333 if (!MSI_RecordIsNull(row,3))
1334 MSI_RecordGetStringW(row,3,package->features[index].Title,&sz);
1336 sz = 0x100;
1337 if (!MSI_RecordIsNull(row,4))
1338 MSI_RecordGetStringW(row,4,package->features[index].Description,&sz);
1340 if (!MSI_RecordIsNull(row,5))
1341 package->features[index].Display = MSI_RecordGetInteger(row,5);
1343 package->features[index].Level= MSI_RecordGetInteger(row,6);
1345 sz = 96;
1346 if (!MSI_RecordIsNull(row,7))
1347 MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz);
1349 package->features[index].Attributes= MSI_RecordGetInteger(row,8);
1351 package->features[index].Installed = INSTALLSTATE_ABSENT;
1352 package->features[index].Action = INSTALLSTATE_UNKNOWN;
1353 package->features[index].ActionRequest = INSTALLSTATE_UNKNOWN;
1355 /* load feature components */
1357 rc = MSI_OpenQuery(package->db, &view, Query1, package->features[index].Feature);
1358 if (rc != ERROR_SUCCESS)
1359 return;
1360 rc = MSI_ViewExecute(view,0);
1361 if (rc != ERROR_SUCCESS)
1363 MSI_ViewClose(view);
1364 msiobj_release(&view->hdr);
1365 return;
1367 while (1)
1369 DWORD sz = 0x100;
1370 WCHAR buffer[0x100];
1371 DWORD rc;
1372 INT c_indx;
1373 INT cnt = package->features[index].ComponentCount;
1375 rc = MSI_ViewFetch(view,&row2);
1376 if (rc != ERROR_SUCCESS)
1377 break;
1379 sz = 0x100;
1380 MSI_RecordGetStringW(row2,1,buffer,&sz);
1382 /* check to see if the component is already loaded */
1383 c_indx = get_loaded_component(package,buffer);
1384 if (c_indx != -1)
1386 TRACE("Component %s already loaded at %i\n", debugstr_w(buffer),
1387 c_indx);
1388 package->features[index].Components[cnt] = c_indx;
1389 package->features[index].ComponentCount ++;
1390 continue;
1393 rc = MSI_OpenQuery(package->db, &view2, Query2, buffer);
1394 if (rc != ERROR_SUCCESS)
1396 msiobj_release( &row2->hdr );
1397 continue;
1399 rc = MSI_ViewExecute(view2,0);
1400 if (rc != ERROR_SUCCESS)
1402 msiobj_release( &row2->hdr );
1403 MSI_ViewClose(view2);
1404 msiobj_release( &view2->hdr );
1405 continue;
1407 while (1)
1409 DWORD rc;
1411 rc = MSI_ViewFetch(view2,&row3);
1412 if (rc != ERROR_SUCCESS)
1413 break;
1414 c_indx = load_component(package,row3);
1415 msiobj_release( &row3->hdr );
1417 package->features[index].Components[cnt] = c_indx;
1418 package->features[index].ComponentCount ++;
1419 TRACE("Loaded new component to index %i\n",c_indx);
1421 MSI_ViewClose(view2);
1422 msiobj_release( &view2->hdr );
1423 msiobj_release( &row2->hdr );
1425 MSI_ViewClose(view);
1426 msiobj_release(&view->hdr);
1430 * I am not doing any of the costing functionality yet.
1431 * Mostly looking at doing the Component and Feature loading
1433 * The native MSI does ALOT of modification to tables here. Mostly adding alot
1434 * of temporary columns to the Feature and Component tables.
1436 * note: native msi also tracks the short filename. but I am only going to
1437 * track the long ones. Also looking at this directory table
1438 * it appears that the directory table does not get the parents
1439 * resolved base on property only based on their entrys in the
1440 * directory table.
1442 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1444 MSIQUERY * view;
1445 MSIRECORD * row;
1446 UINT rc;
1447 static const WCHAR Query_all[] = {
1448 'S','E','L','E','C','T',' ','*',' ',
1449 'F','R','O','M',' ','F','e','a','t','u','r','e',0};
1450 static const WCHAR szCosting[] = {
1451 'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1452 static const WCHAR szZero[] = { '0', 0 };
1454 MSI_SetPropertyW(package, szCosting, szZero);
1455 MSI_SetPropertyW(package, cszRootDrive , c_collen);
1457 rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
1458 if (rc != ERROR_SUCCESS)
1459 return rc;
1460 rc = MSI_ViewExecute(view,0);
1461 if (rc != ERROR_SUCCESS)
1463 MSI_ViewClose(view);
1464 msiobj_release(&view->hdr);
1465 return rc;
1467 while (1)
1469 DWORD rc;
1471 rc = MSI_ViewFetch(view,&row);
1472 if (rc != ERROR_SUCCESS)
1473 break;
1475 load_feature(package,row);
1476 msiobj_release(&row->hdr);
1478 MSI_ViewClose(view);
1479 msiobj_release(&view->hdr);
1481 return ERROR_SUCCESS;
1484 static UINT load_file(MSIPACKAGE* package, MSIRECORD * row)
1486 DWORD index = package->loaded_files;
1487 DWORD i;
1488 LPWSTR buffer;
1490 /* fill in the data */
1492 package->loaded_files++;
1493 if (package->loaded_files== 1)
1494 package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
1495 else
1496 package->files = HeapReAlloc(GetProcessHeap(),0,
1497 package->files , package->loaded_files * sizeof(MSIFILE));
1499 memset(&package->files[index],0,sizeof(MSIFILE));
1501 package->files[index].File = load_dynamic_stringW(row, 1);
1502 buffer = load_dynamic_stringW(row, 2);
1504 package->files[index].ComponentIndex = -1;
1505 for (i = 0; i < package->loaded_components; i++)
1506 if (strcmpW(package->components[i].Component,buffer)==0)
1508 package->files[index].ComponentIndex = i;
1509 break;
1511 if (package->files[index].ComponentIndex == -1)
1512 ERR("Unfound Component %s\n",debugstr_w(buffer));
1513 HeapFree(GetProcessHeap(), 0, buffer);
1515 package->files[index].FileName = load_dynamic_stringW(row,3);
1517 reduce_to_longfilename(package->files[index].FileName);
1519 package->files[index].FileSize = MSI_RecordGetInteger(row,4);
1520 package->files[index].Version = load_dynamic_stringW(row, 5);
1521 package->files[index].Language = load_dynamic_stringW(row, 6);
1522 package->files[index].Attributes= MSI_RecordGetInteger(row,7);
1523 package->files[index].Sequence= MSI_RecordGetInteger(row,8);
1525 package->files[index].Temporary = FALSE;
1526 package->files[index].State = 0;
1528 TRACE("File Loaded (%s)\n",debugstr_w(package->files[index].File));
1530 return ERROR_SUCCESS;
1533 static UINT ACTION_FileCost(MSIPACKAGE *package)
1535 MSIQUERY * view;
1536 MSIRECORD * row;
1537 UINT rc;
1538 static const WCHAR Query[] = {
1539 'S','E','L','E','C','T',' ','*',' ',
1540 'F','R','O','M',' ','F','i','l','e',' ',
1541 'O','r','d','e','r',' ','b','y',' ','S','e','q','u','e','n','c','e', 0};
1543 if (!package)
1544 return ERROR_INVALID_HANDLE;
1546 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1547 if (rc != ERROR_SUCCESS)
1548 return ERROR_SUCCESS;
1550 rc = MSI_ViewExecute(view, 0);
1551 if (rc != ERROR_SUCCESS)
1553 MSI_ViewClose(view);
1554 msiobj_release(&view->hdr);
1555 return ERROR_SUCCESS;
1558 while (1)
1560 rc = MSI_ViewFetch(view,&row);
1561 if (rc != ERROR_SUCCESS)
1563 rc = ERROR_SUCCESS;
1564 break;
1566 load_file(package,row);
1567 msiobj_release(&row->hdr);
1569 MSI_ViewClose(view);
1570 msiobj_release(&view->hdr);
1572 return ERROR_SUCCESS;
1575 static INT load_folder(MSIPACKAGE *package, const WCHAR* dir)
1578 static const WCHAR Query[] =
1579 {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','D','i','r','e','c',
1580 't','o','r','y',' ','w','h','e','r','e',' ','`','D','i','r','e','c','t',
1581 'o','r','y','`',' ','=',' ','`','%','s','`',0};
1582 UINT rc;
1583 MSIQUERY * view;
1584 LPWSTR targetdir, parent, srcdir;
1585 MSIRECORD * row = 0;
1586 INT index = -1;
1587 DWORD i;
1589 TRACE("Looking for dir %s\n",debugstr_w(dir));
1591 for (i = 0; i < package->loaded_folders; i++)
1593 if (strcmpW(package->folders[i].Directory,dir)==0)
1595 TRACE(" %s retuning on index %lu\n",debugstr_w(dir),i);
1596 return i;
1600 TRACE("Working to load %s\n",debugstr_w(dir));
1602 index = package->loaded_folders++;
1603 if (package->loaded_folders==1)
1604 package->folders = HeapAlloc(GetProcessHeap(),0,
1605 sizeof(MSIFOLDER));
1606 else
1607 package->folders= HeapReAlloc(GetProcessHeap(),0,
1608 package->folders, package->loaded_folders*
1609 sizeof(MSIFOLDER));
1611 memset(&package->folders[index],0,sizeof(MSIFOLDER));
1613 package->folders[index].Directory = dupstrW(dir);
1615 rc = MSI_OpenQuery(package->db, &view, Query, dir);
1616 if (rc != ERROR_SUCCESS)
1617 return -1;
1619 rc = MSI_ViewExecute(view, 0);
1620 if (rc != ERROR_SUCCESS)
1622 MSI_ViewClose(view);
1623 msiobj_release(&view->hdr);
1624 return -1;
1627 rc = MSI_ViewFetch(view,&row);
1628 if (rc != ERROR_SUCCESS)
1630 MSI_ViewClose(view);
1631 msiobj_release(&view->hdr);
1632 return -1;
1635 targetdir = load_dynamic_stringW(row,3);
1637 /* split src and target dir */
1638 if (strchrW(targetdir,':'))
1640 srcdir=strchrW(targetdir,':');
1641 *srcdir=0;
1642 srcdir ++;
1644 else
1645 srcdir=NULL;
1647 /* for now only pick long filename versions */
1648 if (strchrW(targetdir,'|'))
1650 targetdir = strchrW(targetdir,'|');
1651 *targetdir = 0;
1652 targetdir ++;
1654 if (srcdir && strchrW(srcdir,'|'))
1656 srcdir= strchrW(srcdir,'|');
1657 *srcdir= 0;
1658 srcdir ++;
1661 /* now check for root dirs */
1662 if (targetdir[0] == '.' && targetdir[1] == 0)
1663 targetdir = NULL;
1665 if (srcdir && srcdir[0] == '.' && srcdir[1] == 0)
1666 srcdir = NULL;
1668 if (targetdir)
1670 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir));
1671 HeapFree(GetProcessHeap(),0, package->folders[index].TargetDefault);
1672 package->folders[index].TargetDefault = dupstrW(targetdir);
1675 if (srcdir)
1676 package->folders[index].SourceDefault = dupstrW(srcdir);
1677 else if (targetdir)
1678 package->folders[index].SourceDefault = dupstrW(targetdir);
1679 HeapFree(GetProcessHeap(), 0, targetdir);
1681 parent = load_dynamic_stringW(row,2);
1682 if (parent)
1684 i = load_folder(package,parent);
1685 package->folders[index].ParentIndex = i;
1686 TRACE("Parent is index %i... %s %s\n",
1687 package->folders[index].ParentIndex,
1688 debugstr_w(package->folders[package->folders[index].ParentIndex].Directory),
1689 debugstr_w(parent));
1691 else
1692 package->folders[index].ParentIndex = -2;
1693 HeapFree(GetProcessHeap(), 0, parent);
1695 package->folders[index].Property = load_dynamic_property(package, dir,NULL);
1697 msiobj_release(&row->hdr);
1698 MSI_ViewClose(view);
1699 msiobj_release(&view->hdr);
1700 TRACE(" %s retuning on index %i\n",debugstr_w(dir),index);
1701 return index;
1705 LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
1706 BOOL set_prop, MSIFOLDER **folder)
1708 DWORD i;
1709 LPWSTR p, path = NULL;
1711 TRACE("Working to resolve %s\n",debugstr_w(name));
1713 /* special resolving for Target and Source root dir */
1714 if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0)
1716 if (!source)
1718 path = load_dynamic_property(package,cszTargetDir,NULL);
1719 if (!path)
1721 path = load_dynamic_property(package,cszRootDrive,NULL);
1722 if (set_prop)
1723 MSI_SetPropertyW(package,cszTargetDir,path);
1725 if (folder)
1727 for (i = 0; i < package->loaded_folders; i++)
1729 if (strcmpW(package->folders[i].Directory,name)==0)
1730 break;
1732 *folder = &(package->folders[i]);
1734 return path;
1736 else
1738 path = load_dynamic_property(package,cszSourceDir,NULL);
1739 if (!path)
1741 path = load_dynamic_property(package,cszDatabase,NULL);
1742 if (path)
1744 p = strrchrW(path,'\\');
1745 if (p)
1746 *(p+1) = 0;
1749 if (folder)
1751 for (i = 0; i < package->loaded_folders; i++)
1753 if (strcmpW(package->folders[i].Directory,name)==0)
1754 break;
1756 *folder = &(package->folders[i]);
1758 return path;
1762 for (i = 0; i < package->loaded_folders; i++)
1764 if (strcmpW(package->folders[i].Directory,name)==0)
1765 break;
1768 if (i >= package->loaded_folders)
1769 return NULL;
1771 if (folder)
1772 *folder = &(package->folders[i]);
1774 if (!source && package->folders[i].ResolvedTarget)
1776 path = dupstrW(package->folders[i].ResolvedTarget);
1777 TRACE(" already resolved to %s\n",debugstr_w(path));
1778 return path;
1780 else if (source && package->folders[i].ResolvedSource)
1782 path = dupstrW(package->folders[i].ResolvedSource);
1783 return path;
1785 else if (!source && package->folders[i].Property)
1787 path = dupstrW(package->folders[i].Property);
1788 TRACE(" internally set to %s\n",debugstr_w(path));
1789 if (set_prop)
1790 MSI_SetPropertyW(package,name,path);
1791 return path;
1794 if (package->folders[i].ParentIndex >= 0)
1796 LPWSTR parent = package->folders[package->folders[i].ParentIndex].Directory;
1798 TRACE(" ! Parent is %s\n", debugstr_w(parent));
1800 p = resolve_folder(package, parent, source, set_prop, NULL);
1801 if (!source)
1803 TRACE(" TargetDefault = %s\n",debugstr_w(package->folders[i].TargetDefault));
1804 path = build_directory_name(3, p, package->folders[i].TargetDefault, NULL);
1805 package->folders[i].ResolvedTarget = dupstrW(path);
1806 TRACE(" resolved into %s\n",debugstr_w(path));
1807 if (set_prop)
1808 MSI_SetPropertyW(package,name,path);
1810 else
1812 path = build_directory_name(3, p, package->folders[i].SourceDefault, NULL);
1813 package->folders[i].ResolvedSource = dupstrW(path);
1815 HeapFree(GetProcessHeap(),0,p);
1817 return path;
1820 static UINT SetFeatureStates(MSIPACKAGE *package)
1822 LPWSTR level;
1823 INT install_level;
1824 DWORD i;
1825 INT j;
1826 LPWSTR override = NULL;
1827 static const WCHAR all[]={'A','L','L',0};
1828 static const WCHAR szlevel[] = {
1829 'I','N','S','T','A','L','L','L','E','V','E','L',0};
1830 static const WCHAR szAddLocal[] = {
1831 'A','D','D','L','O','C','A','L',0};
1833 /* I do not know if this is where it should happen.. but */
1835 TRACE("Checking Install Level\n");
1837 level = load_dynamic_property(package,szlevel,NULL);
1838 if (level)
1840 install_level = atoiW(level);
1841 HeapFree(GetProcessHeap(), 0, level);
1843 else
1844 install_level = 1;
1846 /* ok hereis the rub
1847 * ADDLOCAL and its friend OVERRIDE INSTALLLEVLE
1848 * I have confirmed this if ADDLOCALis stated then the INSTALLLEVEL is
1849 * itnored for all the features. seems strange, epsecially since it is not
1850 * documented anywhere, but it is how it works.
1853 override = load_dynamic_property(package,szAddLocal,NULL);
1855 if (override)
1857 for(i = 0; i < package->loaded_features; i++)
1859 if (strcmpiW(override,all)==0)
1861 package->features[i].ActionRequest= INSTALLSTATE_LOCAL;
1862 package->features[i].Action = INSTALLSTATE_LOCAL;
1864 else
1866 LPWSTR ptr = override;
1867 LPWSTR ptr2 = strchrW(override,',');
1869 while (ptr)
1871 if ((ptr2 &&
1872 strncmpW(ptr,package->features[i].Feature, ptr2-ptr)==0)
1873 || (!ptr2 &&
1874 strcmpW(ptr,package->features[i].Feature)==0))
1876 package->features[i].ActionRequest= INSTALLSTATE_LOCAL;
1877 package->features[i].Action = INSTALLSTATE_LOCAL;
1878 break;
1880 if (ptr2)
1882 ptr=ptr2+1;
1883 ptr2 = strchrW(ptr,',');
1885 else
1886 break;
1890 HeapFree(GetProcessHeap(),0,override);
1892 else
1894 for(i = 0; i < package->loaded_features; i++)
1896 BOOL feature_state= ((package->features[i].Level > 0) &&
1897 (package->features[i].Level <= install_level));
1899 if (feature_state)
1901 package->features[i].ActionRequest= INSTALLSTATE_LOCAL;
1902 package->features[i].Action = INSTALLSTATE_LOCAL;
1908 * now we want to enable or disable components base on feature
1911 for(i = 0; i < package->loaded_features; i++)
1913 MSIFEATURE* feature = &package->features[i];
1914 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1915 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1916 feature->ActionRequest);
1918 for( j = 0; j < feature->ComponentCount; j++)
1920 MSICOMPONENT* component = &package->components[
1921 feature->Components[j]];
1923 if (!component->Enabled)
1925 component->Action = INSTALLSTATE_ABSENT;
1926 component->ActionRequest = INSTALLSTATE_ABSENT;
1928 else
1930 if (feature->Action == INSTALLSTATE_LOCAL)
1931 component->Action = INSTALLSTATE_LOCAL;
1932 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
1933 component->ActionRequest = INSTALLSTATE_LOCAL;
1938 for(i = 0; i < package->loaded_components; i++)
1940 MSICOMPONENT* component= &package->components[i];
1942 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1943 debugstr_w(component->Component), component->Installed,
1944 component->Action, component->ActionRequest);
1948 return ERROR_SUCCESS;
1952 * Alot is done in this function aside from just the costing.
1953 * The costing needs to be implemented at some point but for now I am going
1954 * to focus on the directory building
1957 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1959 static const WCHAR ExecSeqQuery[] = {
1960 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
1961 'D','i','r','e','c','t','o','r','y',0};
1962 static const WCHAR ConditionQuery[] = {
1963 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
1964 'C','o','n','d','i','t','i','o','n',0};
1965 static const WCHAR szCosting[] = {
1966 'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1967 static const WCHAR szlevel[] = {
1968 'I','N','S','T','A','L','L','L','E','V','E','L',0};
1969 static const WCHAR szOne[] = { '1', 0 };
1970 UINT rc;
1971 MSIQUERY * view;
1972 DWORD i;
1973 LPWSTR level;
1975 TRACE("Building Directory properties\n");
1977 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1978 if (rc == ERROR_SUCCESS)
1980 rc = MSI_ViewExecute(view, 0);
1981 if (rc != ERROR_SUCCESS)
1983 MSI_ViewClose(view);
1984 msiobj_release(&view->hdr);
1985 return rc;
1988 while (1)
1990 WCHAR name[0x100];
1991 LPWSTR path;
1992 MSIRECORD * row = 0;
1993 DWORD sz;
1995 rc = MSI_ViewFetch(view,&row);
1996 if (rc != ERROR_SUCCESS)
1998 rc = ERROR_SUCCESS;
1999 break;
2002 sz=0x100;
2003 MSI_RecordGetStringW(row,1,name,&sz);
2005 /* This helper function now does ALL the work */
2006 TRACE("Dir %s ...\n",debugstr_w(name));
2007 load_folder(package,name);
2008 path = resolve_folder(package,name,FALSE,TRUE,NULL);
2009 TRACE("resolves to %s\n",debugstr_w(path));
2010 HeapFree( GetProcessHeap(), 0, path);
2012 msiobj_release(&row->hdr);
2014 MSI_ViewClose(view);
2015 msiobj_release(&view->hdr);
2018 TRACE("File calculations %i files\n",package->loaded_files);
2020 for (i = 0; i < package->loaded_files; i++)
2022 MSICOMPONENT* comp = NULL;
2023 MSIFILE* file= NULL;
2025 file = &package->files[i];
2026 if (file->ComponentIndex >= 0)
2027 comp = &package->components[file->ComponentIndex];
2029 if (file->Temporary == TRUE)
2030 continue;
2032 if (comp)
2034 LPWSTR p;
2036 /* calculate target */
2037 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
2039 HeapFree(GetProcessHeap(),0,file->TargetPath);
2041 TRACE("file %s is named %s\n",
2042 debugstr_w(file->File),debugstr_w(file->FileName));
2044 file->TargetPath = build_directory_name(2, p, file->FileName);
2046 HeapFree(GetProcessHeap(),0,p);
2048 TRACE("file %s resolves to %s\n",
2049 debugstr_w(file->File),debugstr_w(file->TargetPath));
2051 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2053 file->State = 1;
2054 comp->Cost += file->FileSize;
2056 else
2058 if (file->Version)
2060 DWORD handle;
2061 DWORD versize;
2062 UINT sz;
2063 LPVOID version;
2064 static const WCHAR name[] =
2065 {'\\',0};
2066 static const WCHAR name_fmt[] =
2067 {'%','u','.','%','u','.','%','u','.','%','u',0};
2068 WCHAR filever[0x100];
2069 VS_FIXEDFILEINFO *lpVer;
2071 TRACE("Version comparison.. \n");
2072 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
2073 version = HeapAlloc(GetProcessHeap(),0,versize);
2074 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
2076 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
2078 sprintfW(filever,name_fmt,
2079 HIWORD(lpVer->dwFileVersionMS),
2080 LOWORD(lpVer->dwFileVersionMS),
2081 HIWORD(lpVer->dwFileVersionLS),
2082 LOWORD(lpVer->dwFileVersionLS));
2084 TRACE("new %s old %s\n", debugstr_w(file->Version),
2085 debugstr_w(filever));
2086 if (strcmpiW(filever,file->Version)<0)
2088 file->State = 2;
2089 FIXME("cost should be diff in size\n");
2090 comp->Cost += file->FileSize;
2092 else
2093 file->State = 3;
2094 HeapFree(GetProcessHeap(),0,version);
2096 else
2097 file->State = 3;
2102 TRACE("Evaluating Condition Table\n");
2104 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2105 if (rc == ERROR_SUCCESS)
2107 rc = MSI_ViewExecute(view, 0);
2108 if (rc != ERROR_SUCCESS)
2110 MSI_ViewClose(view);
2111 msiobj_release(&view->hdr);
2112 return rc;
2115 while (1)
2117 WCHAR Feature[0x100];
2118 MSIRECORD * row = 0;
2119 DWORD sz;
2120 int feature_index;
2122 rc = MSI_ViewFetch(view,&row);
2124 if (rc != ERROR_SUCCESS)
2126 rc = ERROR_SUCCESS;
2127 break;
2130 sz = 0x100;
2131 MSI_RecordGetStringW(row,1,Feature,&sz);
2133 feature_index = get_loaded_feature(package,Feature);
2134 if (feature_index < 0)
2135 ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature));
2136 else
2138 LPWSTR Condition;
2139 Condition = load_dynamic_stringW(row,3);
2141 if (MSI_EvaluateConditionW(package,Condition) ==
2142 MSICONDITION_TRUE)
2144 int level = MSI_RecordGetInteger(row,2);
2145 TRACE("Reseting feature %s to level %i\n",
2146 debugstr_w(Feature), level);
2147 package->features[feature_index].Level = level;
2149 HeapFree(GetProcessHeap(),0,Condition);
2152 msiobj_release(&row->hdr);
2154 MSI_ViewClose(view);
2155 msiobj_release(&view->hdr);
2158 TRACE("Enabling or Disabling Components\n");
2159 for (i = 0; i < package->loaded_components; i++)
2161 if (package->components[i].Condition[0])
2163 if (MSI_EvaluateConditionW(package,
2164 package->components[i].Condition) == MSICONDITION_FALSE)
2166 TRACE("Disabling component %s\n",
2167 debugstr_w(package->components[i].Component));
2168 package->components[i].Enabled = FALSE;
2173 MSI_SetPropertyW(package,szCosting,szOne);
2174 /* set default run level if not set */
2175 level = load_dynamic_property(package,szlevel,NULL);
2176 if (!level)
2177 MSI_SetPropertyW(package,szlevel, szOne);
2178 else
2179 HeapFree(GetProcessHeap(),0,level);
2181 return SetFeatureStates(package);
2186 * This is a helper function for handling embedded cabinet media
2188 static UINT writeout_cabinet_stream(MSIPACKAGE *package, WCHAR* stream_name,
2189 WCHAR* source)
2191 UINT rc;
2192 USHORT* data;
2193 UINT size;
2194 DWORD write;
2195 HANDLE the_file;
2196 WCHAR tmp[MAX_PATH];
2198 rc = read_raw_stream_data(package->db,stream_name,&data,&size);
2199 if (rc != ERROR_SUCCESS)
2200 return rc;
2202 write = MAX_PATH;
2203 if (MSI_GetPropertyW(package, cszTempFolder, tmp, &write))
2204 GetTempPathW(MAX_PATH,tmp);
2206 GetTempFileNameW(tmp,stream_name,0,source);
2208 track_tempfile(package,strrchrW(source,'\\'), source);
2209 the_file = CreateFileW(source, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
2210 FILE_ATTRIBUTE_NORMAL, NULL);
2212 if (the_file == INVALID_HANDLE_VALUE)
2214 rc = ERROR_FUNCTION_FAILED;
2215 goto end;
2218 WriteFile(the_file,data,size,&write,NULL);
2219 CloseHandle(the_file);
2220 TRACE("wrote %li bytes to %s\n",write,debugstr_w(source));
2221 end:
2222 HeapFree(GetProcessHeap(),0,data);
2223 return rc;
2227 /* Support functions for FDI functions */
2228 typedef struct
2230 MSIPACKAGE* package;
2231 LPCSTR cab_path;
2232 LPCSTR file_name;
2233 } CabData;
2235 static void * cabinet_alloc(ULONG cb)
2237 return HeapAlloc(GetProcessHeap(), 0, cb);
2240 static void cabinet_free(void *pv)
2242 HeapFree(GetProcessHeap(), 0, pv);
2245 static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode)
2247 DWORD dwAccess = 0;
2248 DWORD dwShareMode = 0;
2249 DWORD dwCreateDisposition = OPEN_EXISTING;
2250 switch (oflag & _O_ACCMODE)
2252 case _O_RDONLY:
2253 dwAccess = GENERIC_READ;
2254 dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE;
2255 break;
2256 case _O_WRONLY:
2257 dwAccess = GENERIC_WRITE;
2258 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2259 break;
2260 case _O_RDWR:
2261 dwAccess = GENERIC_READ | GENERIC_WRITE;
2262 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2263 break;
2265 if ((oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL))
2266 dwCreateDisposition = CREATE_NEW;
2267 else if (oflag & _O_CREAT)
2268 dwCreateDisposition = CREATE_ALWAYS;
2269 return (INT_PTR)CreateFileA(pszFile, dwAccess, dwShareMode, NULL, dwCreateDisposition, 0, NULL);
2272 static UINT cabinet_read(INT_PTR hf, void *pv, UINT cb)
2274 DWORD dwRead;
2275 if (ReadFile((HANDLE)hf, pv, cb, &dwRead, NULL))
2276 return dwRead;
2277 return 0;
2280 static UINT cabinet_write(INT_PTR hf, void *pv, UINT cb)
2282 DWORD dwWritten;
2283 if (WriteFile((HANDLE)hf, pv, cb, &dwWritten, NULL))
2284 return dwWritten;
2285 return 0;
2288 static int cabinet_close(INT_PTR hf)
2290 return CloseHandle((HANDLE)hf) ? 0 : -1;
2293 static long cabinet_seek(INT_PTR hf, long dist, int seektype)
2295 /* flags are compatible and so are passed straight through */
2296 return SetFilePointer((HANDLE)hf, dist, NULL, seektype);
2299 static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
2301 /* FIXME: try to do more processing in this function */
2302 switch (fdint)
2304 case fdintCOPY_FILE:
2306 CabData *data = (CabData*) pfdin->pv;
2307 ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1);
2308 char *file;
2310 LPWSTR trackname;
2311 LPWSTR trackpath;
2312 LPWSTR tracknametmp;
2313 static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0};
2315 if (data->file_name && strcmp(data->file_name,pfdin->psz1))
2316 return 0;
2318 file = cabinet_alloc((len+1)*sizeof(char));
2319 strcpy(file, data->cab_path);
2320 strcat(file, pfdin->psz1);
2322 TRACE("file: %s\n", debugstr_a(file));
2324 /* track this file so it can be deleted if not installed */
2325 trackpath=strdupAtoW(file);
2326 tracknametmp=strdupAtoW(strrchr(file,'\\')+1);
2327 trackname = HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp) +
2328 strlenW(tmpprefix)+1) * sizeof(WCHAR));
2330 strcpyW(trackname,tmpprefix);
2331 strcatW(trackname,tracknametmp);
2333 track_tempfile(data->package, trackname, trackpath);
2335 HeapFree(GetProcessHeap(),0,trackpath);
2336 HeapFree(GetProcessHeap(),0,trackname);
2337 HeapFree(GetProcessHeap(),0,tracknametmp);
2339 return cabinet_open(file, _O_WRONLY | _O_CREAT, 0);
2341 case fdintCLOSE_FILE_INFO:
2343 FILETIME ft;
2344 FILETIME ftLocal;
2345 if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
2346 return -1;
2347 if (!LocalFileTimeToFileTime(&ft, &ftLocal))
2348 return -1;
2349 if (!SetFileTime((HANDLE)pfdin->hf, &ftLocal, 0, &ftLocal))
2350 return -1;
2352 cabinet_close(pfdin->hf);
2353 return 1;
2355 default:
2356 return 0;
2360 /***********************************************************************
2361 * extract_cabinet_file
2363 * Extract files from a cab file.
2365 static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source,
2366 const WCHAR* path, const WCHAR* file)
2368 HFDI hfdi;
2369 ERF erf;
2370 BOOL ret;
2371 char *cabinet;
2372 char *cab_path;
2373 char *file_name;
2374 CabData data;
2376 TRACE("Extracting %s (%s) to %s\n",debugstr_w(source),
2377 debugstr_w(file), debugstr_w(path));
2379 hfdi = FDICreate(cabinet_alloc,
2380 cabinet_free,
2381 cabinet_open,
2382 cabinet_read,
2383 cabinet_write,
2384 cabinet_close,
2385 cabinet_seek,
2387 &erf);
2388 if (!hfdi)
2390 ERR("FDICreate failed\n");
2391 return FALSE;
2394 if (!(cabinet = strdupWtoA( source )))
2396 FDIDestroy(hfdi);
2397 return FALSE;
2399 if (!(cab_path = strdupWtoA( path )))
2401 FDIDestroy(hfdi);
2402 HeapFree(GetProcessHeap(), 0, cabinet);
2403 return FALSE;
2406 data.package = package;
2407 data.cab_path = cab_path;
2408 if (file)
2409 file_name = strdupWtoA(file);
2410 else
2411 file_name = NULL;
2412 data.file_name = file_name;
2414 ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);
2416 if (!ret)
2417 ERR("FDICopy failed\n");
2419 FDIDestroy(hfdi);
2421 HeapFree(GetProcessHeap(), 0, cabinet);
2422 HeapFree(GetProcessHeap(), 0, cab_path);
2423 HeapFree(GetProcessHeap(), 0, file_name);
2425 return ret;
2428 static UINT ready_media_for_file(MSIPACKAGE *package, UINT sequence,
2429 WCHAR* path, WCHAR* file)
2431 UINT rc;
2432 MSIQUERY * view;
2433 MSIRECORD * row = 0;
2434 static WCHAR source[MAX_PATH];
2435 static const WCHAR ExecSeqQuery[] = {
2436 's','e','l','e','c','t',' ','*',' ',
2437 'f','r','o','m',' ','M','e','d','i','a',' ',
2438 'w','h','e','r','e',' ','L','a','s','t','S','e','q','u','e','n','c','e',' ','>','=',' ','%','i',' ',
2439 'o','r','d','e','r',' ','b','y',' ','L','a','s','t','S','e','q','u','e','n','c','e',0};
2440 WCHAR Query[1024];
2441 WCHAR cab[0x100];
2442 DWORD sz=0x100;
2443 INT seq;
2444 static UINT last_sequence = 0;
2446 if (sequence <= last_sequence)
2448 TRACE("Media already ready (%u, %u)\n",sequence,last_sequence);
2449 /*extract_a_cabinet_file(package, source,path,file); */
2450 return ERROR_SUCCESS;
2453 sprintfW(Query,ExecSeqQuery,sequence);
2455 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2456 if (rc != ERROR_SUCCESS)
2457 return rc;
2459 rc = MSI_ViewExecute(view, 0);
2460 if (rc != ERROR_SUCCESS)
2462 MSI_ViewClose(view);
2463 msiobj_release(&view->hdr);
2464 return rc;
2467 rc = MSI_ViewFetch(view,&row);
2468 if (rc != ERROR_SUCCESS)
2470 MSI_ViewClose(view);
2471 msiobj_release(&view->hdr);
2472 return rc;
2474 seq = MSI_RecordGetInteger(row,2);
2475 last_sequence = seq;
2477 if (!MSI_RecordIsNull(row,4))
2479 sz=0x100;
2480 MSI_RecordGetStringW(row,4,cab,&sz);
2481 TRACE("Source is CAB %s\n",debugstr_w(cab));
2482 /* the stream does not contain the # character */
2483 if (cab[0]=='#')
2485 writeout_cabinet_stream(package,&cab[1],source);
2486 strcpyW(path,source);
2487 *(strrchrW(path,'\\')+1)=0;
2489 else
2491 sz = MAX_PATH;
2492 if (MSI_GetPropertyW(package, cszSourceDir, source, &sz))
2494 ERR("No Source dir defined \n");
2495 rc = ERROR_FUNCTION_FAILED;
2497 else
2499 strcpyW(path,source);
2500 strcatW(source,cab);
2501 /* extract the cab file into a folder in the temp folder */
2502 sz = MAX_PATH;
2503 if (MSI_GetPropertyW(package, cszTempFolder,path, &sz)
2504 != ERROR_SUCCESS)
2505 GetTempPathW(MAX_PATH,path);
2508 rc = !extract_a_cabinet_file(package, source,path,NULL);
2510 msiobj_release(&row->hdr);
2511 MSI_ViewClose(view);
2512 msiobj_release(&view->hdr);
2513 return rc;
2516 inline static UINT create_component_directory ( MSIPACKAGE* package, INT component)
2518 UINT rc = ERROR_SUCCESS;
2519 MSIFOLDER *folder;
2520 LPWSTR install_path;
2522 install_path = resolve_folder(package, package->components[component].Directory,
2523 FALSE, FALSE, &folder);
2524 if (!install_path)
2525 return ERROR_FUNCTION_FAILED;
2527 /* create the path */
2528 if (folder->State == 0)
2530 create_full_pathW(install_path);
2531 folder->State = 2;
2533 HeapFree(GetProcessHeap(), 0, install_path);
2535 return rc;
2538 static UINT ACTION_InstallFiles(MSIPACKAGE *package)
2540 UINT rc = ERROR_SUCCESS;
2541 DWORD index;
2542 MSIRECORD * uirow;
2543 WCHAR uipath[MAX_PATH];
2545 if (!package)
2546 return ERROR_INVALID_HANDLE;
2548 /* increment progress bar each time action data is sent */
2549 ui_progress(package,1,1,0,0);
2551 for (index = 0; index < package->loaded_files; index++)
2553 WCHAR path_to_source[MAX_PATH];
2554 MSIFILE *file;
2556 file = &package->files[index];
2558 if (file->Temporary)
2559 continue;
2561 if (package->components[file->ComponentIndex].ActionRequest !=
2562 INSTALLSTATE_LOCAL)
2564 ui_progress(package,2,file->FileSize,0,0);
2565 TRACE("File %s is not scheduled for install\n",
2566 debugstr_w(file->File));
2568 continue;
2571 if ((file->State == 1) || (file->State == 2))
2573 LPWSTR p;
2574 INT len;
2575 MSICOMPONENT* comp = NULL;
2577 TRACE("Installing %s\n",debugstr_w(file->File));
2578 rc = ready_media_for_file(package,file->Sequence,path_to_source,
2579 file->File);
2581 * WARNING!
2582 * our file table could change here because a new temp file
2583 * may have been created
2585 file = &package->files[index];
2586 if (rc != ERROR_SUCCESS)
2588 ERR("Unable to ready media\n");
2589 rc = ERROR_FUNCTION_FAILED;
2590 break;
2593 create_component_directory( package, file->ComponentIndex);
2595 /* recalculate file paths because things may have changed */
2597 if (file->ComponentIndex >= 0)
2598 comp = &package->components[file->ComponentIndex];
2600 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
2601 HeapFree(GetProcessHeap(),0,file->TargetPath);
2603 file->TargetPath = build_directory_name(2, p, file->FileName);
2605 len = strlenW(path_to_source) + strlenW(file->File) + 2;
2606 file->SourcePath = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
2607 strcpyW(file->SourcePath, path_to_source);
2608 strcatW(file->SourcePath, file->File);
2610 TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
2611 debugstr_w(file->TargetPath));
2613 /* the UI chunk */
2614 uirow=MSI_CreateRecord(9);
2615 MSI_RecordSetStringW(uirow,1,file->File);
2616 strcpyW(uipath,file->TargetPath);
2617 *(strrchrW(uipath,'\\')+1)=0;
2618 MSI_RecordSetStringW(uirow,9,uipath);
2619 MSI_RecordSetInteger(uirow,6,file->FileSize);
2620 ui_actiondata(package,szInstallFiles,uirow);
2621 msiobj_release( &uirow->hdr );
2622 ui_progress(package,2,file->FileSize,0,0);
2624 if (!MoveFileW(file->SourcePath,file->TargetPath))
2626 rc = GetLastError();
2627 ERR("Unable to move file (%s -> %s) (error %d)\n",
2628 debugstr_w(file->SourcePath), debugstr_w(file->TargetPath),
2629 rc);
2630 if (rc == ERROR_ALREADY_EXISTS && file->State == 2)
2632 CopyFileW(file->SourcePath,file->TargetPath,FALSE);
2633 DeleteFileW(file->SourcePath);
2634 rc = 0;
2636 else if (rc == ERROR_FILE_NOT_FOUND)
2638 ERR("Source File Not Found! Continueing\n");
2639 rc = 0;
2641 else
2643 ERR("Ignoring Error and continuing...\n");
2644 rc = 0;
2647 else
2648 file->State = 4;
2652 return rc;
2655 inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key,
2656 LPWSTR* file_source)
2658 DWORD index;
2660 if (!package)
2661 return ERROR_INVALID_HANDLE;
2663 for (index = 0; index < package->loaded_files; index ++)
2665 if (strcmpW(file_key,package->files[index].File)==0)
2667 if (package->files[index].State >= 2)
2669 *file_source = dupstrW(package->files[index].TargetPath);
2670 return ERROR_SUCCESS;
2672 else
2673 return ERROR_FILE_NOT_FOUND;
2677 return ERROR_FUNCTION_FAILED;
2680 static UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
2682 UINT rc;
2683 MSIQUERY * view;
2684 MSIRECORD * row = 0;
2685 static const WCHAR ExecSeqQuery[] = {
2686 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2687 'D','u','p','l','i','c','a','t','e','F','i','l','e',0};
2689 if (!package)
2690 return ERROR_INVALID_HANDLE;
2692 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2693 if (rc != ERROR_SUCCESS)
2694 return ERROR_SUCCESS;
2696 rc = MSI_ViewExecute(view, 0);
2697 if (rc != ERROR_SUCCESS)
2699 MSI_ViewClose(view);
2700 msiobj_release(&view->hdr);
2701 return rc;
2704 while (1)
2706 WCHAR file_key[0x100];
2707 WCHAR *file_source = NULL;
2708 WCHAR dest_name[0x100];
2709 LPWSTR dest_path, dest;
2710 WCHAR component[0x100];
2711 INT component_index;
2713 DWORD sz=0x100;
2715 rc = MSI_ViewFetch(view,&row);
2716 if (rc != ERROR_SUCCESS)
2718 rc = ERROR_SUCCESS;
2719 break;
2722 sz=0x100;
2723 rc = MSI_RecordGetStringW(row,2,component,&sz);
2724 if (rc != ERROR_SUCCESS)
2726 ERR("Unable to get component\n");
2727 msiobj_release(&row->hdr);
2728 break;
2731 component_index = get_loaded_component(package,component);
2732 if (package->components[component_index].ActionRequest !=
2733 INSTALLSTATE_LOCAL)
2735 TRACE("Skipping copy due to disabled component\n");
2736 msiobj_release(&row->hdr);
2737 continue;
2740 sz=0x100;
2741 rc = MSI_RecordGetStringW(row,3,file_key,&sz);
2742 if (rc != ERROR_SUCCESS)
2744 ERR("Unable to get file key\n");
2745 msiobj_release(&row->hdr);
2746 break;
2749 rc = get_file_target(package,file_key,&file_source);
2751 if (rc != ERROR_SUCCESS)
2753 ERR("Original file unknown %s\n",debugstr_w(file_key));
2754 msiobj_release(&row->hdr);
2755 HeapFree(GetProcessHeap(),0,file_source);
2756 continue;
2759 if (MSI_RecordIsNull(row,4))
2761 strcpyW(dest_name,strrchrW(file_source,'\\')+1);
2763 else
2765 sz=0x100;
2766 MSI_RecordGetStringW(row,4,dest_name,&sz);
2767 reduce_to_longfilename(dest_name);
2770 if (MSI_RecordIsNull(row,5))
2772 LPWSTR p;
2773 dest_path = dupstrW(file_source);
2774 p = strrchrW(dest_path,'\\');
2775 if (p)
2776 *p=0;
2778 else
2780 WCHAR destkey[0x100];
2781 sz=0x100;
2782 MSI_RecordGetStringW(row,5,destkey,&sz);
2783 sz = 0x100;
2784 dest_path = resolve_folder(package, destkey, FALSE,FALSE,NULL);
2785 if (!dest_path)
2787 ERR("Unable to get destination folder\n");
2788 msiobj_release(&row->hdr);
2789 HeapFree(GetProcessHeap(),0,file_source);
2790 break;
2794 dest = build_directory_name(2, dest_path, dest_name);
2795 HeapFree(GetProcessHeap(), 0, dest_path);
2797 TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),
2798 debugstr_w(dest));
2800 if (strcmpW(file_source,dest))
2801 rc = !CopyFileW(file_source,dest,TRUE);
2802 else
2803 rc = ERROR_SUCCESS;
2805 if (rc != ERROR_SUCCESS)
2806 ERR("Failed to copy file\n");
2808 FIXME("We should track these duplicate files as well\n");
2810 msiobj_release(&row->hdr);
2811 HeapFree(GetProcessHeap(),0,dest);
2812 HeapFree(GetProcessHeap(),0,file_source);
2814 MSI_ViewClose(view);
2815 msiobj_release(&view->hdr);
2816 return rc;
2820 /* OK this value is "interpretted" and then formatted based on the
2821 first few characters */
2822 static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type,
2823 DWORD *size)
2825 LPSTR data = NULL;
2826 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2828 if (value[1]=='x')
2830 LPWSTR ptr;
2831 CHAR byte[5];
2832 LPWSTR deformated;
2833 int count;
2835 deformat_string(package, &value[2], &deformated);
2837 /* binary value type */
2838 ptr = deformated;
2839 *type=REG_BINARY;
2840 *size = strlenW(ptr)/2;
2841 data = HeapAlloc(GetProcessHeap(),0,*size);
2843 byte[0] = '0';
2844 byte[1] = 'x';
2845 byte[4] = 0;
2846 count = 0;
2847 while (*ptr)
2849 byte[2]= *ptr;
2850 ptr++;
2851 byte[3]= *ptr;
2852 ptr++;
2853 data[count] = (BYTE)strtol(byte,NULL,0);
2854 count ++;
2856 HeapFree(GetProcessHeap(),0,deformated);
2858 TRACE("Data %li bytes(%i)\n",*size,count);
2860 else
2862 LPWSTR deformated;
2863 deformat_string(package, &value[1], &deformated);
2865 *type=REG_DWORD;
2866 *size = sizeof(DWORD);
2867 data = HeapAlloc(GetProcessHeap(),0,*size);
2868 *(LPDWORD)data = atoiW(deformated);
2869 TRACE("DWORD %i\n",*data);
2871 HeapFree(GetProcessHeap(),0,deformated);
2874 else
2876 static const WCHAR szMulti[] = {'[','~',']',0};
2877 WCHAR *ptr;
2878 *type=REG_SZ;
2880 if (value[0]=='#')
2882 if (value[1]=='%')
2884 ptr = &value[2];
2885 *type=REG_EXPAND_SZ;
2887 else
2888 ptr = &value[1];
2890 else
2891 ptr=value;
2893 if (strstrW(value,szMulti))
2894 *type = REG_MULTI_SZ;
2896 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2898 return data;
2901 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2903 UINT rc;
2904 MSIQUERY * view;
2905 MSIRECORD * row = 0;
2906 static const WCHAR ExecSeqQuery[] = {
2907 's','e','l','e','c','t',' ','*',' ',
2908 'f','r','o','m',' ','R','e','g','i','s','t','r','y',0 };
2910 if (!package)
2911 return ERROR_INVALID_HANDLE;
2913 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2914 if (rc != ERROR_SUCCESS)
2915 return ERROR_SUCCESS;
2917 rc = MSI_ViewExecute(view, 0);
2918 if (rc != ERROR_SUCCESS)
2920 MSI_ViewClose(view);
2921 msiobj_release(&view->hdr);
2922 return rc;
2925 /* increment progress bar each time action data is sent */
2926 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2928 while (1)
2930 static const WCHAR szHCR[] =
2931 {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T','\\',0};
2932 static const WCHAR szHCU[] =
2933 {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R','\\',0};
2934 static const WCHAR szHLM[] =
2935 {'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',
2936 '\\',0};
2937 static const WCHAR szHU[] =
2938 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2940 LPSTR value_data = NULL;
2941 HKEY root_key, hkey;
2942 DWORD type,size;
2943 LPWSTR value, key, name, component, deformated;
2944 LPCWSTR szRoot;
2945 INT component_index;
2946 MSIRECORD * uirow;
2947 LPWSTR uikey;
2948 INT root;
2950 rc = MSI_ViewFetch(view,&row);
2951 if (rc != ERROR_SUCCESS)
2953 rc = ERROR_SUCCESS;
2954 break;
2956 ui_progress(package,2,0,0,0);
2958 value = NULL;
2959 key = NULL;
2960 uikey = NULL;
2961 name = NULL;
2963 component = load_dynamic_stringW(row, 6);
2964 component_index = get_loaded_component(package,component);
2966 if (package->components[component_index].ActionRequest !=
2967 INSTALLSTATE_LOCAL)
2969 TRACE("Skipping write due to disabled component\n");
2970 msiobj_release(&row->hdr);
2971 goto next;
2974 /* null values have special meanings during uninstalls and such */
2976 if(MSI_RecordIsNull(row,5))
2978 msiobj_release(&row->hdr);
2979 goto next;
2982 root = MSI_RecordGetInteger(row,2);
2983 key = load_dynamic_stringW(row, 3);
2985 name = load_dynamic_stringW(row, 4);
2987 /* get the root key */
2988 switch (root)
2990 case 0: root_key = HKEY_CLASSES_ROOT;
2991 szRoot = szHCR;
2992 break;
2993 case 1: root_key = HKEY_CURRENT_USER;
2994 szRoot = szHCU;
2995 break;
2996 case 2: root_key = HKEY_LOCAL_MACHINE;
2997 szRoot = szHLM;
2998 break;
2999 case 3: root_key = HKEY_USERS;
3000 szRoot = szHU;
3001 break;
3002 default:
3003 ERR("Unknown root %i\n",root);
3004 root_key=NULL;
3005 szRoot = NULL;
3006 break;
3008 if (!root_key)
3010 msiobj_release(&row->hdr);
3011 goto next;
3014 deformat_string(package, key , &deformated);
3015 size = strlenW(deformated) + strlenW(szRoot) + 1;
3016 uikey = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR));
3017 strcpyW(uikey,szRoot);
3018 strcatW(uikey,deformated);
3020 if (RegCreateKeyW( root_key, deformated, &hkey))
3022 ERR("Could not create key %s\n",debugstr_w(deformated));
3023 msiobj_release(&row->hdr);
3024 HeapFree(GetProcessHeap(),0,deformated);
3025 goto next;
3027 HeapFree(GetProcessHeap(),0,deformated);
3029 value = load_dynamic_stringW(row,5);
3030 value_data = parse_value(package, value, &type, &size);
3032 deformat_string(package, name, &deformated);
3034 if (value_data)
3036 TRACE("Setting value %s\n",debugstr_w(deformated));
3037 RegSetValueExW(hkey, deformated, 0, type, value_data, size);
3039 uirow = MSI_CreateRecord(3);
3040 MSI_RecordSetStringW(uirow,2,deformated);
3041 MSI_RecordSetStringW(uirow,1,uikey);
3043 if (type == REG_SZ)
3044 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
3045 else
3046 MSI_RecordSetStringW(uirow,3,value);
3048 ui_actiondata(package,szWriteRegistryValues,uirow);
3049 msiobj_release( &uirow->hdr );
3051 HeapFree(GetProcessHeap(),0,value_data);
3053 HeapFree(GetProcessHeap(),0,value);
3054 HeapFree(GetProcessHeap(),0,deformated);
3056 msiobj_release(&row->hdr);
3057 RegCloseKey(hkey);
3058 next:
3059 HeapFree(GetProcessHeap(),0,uikey);
3060 HeapFree(GetProcessHeap(),0,key);
3061 HeapFree(GetProcessHeap(),0,name);
3062 HeapFree(GetProcessHeap(),0,component);
3064 MSI_ViewClose(view);
3065 msiobj_release(&view->hdr);
3066 return rc;
3069 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
3071 return ERROR_SUCCESS;
3075 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3077 DWORD progress = 0;
3078 DWORD total = 0;
3079 static const WCHAR q1[]={
3080 'S','E','L','E','C','T',' ','*',' ',
3081 'F','R','O','M',' ','R','e','g','i','s','t','r','y',0};
3082 UINT rc;
3083 MSIQUERY * view;
3084 MSIRECORD * row = 0;
3085 int i;
3087 TRACE(" InstallValidate \n");
3089 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
3090 if (rc != ERROR_SUCCESS)
3091 return ERROR_SUCCESS;
3093 rc = MSI_ViewExecute(view, 0);
3094 if (rc != ERROR_SUCCESS)
3096 MSI_ViewClose(view);
3097 msiobj_release(&view->hdr);
3098 return rc;
3100 while (1)
3102 rc = MSI_ViewFetch(view,&row);
3103 if (rc != ERROR_SUCCESS)
3105 rc = ERROR_SUCCESS;
3106 break;
3108 progress +=1;
3110 msiobj_release(&row->hdr);
3112 MSI_ViewClose(view);
3113 msiobj_release(&view->hdr);
3115 total = total + progress * REG_PROGRESS_VALUE;
3116 total = total + package->loaded_components * COMPONENT_PROGRESS_VALUE;
3117 for (i=0; i < package->loaded_files; i++)
3118 total += package->files[i].FileSize;
3119 ui_progress(package,0,total,0,0);
3121 return ERROR_SUCCESS;
3124 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3126 UINT rc;
3127 MSIQUERY * view = NULL;
3128 MSIRECORD * row = 0;
3129 static const WCHAR ExecSeqQuery[] = {
3130 'S','E','L','E','C','T',' ','*',' ',
3131 'f','r','o','m',' ','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n',0};
3132 static const WCHAR title[]=
3133 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3135 TRACE("Checking launch conditions\n");
3137 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3138 if (rc != ERROR_SUCCESS)
3139 return ERROR_SUCCESS;
3141 rc = MSI_ViewExecute(view, 0);
3142 if (rc != ERROR_SUCCESS)
3144 MSI_ViewClose(view);
3145 msiobj_release(&view->hdr);
3146 return rc;
3149 rc = ERROR_SUCCESS;
3150 while (rc == ERROR_SUCCESS)
3152 LPWSTR cond = NULL;
3153 LPWSTR message = NULL;
3155 rc = MSI_ViewFetch(view,&row);
3156 if (rc != ERROR_SUCCESS)
3158 rc = ERROR_SUCCESS;
3159 break;
3162 cond = load_dynamic_stringW(row,1);
3164 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
3166 LPWSTR deformated;
3167 message = load_dynamic_stringW(row,2);
3168 deformat_string(package,message,&deformated);
3169 MessageBoxW(NULL,deformated,title,MB_OK);
3170 HeapFree(GetProcessHeap(),0,message);
3171 HeapFree(GetProcessHeap(),0,deformated);
3172 rc = ERROR_FUNCTION_FAILED;
3174 HeapFree(GetProcessHeap(),0,cond);
3175 msiobj_release(&row->hdr);
3177 MSI_ViewClose(view);
3178 msiobj_release(&view->hdr);
3179 return rc;
3182 static LPWSTR resolve_keypath( MSIPACKAGE* package, INT
3183 component_index)
3185 MSICOMPONENT* cmp = &package->components[component_index];
3187 if (cmp->KeyPath[0]==0)
3189 LPWSTR p = resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
3190 return p;
3192 if (cmp->Attributes & 0x4)
3194 MSIQUERY * view;
3195 MSIRECORD * row = 0;
3196 UINT rc,root,len;
3197 LPWSTR key,deformated,buffer,name,deformated_name;
3198 static const WCHAR ExecSeqQuery[] = {
3199 's','e','l','e','c','t',' ','*',' ',
3200 'f','r','o','m',' ','R','e','g','i','s','t','r','y',' ',
3201 'w','h','e','r','e',' ','R','e','g','i','s','t','r','y',' ','=',' '
3202 ,'`','%','s','`',0 };
3203 static const WCHAR fmt[]={'%','0','2','i',':','%','s',0};
3204 static const WCHAR fmt2[]={'%','0','2','i',':','%','s','\\','%','s',0};
3206 rc = MSI_OpenQuery(package->db,&view,ExecSeqQuery,cmp->KeyPath);
3208 if (rc!=ERROR_SUCCESS)
3209 return NULL;
3211 rc = MSI_ViewExecute(view, 0);
3212 if (rc != ERROR_SUCCESS)
3214 MSI_ViewClose(view);
3215 msiobj_release(&view->hdr);
3216 return NULL;
3219 rc = MSI_ViewFetch(view,&row);
3220 if (rc != ERROR_SUCCESS)
3222 MSI_ViewClose(view);
3223 msiobj_release(&view->hdr);
3224 return NULL;
3227 root = MSI_RecordGetInteger(row,2);
3228 key = load_dynamic_stringW(row, 3);
3229 name = load_dynamic_stringW(row, 4);
3230 deformat_string(package, key , &deformated);
3231 deformat_string(package, name, &deformated_name);
3233 len = strlenW(deformated) + 5;
3234 if (deformated_name)
3235 len+=strlenW(deformated_name);
3237 buffer = HeapAlloc(GetProcessHeap(),0, len *sizeof(WCHAR));
3239 if (deformated_name)
3240 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3241 else
3242 sprintfW(buffer,fmt,root,deformated);
3244 HeapFree(GetProcessHeap(),0,key);
3245 HeapFree(GetProcessHeap(),0,deformated);
3246 HeapFree(GetProcessHeap(),0,name);
3247 HeapFree(GetProcessHeap(),0,deformated_name);
3248 msiobj_release(&row->hdr);
3249 MSI_ViewClose(view);
3250 msiobj_release(&view->hdr);
3252 return buffer;
3254 else if (cmp->Attributes & 0x20)
3256 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3257 return NULL;
3259 else
3261 int j;
3262 j = get_loaded_file(package,cmp->KeyPath);
3264 if (j>=0)
3266 LPWSTR p = dupstrW(package->files[j].TargetPath);
3267 return p;
3270 return NULL;
3274 * Ok further analysis makes me think that this work is
3275 * actually done in the PublishComponents and PublishFeatures
3276 * step, and not here. It appears like the keypath and all that is
3277 * resolved in this step, however actually written in the Publish steps.
3278 * But we will leave it here for now because it is unclear
3280 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3282 LPWSTR productcode;
3283 WCHAR squished_pc[GUID_SIZE];
3284 WCHAR squished_cc[GUID_SIZE];
3285 UINT rc;
3286 DWORD i;
3287 HKEY hkey=0,hkey2=0;
3288 static const WCHAR szProductCode[]=
3289 {'P','r','o','d','u','c','t','C','o','d','e',0};
3291 if (!package)
3292 return ERROR_INVALID_HANDLE;
3294 /* writes the Component and Features values to the registry */
3295 productcode = load_dynamic_property(package,szProductCode,&rc);
3296 if (!productcode)
3297 return rc;
3299 rc = MSIREG_OpenComponents(&hkey);
3300 if (rc != ERROR_SUCCESS)
3301 goto end;
3303 squash_guid(productcode,squished_pc);
3304 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
3305 for (i = 0; i < package->loaded_components; i++)
3307 ui_progress(package,2,0,0,0);
3308 if (package->components[i].ComponentId[0]!=0)
3310 WCHAR *keypath = NULL;
3311 MSIRECORD * uirow;
3313 squash_guid(package->components[i].ComponentId,squished_cc);
3314 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
3315 if (rc != ERROR_SUCCESS)
3316 continue;
3318 keypath = resolve_keypath(package,i);
3319 if (keypath)
3321 RegSetValueExW(hkey2,squished_pc,0,REG_SZ,(LPVOID)keypath,
3322 (strlenW(keypath)+1)*sizeof(WCHAR));
3323 RegCloseKey(hkey2);
3325 /* UI stuff */
3326 uirow = MSI_CreateRecord(3);
3327 MSI_RecordSetStringW(uirow,1,productcode);
3328 MSI_RecordSetStringW(uirow,2,package->components[i].
3329 ComponentId);
3330 MSI_RecordSetStringW(uirow,3,keypath);
3331 ui_actiondata(package,szProcessComponents,uirow);
3332 msiobj_release( &uirow->hdr );
3333 HeapFree(GetProcessHeap(),0,keypath);
3337 end:
3338 HeapFree(GetProcessHeap(), 0, productcode);
3339 RegCloseKey(hkey);
3340 return rc;
3343 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3346 * OK this is a bit confusing.. I am given a _Component key and I believe
3347 * that the file that is being registered as a type library is the "key file
3348 * of that component" which I interpret to mean "The file in the KeyPath of
3349 * that component".
3351 UINT rc;
3352 MSIQUERY * view;
3353 MSIRECORD * row = 0;
3354 static const WCHAR Query[] = {
3355 'S','E','L','E','C','T',' ','*',' ',
3356 'f','r','o','m',' ','T','y','p','e','L','i','b',0};
3357 ITypeLib *ptLib;
3358 HRESULT res;
3360 if (!package)
3361 return ERROR_INVALID_HANDLE;
3363 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3364 if (rc != ERROR_SUCCESS)
3365 return ERROR_SUCCESS;
3367 rc = MSI_ViewExecute(view, 0);
3368 if (rc != ERROR_SUCCESS)
3370 MSI_ViewClose(view);
3371 msiobj_release(&view->hdr);
3372 return rc;
3375 while (1)
3377 WCHAR component[0x100];
3378 DWORD sz;
3379 INT index;
3381 rc = MSI_ViewFetch(view,&row);
3382 if (rc != ERROR_SUCCESS)
3384 rc = ERROR_SUCCESS;
3385 break;
3388 sz = 0x100;
3389 MSI_RecordGetStringW(row,3,component,&sz);
3391 index = get_loaded_component(package,component);
3392 if (index < 0)
3394 msiobj_release(&row->hdr);
3395 continue;
3398 if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)
3400 TRACE("Skipping typelib reg due to disabled component\n");
3401 msiobj_release(&row->hdr);
3402 continue;
3405 index = get_loaded_file(package,package->components[index].KeyPath);
3407 if (index < 0)
3409 msiobj_release(&row->hdr);
3410 continue;
3413 res = LoadTypeLib(package->files[index].TargetPath,&ptLib);
3414 if (SUCCEEDED(res))
3416 LPWSTR help;
3417 WCHAR helpid[0x100];
3419 sz = 0x100;
3420 MSI_RecordGetStringW(row,6,helpid,&sz);
3422 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
3423 res = RegisterTypeLib(ptLib,package->files[index].TargetPath,help);
3424 HeapFree(GetProcessHeap(),0,help);
3426 if (!SUCCEEDED(res))
3427 ERR("Failed to register type library %s\n",
3428 debugstr_w(package->files[index].TargetPath));
3429 else
3431 /* Yes the row has more fields than I need, but #1 is
3432 correct and the only one I need. Why make a new row? */
3434 ui_actiondata(package,szRegisterTypeLibraries,row);
3436 TRACE("Registered %s\n",
3437 debugstr_w(package->files[index].TargetPath));
3440 if (ptLib)
3441 ITypeLib_Release(ptLib);
3443 else
3444 ERR("Failed to load type library %s\n",
3445 debugstr_w(package->files[index].TargetPath));
3447 msiobj_release(&row->hdr);
3449 MSI_ViewClose(view);
3450 msiobj_release(&view->hdr);
3451 return rc;
3455 static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app )
3457 static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
3458 UINT rc;
3459 MSIQUERY * view;
3460 MSIRECORD * row = 0;
3461 static const WCHAR ExecSeqQuery[] =
3462 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','p','p','I'
3463 ,'d',' ','w','h','e','r','e',' ','A','p','p','I','d','=','`','%','s','`',0};
3464 HKEY hkey2,hkey3;
3465 LPWSTR buffer=0;
3467 if (!package)
3468 return ERROR_INVALID_HANDLE;
3470 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, clsid);
3471 if (rc != ERROR_SUCCESS)
3472 return rc;
3474 rc = MSI_ViewExecute(view, 0);
3475 if (rc != ERROR_SUCCESS)
3477 MSI_ViewClose(view);
3478 msiobj_release(&view->hdr);
3479 return rc;
3482 RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);
3483 RegCreateKeyW(hkey2,clsid,&hkey3);
3484 RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app,
3485 (strlenW(app)+1)*sizeof(WCHAR));
3487 rc = MSI_ViewFetch(view,&row);
3488 if (rc != ERROR_SUCCESS)
3490 MSI_ViewClose(view);
3491 msiobj_release(&view->hdr);
3492 return rc;
3495 if (!MSI_RecordIsNull(row,2))
3497 LPWSTR deformated=0;
3498 UINT size;
3499 static const WCHAR szRemoteServerName[] =
3500 {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0};
3501 buffer = load_dynamic_stringW(row,2);
3502 size = deformat_string(package,buffer,&deformated);
3503 RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,(LPVOID)deformated,
3504 size);
3505 HeapFree(GetProcessHeap(),0,deformated);
3506 HeapFree(GetProcessHeap(),0,buffer);
3509 if (!MSI_RecordIsNull(row,3))
3511 static const WCHAR szLocalService[] =
3512 {'L','o','c','a','l','S','e','r','v','i','c','e',0};
3513 UINT size;
3514 buffer = load_dynamic_stringW(row,3);
3515 size = (strlenW(buffer)+1) * sizeof(WCHAR);
3516 RegSetValueExW(hkey3,szLocalService,0,REG_SZ,(LPVOID)buffer,size);
3517 HeapFree(GetProcessHeap(),0,buffer);
3520 if (!MSI_RecordIsNull(row,4))
3522 static const WCHAR szService[] =
3523 {'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0};
3524 UINT size;
3525 buffer = load_dynamic_stringW(row,4);
3526 size = (strlenW(buffer)+1) * sizeof(WCHAR);
3527 RegSetValueExW(hkey3,szService,0,REG_SZ,(LPVOID)buffer,size);
3528 HeapFree(GetProcessHeap(),0,buffer);
3531 if (!MSI_RecordIsNull(row,5))
3533 static const WCHAR szDLL[] =
3534 {'D','l','l','S','u','r','r','o','g','a','t','e',0};
3535 UINT size;
3536 buffer = load_dynamic_stringW(row,5);
3537 size = (strlenW(buffer)+1) * sizeof(WCHAR);
3538 RegSetValueExW(hkey3,szDLL,0,REG_SZ,(LPVOID)buffer,size);
3539 HeapFree(GetProcessHeap(),0,buffer);
3542 if (!MSI_RecordIsNull(row,6))
3544 static const WCHAR szActivate[] =
3545 {'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0};
3546 static const WCHAR szY[] = {'Y',0};
3548 if (MSI_RecordGetInteger(row,6))
3549 RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4);
3552 if (!MSI_RecordIsNull(row,7))
3554 static const WCHAR szRunAs[] = {'R','u','n','A','s',0};
3555 static const WCHAR szUser[] =
3556 {'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0};
3558 if (MSI_RecordGetInteger(row,7))
3559 RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,34);
3562 msiobj_release(&row->hdr);
3563 MSI_ViewClose(view);
3564 msiobj_release(&view->hdr);
3565 RegCloseKey(hkey3);
3566 RegCloseKey(hkey2);
3567 return rc;
3570 static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
3573 * Again I am assuming the words, "Whose key file represents" when referring
3574 * to a Component as to meaning that Components KeyPath file
3576 * Also there is a very strong connection between ClassInfo and ProgID
3577 * that I am mostly glossing over.
3578 * What would be more propper is to load the ClassInfo and the ProgID info
3579 * into memory data structures and then be able to enable and disable them
3580 * based on component.
3583 UINT rc;
3584 MSIQUERY * view;
3585 MSIRECORD * row = 0;
3586 static const WCHAR ExecSeqQuery[] = {
3587 'S','E','L','E','C','T',' ','*',' ',
3588 'f','r','o','m',' ','C','l','a','s','s',0};
3589 static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
3590 static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 };
3591 static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
3592 HKEY hkey,hkey2,hkey3;
3594 if (!package)
3595 return ERROR_INVALID_HANDLE;
3597 rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);
3598 if (rc != ERROR_SUCCESS)
3599 return ERROR_FUNCTION_FAILED;
3601 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3602 if (rc != ERROR_SUCCESS)
3604 rc = ERROR_SUCCESS;
3605 goto end;
3608 rc = MSI_ViewExecute(view, 0);
3609 if (rc != ERROR_SUCCESS)
3611 MSI_ViewClose(view);
3612 msiobj_release(&view->hdr);
3613 goto end;
3616 while (1)
3618 WCHAR clsid[0x100];
3619 WCHAR buffer[0x100];
3620 WCHAR desc[0x100];
3621 DWORD sz;
3622 INT index;
3624 rc = MSI_ViewFetch(view,&row);
3625 if (rc != ERROR_SUCCESS)
3627 rc = ERROR_SUCCESS;
3628 break;
3631 sz=0x100;
3632 MSI_RecordGetStringW(row,3,buffer,&sz);
3634 index = get_loaded_component(package,buffer);
3636 if (index < 0)
3638 msiobj_release(&row->hdr);
3639 continue;
3642 if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)
3644 TRACE("Skipping class reg due to disabled component\n");
3645 msiobj_release(&row->hdr);
3646 continue;
3649 sz=0x100;
3650 MSI_RecordGetStringW(row,1,clsid,&sz);
3651 RegCreateKeyW(hkey,clsid,&hkey2);
3653 if (!MSI_RecordIsNull(row,5))
3655 sz=0x100;
3656 MSI_RecordGetStringW(row,5,desc,&sz);
3658 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)desc,
3659 (strlenW(desc)+1)*sizeof(WCHAR));
3661 else
3662 desc[0]=0;
3664 sz=0x100;
3665 MSI_RecordGetStringW(row,2,buffer,&sz);
3667 RegCreateKeyW(hkey2,buffer,&hkey3);
3669 index = get_loaded_file(package,package->components[index].KeyPath);
3670 RegSetValueExW(hkey3,NULL,0,REG_SZ,
3671 (LPVOID)package->files[index].TargetPath,
3672 (strlenW(package->files[index].TargetPath)+1)
3673 *sizeof(WCHAR));
3675 RegCloseKey(hkey3);
3677 if (!MSI_RecordIsNull(row,4))
3679 sz=0x100;
3680 MSI_RecordGetStringW(row,4,buffer,&sz);
3682 RegCreateKeyW(hkey2,szProgID,&hkey3);
3684 RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)buffer,
3685 (strlenW(buffer)+1)*sizeof(WCHAR));
3687 RegCloseKey(hkey3);
3690 if (!MSI_RecordIsNull(row,6))
3692 sz=0x100;
3693 MSI_RecordGetStringW(row,6,buffer,&sz);
3695 RegSetValueExW(hkey2,szAppID,0,REG_SZ,(LPVOID)buffer,
3696 (strlenW(buffer)+1)*sizeof(WCHAR));
3698 register_appid(package,buffer,desc);
3701 RegCloseKey(hkey2);
3703 FIXME("Process the rest of the fields >7\n");
3705 ui_actiondata(package,szRegisterClassInfo,row);
3707 msiobj_release(&row->hdr);
3709 MSI_ViewClose(view);
3710 msiobj_release(&view->hdr);
3712 end:
3713 RegCloseKey(hkey);
3714 return rc;
3717 static UINT register_progid_base(MSIPACKAGE* package, MSIRECORD * row,
3718 LPWSTR clsid)
3720 static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
3721 static const WCHAR szDefaultIcon[] = {
3722 'D','e','f','a','u','l','t','I','c','o','n',0};
3723 HKEY hkey,hkey2;
3724 WCHAR buffer[0x100];
3725 DWORD sz;
3728 sz = 0x100;
3729 MSI_RecordGetStringW(row,1,buffer,&sz);
3730 RegCreateKeyW(HKEY_CLASSES_ROOT,buffer,&hkey);
3732 if (!MSI_RecordIsNull(row,4))
3734 sz = 0x100;
3735 MSI_RecordGetStringW(row,4,buffer,&sz);
3736 RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *
3737 sizeof(WCHAR));
3740 if (!MSI_RecordIsNull(row,3))
3742 sz = 0x100;
3744 MSI_RecordGetStringW(row,3,buffer,&sz);
3745 RegCreateKeyW(hkey,szCLSID,&hkey2);
3746 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *
3747 sizeof(WCHAR));
3749 if (clsid)
3750 strcpyW(clsid,buffer);
3752 RegCloseKey(hkey2);
3754 else
3756 FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
3757 return ERROR_FUNCTION_FAILED;
3759 if (!MSI_RecordIsNull(row,5))
3761 INT index = MSI_RecordGetInteger(row,6);
3762 LPWSTR FileName = load_dynamic_stringW(row,5);
3763 LPWSTR FilePath,IconPath;
3764 static const WCHAR fmt[] = {'%','s',',','%','i',0};
3766 RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
3767 build_icon_path(package,FileName,&FilePath);
3769 IconPath = HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+5)*
3770 sizeof(WCHAR));
3772 sprintfW(IconPath,fmt,FilePath,index);
3773 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)IconPath,
3774 (strlenW(IconPath)+1) * sizeof(WCHAR));
3775 HeapFree(GetProcessHeap(),0,FilePath);
3776 HeapFree(GetProcessHeap(),0,FileName);
3777 RegCloseKey(hkey2);
3779 return ERROR_SUCCESS;
3782 static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid);
3784 static UINT register_parent_progid(MSIPACKAGE *package, LPCWSTR parent,
3785 LPWSTR clsid)
3787 UINT rc;
3788 MSIQUERY * view;
3789 MSIRECORD * row = 0;
3790 static const WCHAR Query_t[] =
3791 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','r','o','g'
3792 ,'I','d',' ','w','h','e','r','e',' ','P','r','o','g','I','d',' ','=',' ','`'
3793 ,'%','s','`',0};
3795 if (!package)
3796 return ERROR_INVALID_HANDLE;
3798 rc = MSI_OpenQuery(package->db, &view, Query_t, parent);
3799 if (rc != ERROR_SUCCESS)
3800 return rc;
3802 rc = MSI_ViewExecute(view, 0);
3803 if (rc != ERROR_SUCCESS)
3805 MSI_ViewClose(view);
3806 msiobj_release(&view->hdr);
3807 return rc;
3810 rc = MSI_ViewFetch(view,&row);
3811 if (rc != ERROR_SUCCESS)
3813 MSI_ViewClose(view);
3814 msiobj_release(&view->hdr);
3815 return rc;
3818 register_progid(package,row,clsid);
3820 msiobj_release(&row->hdr);
3821 MSI_ViewClose(view);
3822 msiobj_release(&view->hdr);
3823 return rc;
3826 static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid)
3828 UINT rc = ERROR_SUCCESS;
3830 if (MSI_RecordIsNull(row,2))
3831 rc = register_progid_base(package,row,clsid);
3832 else
3834 WCHAR buffer[0x1000];
3835 DWORD sz, disp;
3836 HKEY hkey,hkey2;
3837 static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
3838 static const WCHAR szDefaultIcon[] = {
3839 'D','e','f','a','u','l','t','I','c','o','n',0};
3841 /* check if already registered */
3842 sz = 0x100;
3843 MSI_RecordGetStringW(row,1,buffer,&sz);
3844 RegCreateKeyExW(HKEY_CLASSES_ROOT, buffer, 0, NULL, 0,
3845 KEY_ALL_ACCESS, NULL, &hkey, &disp );
3846 if (disp == REG_OPENED_EXISTING_KEY)
3848 TRACE("Key already registered\n");
3849 RegCloseKey(hkey);
3850 return rc;
3853 sz = 0x100;
3854 MSI_RecordGetStringW(row,2,buffer,&sz);
3855 rc = register_parent_progid(package,buffer,clsid);
3857 /* clsid is same as parent */
3858 RegCreateKeyW(hkey,szCLSID,&hkey2);
3859 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) *
3860 sizeof(WCHAR));
3862 RegCloseKey(hkey2);
3865 if (!MSI_RecordIsNull(row,4))
3867 sz = 0x100;
3868 MSI_RecordGetStringW(row,4,buffer,&sz);
3869 RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer,
3870 (strlenW(buffer)+1) * sizeof(WCHAR));
3873 if (!MSI_RecordIsNull(row,5))
3875 LPWSTR FileName = load_dynamic_stringW(row,5);
3876 LPWSTR FilePath;
3877 RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
3878 build_icon_path(package,FileName,&FilePath);
3879 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)FilePath,
3880 (strlenW(FilePath)+1) * sizeof(WCHAR));
3881 HeapFree(GetProcessHeap(),0,FilePath);
3882 HeapFree(GetProcessHeap(),0,FileName);
3883 RegCloseKey(hkey2);
3886 RegCloseKey(hkey);
3888 return rc;
3891 static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
3894 * Sigh, here I am just brute force registering all progids
3895 * this needs to be linked to the Classes that have been registered
3896 * but the easiest way to do that is to load all these stuff into
3897 * memory for easy checking.
3899 * Gives me something to continue to work toward.
3901 UINT rc;
3902 MSIQUERY * view;
3903 MSIRECORD * row = 0;
3904 static const WCHAR Query[] = {
3905 'S','E','L','E','C','T',' ','*',' ',
3906 'F','R','O','M',' ','P','r','o','g','I','d',0};
3908 if (!package)
3909 return ERROR_INVALID_HANDLE;
3911 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3912 if (rc != ERROR_SUCCESS)
3913 return ERROR_SUCCESS;
3915 rc = MSI_ViewExecute(view, 0);
3916 if (rc != ERROR_SUCCESS)
3918 MSI_ViewClose(view);
3919 msiobj_release(&view->hdr);
3920 return rc;
3923 while (1)
3925 WCHAR clsid[0x1000];
3927 rc = MSI_ViewFetch(view,&row);
3928 if (rc != ERROR_SUCCESS)
3930 rc = ERROR_SUCCESS;
3931 break;
3934 register_progid(package,row,clsid);
3935 ui_actiondata(package,szRegisterProgIdInfo,row);
3937 msiobj_release(&row->hdr);
3939 MSI_ViewClose(view);
3940 msiobj_release(&view->hdr);
3941 return rc;
3944 static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name,
3945 LPWSTR *FilePath)
3947 LPWSTR ProductCode;
3948 LPWSTR SystemFolder;
3949 LPWSTR dest;
3950 UINT rc;
3952 static const WCHAR szInstaller[] =
3953 {'I','n','s','t','a','l','l','e','r','\\',0};
3954 static const WCHAR szProductCode[] =
3955 {'P','r','o','d','u','c','t','C','o','d','e',0};
3956 static const WCHAR szFolder[] =
3957 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3959 ProductCode = load_dynamic_property(package,szProductCode,&rc);
3960 if (!ProductCode)
3961 return rc;
3963 SystemFolder = load_dynamic_property(package,szFolder,NULL);
3965 dest = build_directory_name(3, SystemFolder, szInstaller, ProductCode);
3967 create_full_pathW(dest);
3969 *FilePath = build_directory_name(2, dest, icon_name);
3971 HeapFree(GetProcessHeap(),0,SystemFolder);
3972 HeapFree(GetProcessHeap(),0,ProductCode);
3973 HeapFree(GetProcessHeap(),0,dest);
3974 return ERROR_SUCCESS;
3977 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3979 UINT rc;
3980 MSIQUERY * view;
3981 MSIRECORD * row = 0;
3982 static const WCHAR Query[] = {
3983 'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ',
3984 'S','h','o','r','t','c','u','t',0};
3985 IShellLinkW *sl;
3986 IPersistFile *pf;
3987 HRESULT res;
3989 if (!package)
3990 return ERROR_INVALID_HANDLE;
3992 res = CoInitialize( NULL );
3993 if (FAILED (res))
3995 ERR("CoInitialize failed\n");
3996 return ERROR_FUNCTION_FAILED;
3999 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
4000 if (rc != ERROR_SUCCESS)
4001 return ERROR_SUCCESS;
4003 rc = MSI_ViewExecute(view, 0);
4004 if (rc != ERROR_SUCCESS)
4006 MSI_ViewClose(view);
4007 msiobj_release(&view->hdr);
4008 return rc;
4011 while (1)
4013 LPWSTR target_file, target_folder;
4014 WCHAR buffer[0x100];
4015 DWORD sz;
4016 DWORD index;
4017 static const WCHAR szlnk[]={'.','l','n','k',0};
4019 rc = MSI_ViewFetch(view,&row);
4020 if (rc != ERROR_SUCCESS)
4022 rc = ERROR_SUCCESS;
4023 break;
4026 sz = 0x100;
4027 MSI_RecordGetStringW(row,4,buffer,&sz);
4029 index = get_loaded_component(package,buffer);
4031 if (index < 0)
4033 msiobj_release(&row->hdr);
4034 continue;
4037 if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)
4039 TRACE("Skipping shortcut creation due to disabled component\n");
4040 msiobj_release(&row->hdr);
4041 continue;
4044 ui_actiondata(package,szCreateShortcuts,row);
4046 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
4047 &IID_IShellLinkW, (LPVOID *) &sl );
4049 if (FAILED(res))
4051 ERR("Is IID_IShellLink\n");
4052 msiobj_release(&row->hdr);
4053 continue;
4056 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
4057 if( FAILED( res ) )
4059 ERR("Is IID_IPersistFile\n");
4060 msiobj_release(&row->hdr);
4061 continue;
4064 sz = 0x100;
4065 MSI_RecordGetStringW(row,2,buffer,&sz);
4066 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
4068 /* may be needed because of a bug somehwere else */
4069 create_full_pathW(target_folder);
4071 sz = 0x100;
4072 MSI_RecordGetStringW(row,3,buffer,&sz);
4073 reduce_to_longfilename(buffer);
4074 if (!strchrW(buffer,'.') || strcmpiW(strchrW(buffer,'.'),szlnk))
4075 strcatW(buffer,szlnk);
4076 target_file = build_directory_name(2, target_folder, buffer);
4077 HeapFree(GetProcessHeap(),0,target_folder);
4079 sz = 0x100;
4080 MSI_RecordGetStringW(row,5,buffer,&sz);
4081 if (strchrW(buffer,'['))
4083 LPWSTR deformated;
4084 deformat_string(package,buffer,&deformated);
4085 IShellLinkW_SetPath(sl,deformated);
4086 HeapFree(GetProcessHeap(),0,deformated);
4088 else
4090 FIXME("UNHANDLED shortcut format, advertised shortcut\n");
4091 IPersistFile_Release( pf );
4092 IShellLinkW_Release( sl );
4093 msiobj_release(&row->hdr);
4094 continue;
4097 if (!MSI_RecordIsNull(row,6))
4099 LPWSTR deformated;
4100 sz = 0x100;
4101 MSI_RecordGetStringW(row,6,buffer,&sz);
4102 deformat_string(package,buffer,&deformated);
4103 IShellLinkW_SetArguments(sl,deformated);
4104 HeapFree(GetProcessHeap(),0,deformated);
4107 if (!MSI_RecordIsNull(row,7))
4109 LPWSTR deformated;
4110 deformated = load_dynamic_stringW(row,7);
4111 IShellLinkW_SetDescription(sl,deformated);
4112 HeapFree(GetProcessHeap(),0,deformated);
4115 if (!MSI_RecordIsNull(row,8))
4116 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
4118 if (!MSI_RecordIsNull(row,9))
4120 WCHAR *Path = NULL;
4121 INT index;
4123 sz = 0x100;
4124 MSI_RecordGetStringW(row,9,buffer,&sz);
4126 build_icon_path(package,buffer,&Path);
4127 index = MSI_RecordGetInteger(row,10);
4129 IShellLinkW_SetIconLocation(sl,Path,index);
4130 HeapFree(GetProcessHeap(),0,Path);
4133 if (!MSI_RecordIsNull(row,11))
4134 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
4136 if (!MSI_RecordIsNull(row,12))
4138 LPWSTR Path;
4139 sz = 0x100;
4140 MSI_RecordGetStringW(row,12,buffer,&sz);
4141 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
4142 IShellLinkW_SetWorkingDirectory(sl,Path);
4143 HeapFree(GetProcessHeap(), 0, Path);
4146 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
4147 IPersistFile_Save(pf,target_file,FALSE);
4149 HeapFree(GetProcessHeap(),0,target_file);
4151 IPersistFile_Release( pf );
4152 IShellLinkW_Release( sl );
4154 msiobj_release(&row->hdr);
4156 MSI_ViewClose(view);
4157 msiobj_release(&view->hdr);
4160 CoUninitialize();
4162 return rc;
4167 * 99% of the work done here is only done for
4168 * advertised installs. However this is where the
4169 * Icon table is processed and written out
4170 * so that is what I am going to do here.
4172 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4174 UINT rc;
4175 MSIQUERY * view;
4176 MSIRECORD * row = 0;
4177 static const WCHAR Query[]={
4178 'S','E','L','E','C','T',' ','*',' ',
4179 'f','r','o','m',' ','I','c','o','n',0};
4180 DWORD sz;
4181 /* for registry stuff */
4182 LPWSTR productcode;
4183 HKEY hkey=0;
4184 HKEY hukey=0;
4185 static const WCHAR szProductCode[]=
4186 {'P','r','o','d','u','c','t','C','o','d','e',0};
4187 static const WCHAR szProductName[] = {
4188 'P','r','o','d','u','c','t','N','a','m','e',0};
4189 static const WCHAR szPackageCode[] = {
4190 'P','a','c','k','a','g','e','C','o','d','e',0};
4191 LPWSTR buffer;
4192 DWORD size;
4193 MSIHANDLE hDb, hSumInfo;
4195 if (!package)
4196 return ERROR_INVALID_HANDLE;
4198 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
4199 if (rc != ERROR_SUCCESS)
4200 goto next;
4202 rc = MSI_ViewExecute(view, 0);
4203 if (rc != ERROR_SUCCESS)
4205 MSI_ViewClose(view);
4206 msiobj_release(&view->hdr);
4207 goto next;
4210 while (1)
4212 HANDLE the_file;
4213 WCHAR *FilePath=NULL;
4214 WCHAR *FileName=NULL;
4215 CHAR buffer[1024];
4217 rc = MSI_ViewFetch(view,&row);
4218 if (rc != ERROR_SUCCESS)
4220 rc = ERROR_SUCCESS;
4221 break;
4224 FileName = load_dynamic_stringW(row,1);
4225 if (!FileName)
4227 ERR("Unable to get FileName\n");
4228 msiobj_release(&row->hdr);
4229 continue;
4232 build_icon_path(package,FileName,&FilePath);
4234 HeapFree(GetProcessHeap(),0,FileName);
4236 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
4238 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
4239 FILE_ATTRIBUTE_NORMAL, NULL);
4241 if (the_file == INVALID_HANDLE_VALUE)
4243 ERR("Unable to create file %s\n",debugstr_w(FilePath));
4244 msiobj_release(&row->hdr);
4245 HeapFree(GetProcessHeap(),0,FilePath);
4246 continue;
4251 DWORD write;
4252 sz = 1024;
4253 rc = MSI_RecordReadStream(row,2,buffer,&sz);
4254 if (rc != ERROR_SUCCESS)
4256 ERR("Failed to get stream\n");
4257 CloseHandle(the_file);
4258 DeleteFileW(FilePath);
4259 break;
4261 WriteFile(the_file,buffer,sz,&write,NULL);
4262 } while (sz == 1024);
4264 HeapFree(GetProcessHeap(),0,FilePath);
4266 CloseHandle(the_file);
4267 msiobj_release(&row->hdr);
4269 MSI_ViewClose(view);
4270 msiobj_release(&view->hdr);
4272 next:
4273 /* ok there is alot more done here but i need to figure out what */
4274 productcode = load_dynamic_property(package,szProductCode,&rc);
4275 if (!productcode)
4276 return rc;
4278 rc = MSIREG_OpenProductsKey(productcode,&hkey,TRUE);
4279 if (rc != ERROR_SUCCESS)
4280 goto end;
4282 rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE);
4283 if (rc != ERROR_SUCCESS)
4284 goto end;
4287 buffer = load_dynamic_property(package,szProductName,NULL);
4288 size = strlenW(buffer)*sizeof(WCHAR);
4289 RegSetValueExW(hukey,szProductName,0,REG_SZ, (LPSTR)buffer,size);
4290 HeapFree(GetProcessHeap(),0,buffer);
4291 FIXME("Need to write more keys to the user registry\n");
4293 hDb= msiobj_findhandle( &package->db->hdr );
4294 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
4295 if (rc == ERROR_SUCCESS)
4297 WCHAR guidbuffer[0x200];
4298 size = 0x200;
4299 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 8, NULL, NULL, NULL,
4300 guidbuffer, &size);
4301 if (rc == ERROR_SUCCESS)
4303 WCHAR squashed[GUID_SIZE];
4304 /* for now we only care about the first guid */
4305 LPWSTR ptr = strchrW(guidbuffer,';');
4306 if (ptr) *ptr = 0;
4307 squash_guid(guidbuffer,squashed);
4308 size = strlenW(guidbuffer)*sizeof(WCHAR);
4309 RegSetValueExW(hukey,szPackageCode,0,REG_SZ, (LPSTR)guidbuffer,
4310 size);
4313 else
4315 ERR("Unable to query Revision_Number... \n");
4316 rc = ERROR_SUCCESS;
4318 MsiCloseHandle(hSumInfo);
4320 else
4322 ERR("Unable to open Summary Information\n");
4323 rc = ERROR_SUCCESS;
4326 end:
4328 HeapFree(GetProcessHeap(),0,productcode);
4329 RegCloseKey(hkey);
4330 RegCloseKey(hukey);
4332 return rc;
4335 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4337 UINT rc;
4338 MSIQUERY * view;
4339 MSIRECORD * row = 0;
4340 static const WCHAR ExecSeqQuery[] = {'S','e','l','e','c','t',' ','*',
4341 ' ','f','r','o','m',' ','I','n','i','F','i','l','e',0};
4342 static const WCHAR szWindowsFolder[] =
4343 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
4344 static const WCHAR szbs[] = {'\\',0};
4346 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4347 if (rc != ERROR_SUCCESS)
4349 TRACE("no IniFile table\n");
4350 return ERROR_SUCCESS;
4353 rc = MSI_ViewExecute(view, 0);
4354 if (rc != ERROR_SUCCESS)
4356 MSI_ViewClose(view);
4357 msiobj_release(&view->hdr);
4358 return rc;
4361 while (1)
4363 LPWSTR component,filename,dirproperty,section,key,value,identifier;
4364 LPWSTR deformated_section, deformated_key, deformated_value;
4365 LPWSTR folder, fullname = NULL;
4366 MSIRECORD * uirow;
4367 INT component_index,action;
4369 rc = MSI_ViewFetch(view,&row);
4370 if (rc != ERROR_SUCCESS)
4372 rc = ERROR_SUCCESS;
4373 break;
4376 component = load_dynamic_stringW(row, 8);
4377 component_index = get_loaded_component(package,component);
4378 HeapFree(GetProcessHeap(),0,component);
4380 if (package->components[component_index].ActionRequest !=
4381 INSTALLSTATE_LOCAL)
4383 TRACE("Skipping ini file due to disabled component\n");
4384 msiobj_release(&row->hdr);
4385 continue;
4388 identifier = load_dynamic_stringW(row,1);
4389 filename = load_dynamic_stringW(row,2);
4390 dirproperty = load_dynamic_stringW(row,3);
4391 section = load_dynamic_stringW(row,4);
4392 key = load_dynamic_stringW(row,5);
4393 value = load_dynamic_stringW(row,6);
4394 action = MSI_RecordGetInteger(row,7);
4396 deformat_string(package,section,&deformated_section);
4397 deformat_string(package,key,&deformated_key);
4398 deformat_string(package,value,&deformated_value);
4400 if (dirproperty)
4402 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
4403 if (!folder)
4404 folder = load_dynamic_property(package,dirproperty,NULL);
4406 else
4407 folder = load_dynamic_property(package, szWindowsFolder, NULL);
4409 if (!folder)
4411 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
4412 goto cleanup;
4416 fullname = HeapAlloc(GetProcessHeap(),0,
4417 (strlenW(folder)+strlenW(filename)+2)*sizeof(WCHAR));
4419 strcpyW(fullname,folder);
4420 if (fullname[strlenW(folder)] != '\\')
4421 strcatW(fullname,szbs);
4422 strcatW(fullname,filename);
4424 if (action == 0)
4426 TRACE("Adding value %s to section %s in %s\n",
4427 debugstr_w(deformated_key), debugstr_w(deformated_section),
4428 debugstr_w(fullname));
4429 WritePrivateProfileStringW(deformated_section, deformated_key,
4430 deformated_value, fullname);
4432 else if (action == 1)
4434 WCHAR returned[10];
4435 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4436 returned, 10, fullname);
4437 if (returned[0] == 0)
4439 TRACE("Adding value %s to section %s in %s\n",
4440 debugstr_w(deformated_key), debugstr_w(deformated_section),
4441 debugstr_w(fullname));
4443 WritePrivateProfileStringW(deformated_section, deformated_key,
4444 deformated_value, fullname);
4447 else if (action == 3)
4449 FIXME("Append to existing section not yet implemented\n");
4452 uirow = MSI_CreateRecord(4);
4453 MSI_RecordSetStringW(uirow,1,identifier);
4454 MSI_RecordSetStringW(uirow,2,deformated_section);
4455 MSI_RecordSetStringW(uirow,3,deformated_key);
4456 MSI_RecordSetStringW(uirow,4,deformated_value);
4457 ui_actiondata(package,szWriteIniValues,uirow);
4458 msiobj_release( &uirow->hdr );
4459 cleanup:
4460 HeapFree(GetProcessHeap(),0,identifier);
4461 HeapFree(GetProcessHeap(),0,fullname);
4462 HeapFree(GetProcessHeap(),0,filename);
4463 HeapFree(GetProcessHeap(),0,key);
4464 HeapFree(GetProcessHeap(),0,value);
4465 HeapFree(GetProcessHeap(),0,section);
4466 HeapFree(GetProcessHeap(),0,dirproperty);
4467 HeapFree(GetProcessHeap(),0,folder);
4468 HeapFree(GetProcessHeap(),0,deformated_key);
4469 HeapFree(GetProcessHeap(),0,deformated_value);
4470 HeapFree(GetProcessHeap(),0,deformated_section);
4471 msiobj_release(&row->hdr);
4473 MSI_ViewClose(view);
4474 msiobj_release(&view->hdr);
4475 return rc;
4478 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4480 UINT rc;
4481 MSIQUERY * view;
4482 MSIRECORD * row = 0;
4483 static const WCHAR ExecSeqQuery[] = {'S','e','l','e','c','t',' ','*',' ',
4484 'f','r','o','m',' ','S','e','l','f','R','e','g',0};
4486 static const WCHAR ExeStr[] = {
4487 'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','s',' ',0};
4488 STARTUPINFOW si;
4489 PROCESS_INFORMATION info;
4490 BOOL brc;
4492 memset(&si,0,sizeof(STARTUPINFOW));
4494 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4495 if (rc != ERROR_SUCCESS)
4497 TRACE("no SelfReg table\n");
4498 return ERROR_SUCCESS;
4501 rc = MSI_ViewExecute(view, 0);
4502 if (rc != ERROR_SUCCESS)
4504 MSI_ViewClose(view);
4505 msiobj_release(&view->hdr);
4506 return rc;
4509 while (1)
4511 LPWSTR filename;
4512 INT index;
4513 DWORD len;
4515 rc = MSI_ViewFetch(view,&row);
4516 if (rc != ERROR_SUCCESS)
4518 rc = ERROR_SUCCESS;
4519 break;
4522 filename = load_dynamic_stringW(row,1);
4523 index = get_loaded_file(package,filename);
4525 if (index < 0)
4527 ERR("Unable to find file id %s\n",debugstr_w(filename));
4528 HeapFree(GetProcessHeap(),0,filename);
4529 msiobj_release(&row->hdr);
4530 continue;
4532 HeapFree(GetProcessHeap(),0,filename);
4534 len = strlenW(ExeStr);
4535 len += strlenW(package->files[index].TargetPath);
4536 len +=2;
4538 filename = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
4539 strcpyW(filename,ExeStr);
4540 strcatW(filename,package->files[index].TargetPath);
4542 TRACE("Registering %s\n",debugstr_w(filename));
4543 brc = CreateProcessW(NULL, filename, NULL, NULL, FALSE, 0, NULL,
4544 c_collen, &si, &info);
4546 if (brc)
4547 WaitForSingleObject(info.hProcess,INFINITE);
4549 HeapFree(GetProcessHeap(),0,filename);
4550 msiobj_release(&row->hdr);
4552 MSI_ViewClose(view);
4553 msiobj_release(&view->hdr);
4554 return rc;
4557 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4559 LPWSTR productcode;
4560 UINT rc;
4561 DWORD i;
4562 HKEY hkey=0;
4563 HKEY hukey=0;
4564 static const WCHAR szProductCode[]=
4565 {'P','r','o','d','u','c','t','C','o','d','e',0};
4567 if (!package)
4568 return ERROR_INVALID_HANDLE;
4570 productcode = load_dynamic_property(package,szProductCode,&rc);
4571 if (!productcode)
4572 return rc;
4574 rc = MSIREG_OpenFeaturesKey(productcode,&hkey,TRUE);
4575 if (rc != ERROR_SUCCESS)
4576 goto end;
4578 rc = MSIREG_OpenUserFeaturesKey(productcode,&hukey,TRUE);
4579 if (rc != ERROR_SUCCESS)
4580 goto end;
4582 /* here the guids are base 85 encoded */
4583 for (i = 0; i < package->loaded_features; i++)
4585 LPWSTR data = NULL;
4586 GUID clsid;
4587 int j;
4588 INT size;
4590 size = package->features[i].ComponentCount*21;
4591 size +=1;
4592 if (package->features[i].Feature_Parent[0])
4593 size += strlenW(package->features[i].Feature_Parent)+2;
4595 data = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
4597 data[0] = 0;
4598 for (j = 0; j < package->features[i].ComponentCount; j++)
4600 WCHAR buf[21];
4601 memset(buf,0,sizeof(buf));
4602 TRACE("From %s\n",debugstr_w(package->components
4603 [package->features[i].Components[j]].ComponentId));
4604 CLSIDFromString(package->components
4605 [package->features[i].Components[j]].ComponentId,
4606 &clsid);
4607 encode_base85_guid(&clsid,buf);
4608 TRACE("to %s\n",debugstr_w(buf));
4609 strcatW(data,buf);
4611 if (package->features[i].Feature_Parent[0])
4613 static const WCHAR sep[] = {'\2',0};
4614 strcatW(data,sep);
4615 strcatW(data,package->features[i].Feature_Parent);
4618 size = (strlenW(data)+1)*sizeof(WCHAR);
4619 RegSetValueExW(hkey,package->features[i].Feature,0,REG_SZ,
4620 (LPSTR)data,size);
4621 HeapFree(GetProcessHeap(),0,data);
4623 size = strlenW(package->features[i].Feature_Parent)*sizeof(WCHAR);
4624 RegSetValueExW(hukey,package->features[i].Feature,0,REG_SZ,
4625 (LPSTR)package->features[i].Feature_Parent,size);
4628 end:
4629 RegCloseKey(hkey);
4630 RegCloseKey(hukey);
4631 HeapFree(GetProcessHeap(), 0, productcode);
4632 return rc;
4635 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4637 static const WCHAR szProductCode[]=
4638 {'P','r','o','d','u','c','t','C','o','d','e',0};
4639 HKEY hkey=0;
4640 LPWSTR buffer;
4641 LPWSTR productcode;
4642 UINT rc,i;
4643 DWORD size;
4644 static WCHAR szNONE[] = {0};
4645 static const WCHAR szWindowsInstaler[] =
4646 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4647 static const WCHAR szPropKeys[][80] =
4649 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0},
4650 {'A','R','P','C','O','N','T','A','C','T'},
4651 {'A','R','P','C','O','M','M','E','N','T','S',0},
4652 {'P','r','o','d','u','c','t','N','a','m','e',0},
4653 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0},
4654 {'A','R','P','H','E','L','P','L','I','N','K',0},
4655 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0},
4656 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0},
4657 {'S','O','U','R','C','E','D','I','R',0},
4658 {'M','a','n','u','f','a','c','t','u','r','e','r',0},
4659 {'A','R','P','R','E','A','D','M','E',0},
4660 {'A','R','P','S','I','Z','E',0},
4661 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0},
4662 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0},
4663 {0},
4666 static const WCHAR szRegKeys[][80] =
4668 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0},
4669 {'C','o','n','t','a','c','t',0},
4670 {'C','o','m','m','e','n','t','s',0},
4671 {'D','i','s','p','l','a','y','N','a','m','e',0},
4672 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0},
4673 {'H','e','l','p','L','i','n','k',0},
4674 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0},
4675 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0},
4676 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0},
4677 {'P','u','b','l','i','s','h','e','r',0},
4678 {'R','e','a','d','m','e',0},
4679 {'S','i','z','e',0},
4680 {'U','R','L','I','n','f','o','A','b','o','u','t',0},
4681 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0},
4682 {0},
4685 static const WCHAR path[] = {
4686 'C',':','\\','W','i','n','d','o','w','s','\\',
4687 'I','n','s','t','a','l','l','e','r','\\'};
4688 static const WCHAR fmt[] = {
4689 'C',':','\\','W','i','n','d','o','w','s','\\',
4690 'I','n','s','t','a','l','l','e','r','\\',
4691 '%','x','.','m','s','i',0};
4692 static const WCHAR szLocalPackage[]=
4693 {'L','o','c','a','l','P','a','c','k','a','g','e',0};
4694 WCHAR packagefile[MAX_PATH];
4695 INT num,start;
4697 if (!package)
4698 return ERROR_INVALID_HANDLE;
4700 productcode = load_dynamic_property(package,szProductCode,&rc);
4701 if (!productcode)
4702 return rc;
4704 rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE);
4705 if (rc != ERROR_SUCCESS)
4706 goto end;
4708 /* dump all the info i can grab */
4709 FIXME("Flesh out more information \n");
4711 i = 0;
4712 while (szPropKeys[i][0]!=0)
4714 buffer = load_dynamic_property(package,szPropKeys[i],&rc);
4715 if (rc != ERROR_SUCCESS)
4716 buffer = szNONE;
4717 size = strlenW(buffer)*sizeof(WCHAR);
4718 RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size);
4719 i++;
4722 rc = 0x1;
4723 size = sizeof(rc);
4724 RegSetValueExW(hkey,szWindowsInstaler,0,REG_DWORD,(LPSTR)&rc,size);
4726 /* copy the package locally */
4727 num = GetTickCount() & 0xffff;
4728 if (!num)
4729 num = 1;
4730 start = num;
4731 sprintfW(packagefile,fmt,num);
4734 HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
4735 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
4736 if (handle != INVALID_HANDLE_VALUE)
4738 CloseHandle(handle);
4739 break;
4741 if (GetLastError() != ERROR_FILE_EXISTS &&
4742 GetLastError() != ERROR_SHARING_VIOLATION)
4743 break;
4744 if (!(++num & 0xffff)) num = 1;
4745 sprintfW(packagefile,fmt,num);
4746 } while (num != start);
4748 create_full_pathW(path);
4749 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
4750 CopyFileW(package->PackagePath,packagefile,FALSE);
4751 size = strlenW(packagefile)*sizeof(WCHAR);
4752 RegSetValueExW(hkey,szLocalPackage,0,REG_SZ,(LPSTR)packagefile,size);
4754 end:
4755 HeapFree(GetProcessHeap(),0,productcode);
4756 RegCloseKey(hkey);
4758 return ERROR_SUCCESS;
4761 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4763 int i;
4764 if (!package)
4765 return ERROR_INVALID_HANDLE;
4767 for (i = 0; i < package->DeferredActionCount; i++)
4769 LPWSTR action;
4770 action = package->DeferredAction[i];
4771 ui_actionstart(package, action);
4772 TRACE("Executing Action (%s)\n",debugstr_w(action));
4773 ACTION_CustomAction(package,action,TRUE);
4774 HeapFree(GetProcessHeap(),0,package->DeferredAction[i]);
4776 HeapFree(GetProcessHeap(),0,package->DeferredAction);
4778 package->DeferredActionCount = 0;
4779 package->DeferredAction = NULL;
4781 return ERROR_SUCCESS;
4784 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4786 int i;
4787 if (!package)
4788 return ERROR_INVALID_HANDLE;
4790 /* first do the same as an InstallExecute */
4791 ACTION_InstallExecute(package);
4793 /* then handle Commit Actions */
4794 for (i = 0; i < package->CommitActionCount; i++)
4796 LPWSTR action;
4797 action = package->CommitAction[i];
4798 ui_actionstart(package, action);
4799 TRACE("Executing Commit Action (%s)\n",debugstr_w(action));
4800 ACTION_CustomAction(package,action,TRUE);
4801 HeapFree(GetProcessHeap(),0,package->CommitAction[i]);
4803 HeapFree(GetProcessHeap(),0,package->CommitAction);
4805 package->CommitActionCount = 0;
4806 package->CommitAction = NULL;
4808 return ERROR_SUCCESS;
4811 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
4813 static const WCHAR RunOnce[] = {
4814 'S','o','f','t','w','a','r','e','\\',
4815 'M','i','c','r','o','s','o','f','t','\\',
4816 'W','i','n','d','o','w','s','\\',
4817 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4818 'R','u','n','O','n','c','e'};
4819 static const WCHAR InstallRunOnce[] = {
4820 'S','o','f','t','w','a','r','e','\\',
4821 'M','i','c','r','o','s','o','f','t','\\',
4822 'W','i','n','d','o','w','s','\\',
4823 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4824 'I','n','s','t','a','l','l','e','r','\\',
4825 'R','u','n','O','n','c','e','E','n','t','r','i','e','s'};
4827 static const WCHAR msiexec_fmt[] = {
4828 'C',':','\\','W','i','n','d','o','w','s','\\','S','y','s','t','e','m',
4829 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4830 '\"','%','s','\"',0};
4831 static const WCHAR install_fmt[] = {
4832 '/','I',' ','\"','%','s','\"',' ',
4833 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4834 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4835 WCHAR buffer[256];
4836 HKEY hkey,hukey;
4837 LPWSTR productcode;
4838 WCHAR squished_pc[100];
4839 INT rc;
4840 DWORD size;
4841 static const WCHAR szProductCode[]=
4842 {'P','r','o','d','u','c','t','C','o','d','e',0};
4843 static const WCHAR szLUS[] = {
4844 'L','a','s','t','U','s','e','d','S','o','u','r','c','e',0};
4845 static const WCHAR szSourceList[] = {
4846 'S','o','u','r','c','e','L','i','s','t',0};
4847 static const WCHAR szPackageName[] = {
4848 'P','a','c','k','a','g','e','N','a','m','e',0};
4850 if (!package)
4851 return ERROR_INVALID_HANDLE;
4853 productcode = load_dynamic_property(package,szProductCode,&rc);
4854 if (!productcode)
4855 return rc;
4857 squash_guid(productcode,squished_pc);
4859 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4860 sprintfW(buffer,msiexec_fmt,squished_pc);
4862 size = strlenW(buffer)*sizeof(WCHAR);
4863 RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size);
4864 RegCloseKey(hkey);
4866 TRACE("Reboot command %s\n",debugstr_w(buffer));
4868 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4869 sprintfW(buffer,install_fmt,productcode,squished_pc);
4870 RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size);
4871 RegCloseKey(hkey);
4873 rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE);
4874 if (rc == ERROR_SUCCESS)
4876 HKEY hukey2;
4877 LPWSTR buf;
4878 RegCreateKeyW(hukey, szSourceList, &hukey2);
4879 buf = load_dynamic_property(package,cszSourceDir,NULL);
4880 size = strlenW(buf)*sizeof(WCHAR);
4881 RegSetValueExW(hukey2,szLUS,0,REG_SZ,(LPSTR)buf,size);
4882 HeapFree(GetProcessHeap(),0,buf);
4884 buf = strrchrW(package->PackagePath,'\\');
4885 if (buf)
4887 buf++;
4888 size = strlenW(buf)*sizeof(WCHAR);
4889 RegSetValueExW(hukey2,szPackageName,0,REG_SZ,(LPSTR)buf,size);
4892 RegCloseKey(hukey2);
4894 HeapFree(GetProcessHeap(),0,productcode);
4896 return ERROR_INSTALL_SUSPEND;
4899 /* Msi functions that seem appropriate here */
4900 UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
4902 LPWSTR szwAction;
4903 UINT rc;
4905 TRACE(" exteral attempt at action %s\n",szAction);
4907 if (!szAction)
4908 return ERROR_FUNCTION_FAILED;
4909 if (hInstall == 0)
4910 return ERROR_FUNCTION_FAILED;
4912 szwAction = strdupAtoW(szAction);
4914 if (!szwAction)
4915 return ERROR_FUNCTION_FAILED;
4918 rc = MsiDoActionW(hInstall, szwAction);
4919 HeapFree(GetProcessHeap(),0,szwAction);
4920 return rc;
4923 UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction )
4925 MSIPACKAGE *package;
4926 UINT ret = ERROR_INVALID_HANDLE;
4928 TRACE(" external attempt at action %s \n",debugstr_w(szAction));
4930 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4931 if( package )
4933 ret = ACTION_PerformAction(package,szAction);
4934 msiobj_release( &package->hdr );
4936 return ret;
4939 UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder,
4940 LPSTR szPathBuf, DWORD* pcchPathBuf)
4942 LPWSTR szwFolder;
4943 LPWSTR szwPathBuf;
4944 UINT rc;
4946 TRACE("getting folder %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
4948 if (!szFolder)
4949 return ERROR_FUNCTION_FAILED;
4950 if (hInstall == 0)
4951 return ERROR_FUNCTION_FAILED;
4953 szwFolder = strdupAtoW(szFolder);
4955 if (!szwFolder)
4956 return ERROR_FUNCTION_FAILED;
4958 szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
4960 rc = MsiGetTargetPathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
4962 WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
4963 *pcchPathBuf, NULL, NULL );
4965 HeapFree(GetProcessHeap(),0,szwFolder);
4966 HeapFree(GetProcessHeap(),0,szwPathBuf);
4968 return rc;
4971 UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
4972 szPathBuf, DWORD* pcchPathBuf)
4974 LPWSTR path;
4975 UINT rc = ERROR_FUNCTION_FAILED;
4976 MSIPACKAGE *package;
4978 TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
4980 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4981 if (!package)
4982 return ERROR_INVALID_HANDLE;
4983 path = resolve_folder(package, szFolder, FALSE, FALSE, NULL);
4984 msiobj_release( &package->hdr );
4986 if (path && (strlenW(path) > *pcchPathBuf))
4988 *pcchPathBuf = strlenW(path)+1;
4989 rc = ERROR_MORE_DATA;
4991 else if (path)
4993 *pcchPathBuf = strlenW(path)+1;
4994 strcpyW(szPathBuf,path);
4995 TRACE("Returning Path %s\n",debugstr_w(path));
4996 rc = ERROR_SUCCESS;
4998 HeapFree(GetProcessHeap(),0,path);
5000 return rc;
5004 UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder,
5005 LPSTR szPathBuf, DWORD* pcchPathBuf)
5007 LPWSTR szwFolder;
5008 LPWSTR szwPathBuf;
5009 UINT rc;
5011 TRACE("getting source %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
5013 if (!szFolder)
5014 return ERROR_FUNCTION_FAILED;
5015 if (hInstall == 0)
5016 return ERROR_FUNCTION_FAILED;
5018 szwFolder = strdupAtoW(szFolder);
5019 if (!szwFolder)
5020 return ERROR_FUNCTION_FAILED;
5022 szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
5024 rc = MsiGetSourcePathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
5026 WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
5027 *pcchPathBuf, NULL, NULL );
5029 HeapFree(GetProcessHeap(),0,szwFolder);
5030 HeapFree(GetProcessHeap(),0,szwPathBuf);
5032 return rc;
5035 UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
5036 szPathBuf, DWORD* pcchPathBuf)
5038 LPWSTR path;
5039 UINT rc = ERROR_FUNCTION_FAILED;
5040 MSIPACKAGE *package;
5042 TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
5044 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
5045 if( !package )
5046 return ERROR_INVALID_HANDLE;
5047 path = resolve_folder(package, szFolder, TRUE, FALSE, NULL);
5048 msiobj_release( &package->hdr );
5050 if (path && strlenW(path) > *pcchPathBuf)
5052 *pcchPathBuf = strlenW(path)+1;
5053 rc = ERROR_MORE_DATA;
5055 else if (path)
5057 *pcchPathBuf = strlenW(path)+1;
5058 strcpyW(szPathBuf,path);
5059 TRACE("Returning Path %s\n",debugstr_w(path));
5060 rc = ERROR_SUCCESS;
5062 HeapFree(GetProcessHeap(),0,path);
5064 return rc;
5068 UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder,
5069 LPCSTR szFolderPath)
5071 LPWSTR szwFolder;
5072 LPWSTR szwFolderPath;
5073 UINT rc;
5075 if (!szFolder)
5076 return ERROR_FUNCTION_FAILED;
5077 if (hInstall == 0)
5078 return ERROR_FUNCTION_FAILED;
5080 szwFolder = strdupAtoW(szFolder);
5081 if (!szwFolder)
5082 return ERROR_FUNCTION_FAILED;
5084 szwFolderPath = strdupAtoW(szFolderPath);
5085 if (!szwFolderPath)
5087 HeapFree(GetProcessHeap(),0,szwFolder);
5088 return ERROR_FUNCTION_FAILED;
5091 rc = MsiSetTargetPathW(hInstall, szwFolder, szwFolderPath);
5093 HeapFree(GetProcessHeap(),0,szwFolder);
5094 HeapFree(GetProcessHeap(),0,szwFolderPath);
5096 return rc;
5099 UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
5100 LPCWSTR szFolderPath)
5102 DWORD i;
5103 LPWSTR path = NULL;
5104 LPWSTR path2 = NULL;
5105 INT len;
5106 MSIFOLDER *folder;
5108 TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));
5110 if (package==NULL)
5111 return ERROR_INVALID_HANDLE;
5113 if (szFolderPath[0]==0)
5114 return ERROR_FUNCTION_FAILED;
5116 if (GetFileAttributesW(szFolderPath) == INVALID_FILE_ATTRIBUTES)
5117 return ERROR_FUNCTION_FAILED;
5119 path = resolve_folder(package,szFolder,FALSE,FALSE,&folder);
5121 if (!path)
5122 return ERROR_INVALID_PARAMETER;
5124 HeapFree(GetProcessHeap(),0,folder->Property);
5126 len = strlenW(szFolderPath);
5128 if (szFolderPath[len-1]!='\\')
5130 len +=2;
5131 folder->Property = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
5132 strcpyW(folder->Property,szFolderPath);
5133 strcatW(folder->Property,cszbs);
5135 else
5136 folder->Property = dupstrW(szFolderPath);
5138 if (strcmpiW(path, szFolderPath) == 0)
5141 * Resolved Target has not really changed, so just
5142 * set this folder and do not recalculate everything.
5144 HeapFree(GetProcessHeap(),0,folder->ResolvedTarget);
5145 folder->ResolvedTarget = NULL;
5146 path2 = resolve_folder(package,szFolder,FALSE,TRUE,NULL);
5147 HeapFree(GetProcessHeap(),0,path2);
5149 else
5151 for (i = 0; i < package->loaded_folders; i++)
5153 HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);
5154 package->folders[i].ResolvedTarget=NULL;
5157 for (i = 0; i < package->loaded_folders; i++)
5159 path2=resolve_folder(package, package->folders[i].Directory, FALSE,
5160 TRUE, NULL);
5161 HeapFree(GetProcessHeap(),0,path2);
5164 HeapFree(GetProcessHeap(),0,path);
5166 return ERROR_SUCCESS;
5169 UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder,
5170 LPCWSTR szFolderPath)
5172 MSIPACKAGE *package;
5173 UINT ret;
5175 TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
5177 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
5178 ret = MSI_SetTargetPathW( package, szFolder, szFolderPath );
5179 msiobj_release( &package->hdr );
5180 return ret;
5183 /***********************************************************************
5184 * MsiGetMode (MSI.@)
5186 * Returns an internal installer state (if it is running in a mode iRunMode)
5188 * PARAMS
5189 * hInstall [I] Handle to the installation
5190 * hRunMode [I] Checking run mode
5191 * MSIRUNMODE_ADMIN Administrative mode
5192 * MSIRUNMODE_ADVERTISE Advertisement mode
5193 * MSIRUNMODE_MAINTENANCE Maintenance mode
5194 * MSIRUNMODE_ROLLBACKENABLED Rollback is enabled
5195 * MSIRUNMODE_LOGENABLED Log file is writing
5196 * MSIRUNMODE_OPERATIONS Operations in progress??
5197 * MSIRUNMODE_REBOOTATEND We need to reboot after installation completed
5198 * MSIRUNMODE_REBOOTNOW We need to reboot to continue the installation
5199 * MSIRUNMODE_CABINET Files from cabinet are installed
5200 * MSIRUNMODE_SOURCESHORTNAMES Long names in source files is supressed
5201 * MSIRUNMODE_TARGETSHORTNAMES Long names in destination files is supressed
5202 * MSIRUNMODE_RESERVED11 Reserved
5203 * MSIRUNMODE_WINDOWS9X Running under Windows95/98
5204 * MSIRUNMODE_ZAWENABLED Demand installation is supported
5205 * MSIRUNMODE_RESERVED14 Reserved
5206 * MSIRUNMODE_RESERVED15 Reserved
5207 * MSIRUNMODE_SCHEDULED called from install script
5208 * MSIRUNMODE_ROLLBACK called from rollback script
5209 * MSIRUNMODE_COMMIT called from commit script
5211 * RETURNS
5212 * In the state: TRUE
5213 * Not in the state: FALSE
5217 BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
5219 FIXME("STUB (iRunMode=%i)\n",iRunMode);
5220 return TRUE;
5224 * According to the docs, when this is called it immediately recalculates
5225 * all the component states as well
5227 UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
5228 INSTALLSTATE iState)
5230 LPWSTR szwFeature = NULL;
5231 UINT rc;
5233 szwFeature = strdupAtoW(szFeature);
5235 if (!szwFeature)
5236 return ERROR_FUNCTION_FAILED;
5238 rc = MsiSetFeatureStateW(hInstall,szwFeature, iState);
5240 HeapFree(GetProcessHeap(),0,szwFeature);
5242 return rc;
5245 UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
5246 INSTALLSTATE iState)
5248 MSIPACKAGE* package;
5249 INT index;
5251 TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
5253 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
5254 if (!package)
5255 return ERROR_INVALID_HANDLE;
5257 index = get_loaded_feature(package,szFeature);
5258 if (index < 0)
5259 return ERROR_UNKNOWN_FEATURE;
5261 package->features[index].ActionRequest= iState;
5263 return ERROR_SUCCESS;
5266 UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPSTR szFeature,
5267 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
5269 LPWSTR szwFeature = NULL;
5270 UINT rc;
5272 szwFeature = strdupAtoW(szFeature);
5274 rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction);
5276 HeapFree( GetProcessHeap(), 0 , szwFeature);
5278 return rc;
5281 UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature,
5282 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
5284 INT index;
5286 index = get_loaded_feature(package,szFeature);
5287 if (index < 0)
5288 return ERROR_UNKNOWN_FEATURE;
5290 if (piInstalled)
5291 *piInstalled = package->features[index].Installed;
5293 if (piAction)
5294 *piAction = package->features[index].Action;
5296 TRACE("returning %i %i\n",*piInstalled,*piAction);
5298 return ERROR_SUCCESS;
5301 UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPWSTR szFeature,
5302 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
5304 MSIPACKAGE* package;
5305 UINT ret;
5307 TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled,
5308 piAction);
5310 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
5311 if (!package)
5312 return ERROR_INVALID_HANDLE;
5313 ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction);
5314 msiobj_release( &package->hdr );
5315 return ret;
5318 UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPSTR szComponent,
5319 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
5321 LPWSTR szwComponent= NULL;
5322 UINT rc;
5324 szwComponent= strdupAtoW(szComponent);
5326 rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction);
5328 HeapFree( GetProcessHeap(), 0 , szwComponent);
5330 return rc;
5333 UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPWSTR szComponent,
5334 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
5336 INT index;
5338 TRACE("%p %s %p %p\n", package, debugstr_w(szComponent), piInstalled,
5339 piAction);
5341 index = get_loaded_component(package,szComponent);
5342 if (index < 0)
5343 return ERROR_UNKNOWN_COMPONENT;
5345 if (piInstalled)
5346 *piInstalled = package->components[index].Installed;
5348 if (piAction)
5349 *piInstalled = package->components[index].Action;
5351 return ERROR_SUCCESS;
5354 UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPWSTR szComponent,
5355 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
5357 MSIPACKAGE* package;
5358 UINT ret;
5360 TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szComponent),
5361 piInstalled, piAction);
5363 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
5364 if (!package)
5365 return ERROR_INVALID_HANDLE;
5366 ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction);
5367 msiobj_release( &package->hdr );
5368 return ret;
5371 #if 0
5372 static UINT ACTION_Template(MSIPACKAGE *package)
5374 UINT rc;
5375 MSIQUERY * view;
5376 MSIRECORD * row = 0;
5377 static const WCHAR ExecSeqQuery[] = {0};
5379 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5380 if (rc != ERROR_SUCCESS)
5381 return rc;
5383 rc = MSI_ViewExecute(view, 0);
5384 if (rc != ERROR_SUCCESS)
5386 MSI_ViewClose(view);
5387 msiobj_release(&view->hdr);
5388 return rc;
5391 while (1)
5393 rc = MSI_ViewFetch(view,&row);
5394 if (rc != ERROR_SUCCESS)
5396 rc = ERROR_SUCCESS;
5397 break;
5400 msiobj_release(&row->hdr);
5402 MSI_ViewClose(view);
5403 msiobj_release(&view->hdr);
5404 return rc;
5406 #endif