diff --git a/dlls/msi/action.c b/dlls/msi/action.c index a115a422bf0..322ef60c494 100644 --- a/dlls/msi/action.c +++ b/dlls/msi/action.c @@ -616,6 +616,66 @@ void ACTION_free_package_structures( MSIPACKAGE* package) if (package->files && package->loaded_files > 0) HeapFree(GetProcessHeap(),0,package->files); + /* clean up extension, progid, class and verb structures */ + for (i = 0; i < package->loaded_classes; i++) + { + HeapFree(GetProcessHeap(),0,package->classes[i].Description); + HeapFree(GetProcessHeap(),0,package->classes[i].FileTypeMask); + HeapFree(GetProcessHeap(),0,package->classes[i].IconPath); + HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler); + HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler32); + HeapFree(GetProcessHeap(),0,package->classes[i].Argument); + HeapFree(GetProcessHeap(),0,package->classes[i].ProgIDText); + } + + if (package->classes && package->loaded_classes > 0) + HeapFree(GetProcessHeap(),0,package->classes); + + for (i = 0; i < package->loaded_extensions; i++) + { + HeapFree(GetProcessHeap(),0,package->extensions[i].ProgIDText); + } + + if (package->extensions && package->loaded_extensions > 0) + HeapFree(GetProcessHeap(),0,package->extensions); + + for (i = 0; i < package->loaded_progids; i++) + { + HeapFree(GetProcessHeap(),0,package->progids[i].ProgID); + HeapFree(GetProcessHeap(),0,package->progids[i].Description); + HeapFree(GetProcessHeap(),0,package->progids[i].IconPath); + } + + if (package->progids && package->loaded_progids > 0) + HeapFree(GetProcessHeap(),0,package->progids); + + for (i = 0; i < package->loaded_verbs; i++) + { + HeapFree(GetProcessHeap(),0,package->verbs[i].Verb); + HeapFree(GetProcessHeap(),0,package->verbs[i].Command); + HeapFree(GetProcessHeap(),0,package->verbs[i].Argument); + } + + if (package->verbs && package->loaded_verbs > 0) + HeapFree(GetProcessHeap(),0,package->verbs); + + for (i = 0; i < package->loaded_mimes; i++) + HeapFree(GetProcessHeap(),0,package->mimes[i].ContentType); + + if (package->mimes && package->loaded_mimes > 0) + HeapFree(GetProcessHeap(),0,package->mimes); + + for (i = 0; i < package->loaded_appids; i++) + { + HeapFree(GetProcessHeap(),0,package->appids[i].RemoteServerName); + HeapFree(GetProcessHeap(),0,package->appids[i].LocalServer); + HeapFree(GetProcessHeap(),0,package->appids[i].ServiceParameters); + HeapFree(GetProcessHeap(),0,package->appids[i].DllSurrogate); + } + + if (package->appids && package->loaded_appids > 0) + HeapFree(GetProcessHeap(),0,package->appids); + for (i = 0; i < package->DeferredActionCount; i++) HeapFree(GetProcessHeap(),0,package->DeferredAction[i]); HeapFree(GetProcessHeap(),0,package->DeferredAction); @@ -1602,7 +1662,7 @@ static int load_component(MSIPACKAGE* package, MSIRECORD * row) memset(&package->components[index],0,sizeof(MSICOMPONENT)); - sz = 96; + sz = IDENTIFIER_SIZE; MSI_RecordGetStringW(row,1,package->components[index].Component,&sz); TRACE("Loading Component %s\n", @@ -1612,7 +1672,7 @@ static int load_component(MSIPACKAGE* package, MSIRECORD * row) if (!MSI_RecordIsNull(row,2)) MSI_RecordGetStringW(row,2,package->components[index].ComponentId,&sz); - sz = 96; + sz = IDENTIFIER_SIZE; MSI_RecordGetStringW(row,3,package->components[index].Directory,&sz); package->components[index].Attributes = MSI_RecordGetInteger(row,4); @@ -1620,7 +1680,7 @@ static int load_component(MSIPACKAGE* package, MSIRECORD * row) sz = 0x100; MSI_RecordGetStringW(row,5,package->components[index].Condition,&sz); - sz = 96; + sz = IDENTIFIER_SIZE; MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz); package->components[index].Installed = INSTALLSTATE_ABSENT; @@ -1666,12 +1726,12 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row) memset(&package->features[index],0,sizeof(MSIFEATURE)); - sz = 96; + sz = IDENTIFIER_SIZE; MSI_RecordGetStringW(row,1,package->features[index].Feature,&sz); TRACE("Loading feature %s\n",debugstr_w(package->features[index].Feature)); - sz = 96; + sz = IDENTIFIER_SIZE; if (!MSI_RecordIsNull(row,2)) MSI_RecordGetStringW(row,2,package->features[index].Feature_Parent,&sz); @@ -1688,7 +1748,7 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row) package->features[index].Level= MSI_RecordGetInteger(row,6); - sz = 96; + sz = IDENTIFIER_SIZE; if (!MSI_RecordIsNull(row,7)) MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz); @@ -4395,124 +4455,937 @@ static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package) return rc; } -static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app ) +static INT load_appid(MSIPACKAGE* package, MSIRECORD *row) { - static const WCHAR szAppID[] = { 'A','p','p','I','D',0 }; - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR ExecSeqQuery[] = + DWORD index = package->loaded_appids; + DWORD sz; + LPWSTR buffer; + + /* fill in the data */ + + package->loaded_appids++; + if (package->loaded_appids == 1) + package->appids = HeapAlloc(GetProcessHeap(),0,sizeof(MSIAPPID)); + else + package->appids = HeapReAlloc(GetProcessHeap(),0, + package->appids, package->loaded_appids * sizeof(MSIAPPID)); + + memset(&package->appids[index],0,sizeof(MSIAPPID)); + + sz = IDENTIFIER_SIZE; + MSI_RecordGetStringW(row, 1, package->appids[index].AppID, &sz); + TRACE("loading appid %s\n",debugstr_w(package->appids[index].AppID)); + + buffer = load_dynamic_stringW(row,2); + deformat_string(package,buffer,&package->appids[index].RemoteServerName); + HeapFree(GetProcessHeap(),0,buffer); + + package->appids[index].LocalServer = load_dynamic_stringW(row,3); + package->appids[index].ServiceParameters = load_dynamic_stringW(row,4); + package->appids[index].DllSurrogate = load_dynamic_stringW(row,5); + + package->appids[index].ActivateAtStorage = !MSI_RecordIsNull(row,6); + package->appids[index].RunAsInteractiveUser = !MSI_RecordIsNull(row,7); + + return index; +} + +static INT load_given_appid(MSIPACKAGE *package, LPCWSTR appid) +{ + INT rc; + MSIQUERY *view; + MSIRECORD *row; + INT i; + static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','A','p','p','I' ,'d','`',' ','W','H','E','R','E',' ', - '`','A','p','p','I','d','`',' ','=','\'','%','s','\'',0}; - HKEY hkey2,hkey3; - LPWSTR buffer=0; + '`','A','p','p','I','d','`',' ','W','H','E','R','E',' ', + '`','A','p','p','I','d','`',' ','=',' ','\'','%','s','\'',0}; - if (!package) - return ERROR_INVALID_HANDLE; + if (!appid) + return -1; - rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, clsid); + /* check for appids already loaded */ + for (i = 0; i < package->loaded_appids; i++) + if (strcmpiW(package->appids[i].AppID,appid)==0) + { + TRACE("found appid %s at index %i\n",debugstr_w(appid),i); + return i; + } + + rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, appid); if (rc != ERROR_SUCCESS) - return rc; + return -1; rc = MSI_ViewExecute(view, 0); if (rc != ERROR_SUCCESS) { MSI_ViewClose(view); msiobj_release(&view->hdr); - return rc; + return -1; } - RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2); - RegCreateKeyW(hkey2,clsid,&hkey3); - RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app, - (strlenW(app)+1)*sizeof(WCHAR)); - rc = MSI_ViewFetch(view,&row); if (rc != ERROR_SUCCESS) { MSI_ViewClose(view); msiobj_release(&view->hdr); - return rc; + return -1; } - if (!MSI_RecordIsNull(row,2)) + rc = load_appid(package, row); + msiobj_release(&row->hdr); + MSI_ViewClose(view); + msiobj_release(&view->hdr); + + return rc; +} + +static INT load_given_progid(MSIPACKAGE *package, LPCWSTR progid); +static INT load_given_class(MSIPACKAGE *package, LPCWSTR classid); + +static INT load_progid(MSIPACKAGE* package, MSIRECORD *row) +{ + DWORD index = package->loaded_progids; + LPWSTR buffer; + + /* fill in the data */ + + package->loaded_progids++; + if (package->loaded_progids == 1) + package->progids = HeapAlloc(GetProcessHeap(),0,sizeof(MSIPROGID)); + else + package->progids = HeapReAlloc(GetProcessHeap(),0, + package->progids , package->loaded_progids * sizeof(MSIPROGID)); + + memset(&package->progids[index],0,sizeof(MSIPROGID)); + + package->progids[index].ProgID = load_dynamic_stringW(row,1); + TRACE("loading progid %s\n",debugstr_w(package->progids[index].ProgID)); + + buffer = load_dynamic_stringW(row,2); + package->progids[index].ParentIndex = load_given_progid(package,buffer); + if (package->progids[index].ParentIndex < 0 && buffer) + FIXME("Unknown parent ProgID %s\n",debugstr_w(buffer)); + HeapFree(GetProcessHeap(),0,buffer); + + buffer = load_dynamic_stringW(row,3); + package->progids[index].ClassIndex = load_given_class(package,buffer); + if (package->progids[index].ClassIndex< 0 && buffer) + FIXME("Unknown class %s\n",debugstr_w(buffer)); + HeapFree(GetProcessHeap(),0,buffer); + + package->progids[index].Description = load_dynamic_stringW(row,4); + + if (!MSI_RecordIsNull(row,6)) + { + INT icon_index = MSI_RecordGetInteger(row,6); + LPWSTR FileName = load_dynamic_stringW(row,5); + LPWSTR FilePath; + static const WCHAR fmt[] = {'%','s',',','%','i',0}; + + build_icon_path(package,FileName,&FilePath); + + package->progids[index].IconPath = + HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+10)* + sizeof(WCHAR)); + + sprintfW(package->progids[index].IconPath,fmt,FilePath,icon_index); + + HeapFree(GetProcessHeap(),0,FilePath); + HeapFree(GetProcessHeap(),0,FileName); + } + else + { + buffer = load_dynamic_stringW(row,5); + if (buffer) + build_icon_path(package,buffer,&(package->progids[index].IconPath)); + HeapFree(GetProcessHeap(),0,buffer); + } + + return index; +} + +static INT load_given_progid(MSIPACKAGE *package, LPCWSTR progid) +{ + INT rc; + MSIQUERY *view; + MSIRECORD *row; + INT i; + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','P','r','o','g','I','d','`',' ','W','H','E','R','E',' ', + '`','P','r','o','g','I','d','`',' ','=',' ','\'','%','s','\'',0}; + + if (!progid) + return -1; + + /* check for progids already loaded */ + for (i = 0; i < package->loaded_progids; i++) + if (strcmpiW(package->progids[i].ProgID,progid)==0) + { + TRACE("found progid %s at index %i\n",debugstr_w(progid), i); + return i; + } + + rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, progid); + if (rc != ERROR_SUCCESS) + return -1; + + rc = MSI_ViewExecute(view, 0); + if (rc != ERROR_SUCCESS) + { + MSI_ViewClose(view); + msiobj_release(&view->hdr); + return -1; + } + + rc = MSI_ViewFetch(view,&row); + if (rc != ERROR_SUCCESS) + { + MSI_ViewClose(view); + msiobj_release(&view->hdr); + return -1; + } + + rc = load_progid(package, row); + msiobj_release(&row->hdr); + MSI_ViewClose(view); + msiobj_release(&view->hdr); + + return rc; +} + +static INT load_class(MSIPACKAGE* package, MSIRECORD *row) +{ + DWORD index = package->loaded_classes; + DWORD sz,i; + LPWSTR buffer; + + /* fill in the data */ + + package->loaded_classes++; + if (package->loaded_classes== 1) + package->classes = HeapAlloc(GetProcessHeap(),0,sizeof(MSICLASS)); + else + package->classes = HeapReAlloc(GetProcessHeap(),0, + package->classes, package->loaded_classes * sizeof(MSICLASS)); + + memset(&package->classes[index],0,sizeof(MSICLASS)); + + sz = IDENTIFIER_SIZE; + MSI_RecordGetStringW(row, 1, package->classes[index].CLSID, &sz); + TRACE("loading class %s\n",debugstr_w(package->classes[index].CLSID)); + sz = IDENTIFIER_SIZE; + MSI_RecordGetStringW(row, 2, package->classes[index].Context, &sz); + buffer = load_dynamic_stringW(row,3); + package->classes[index].ComponentIndex = get_loaded_component(package, + buffer); + HeapFree(GetProcessHeap(),0,buffer); + + package->classes[index].ProgIDText = load_dynamic_stringW(row,4); + package->classes[index].ProgIDIndex = + load_given_progid(package, package->classes[index].ProgIDText); + + package->classes[index].Description = load_dynamic_stringW(row,5); + + buffer = load_dynamic_stringW(row,6); + if (buffer) + package->classes[index].AppIDIndex = + load_given_appid(package, buffer); + else + package->classes[index].AppIDIndex = -1; + HeapFree(GetProcessHeap(),0,buffer); + + package->classes[index].FileTypeMask = load_dynamic_stringW(row,7); + + if (!MSI_RecordIsNull(row,9)) + { + + INT icon_index = MSI_RecordGetInteger(row,9); + LPWSTR FileName = load_dynamic_stringW(row,8); + LPWSTR FilePath; + static const WCHAR fmt[] = {'%','s',',','%','i',0}; + + build_icon_path(package,FileName,&FilePath); + + package->classes[index].IconPath = + HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+5)* + sizeof(WCHAR)); + + sprintfW(package->classes[index].IconPath,fmt,FilePath,icon_index); + + HeapFree(GetProcessHeap(),0,FilePath); + HeapFree(GetProcessHeap(),0,FileName); + } + else + { + buffer = load_dynamic_stringW(row,8); + if (buffer) + build_icon_path(package,buffer,&(package->classes[index].IconPath)); + HeapFree(GetProcessHeap(),0,buffer); + } + + if (!MSI_RecordIsNull(row,10)) + { + i = MSI_RecordGetInteger(row,10); + if (i != MSI_NULL_INTEGER && i > 0 && i < 4) + { + static const WCHAR ole2[] = {'o','l','e','2','.','d','l','l',0}; + static const WCHAR ole32[] = {'o','l','e','3','2','.','d','l','l',0}; + + switch(i) + { + case 1: + package->classes[index].DefInprocHandler = strdupW(ole2); + break; + case 2: + package->classes[index].DefInprocHandler32 = strdupW(ole32); + break; + case 3: + package->classes[index].DefInprocHandler = strdupW(ole2); + package->classes[index].DefInprocHandler32 = strdupW(ole32); + break; + } + } + else + { + package->classes[index].DefInprocHandler32 = load_dynamic_stringW( + row, 10); + reduce_to_longfilename(package->classes[index].DefInprocHandler32); + } + } + buffer = load_dynamic_stringW(row,11); + deformat_string(package,buffer,&package->classes[index].Argument); + HeapFree(GetProcessHeap(),0,buffer); + + buffer = load_dynamic_stringW(row,12); + package->classes[index].FeatureIndex = get_loaded_feature(package,buffer); + HeapFree(GetProcessHeap(),0,buffer); + + package->classes[index].Attributes = MSI_RecordGetInteger(row,13); + + return index; +} + +/* + * the Class table has 3 primary keys. Generally it is only + * referenced through the first CLSID key. However when loading + * all of the classes we need to make sure we do not ignore rows + * with other Context and ComponentIndexs + */ +static INT load_given_class(MSIPACKAGE *package, LPCWSTR classid) +{ + INT rc; + MSIQUERY *view; + MSIRECORD *row; + INT i; + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','C','l','a','s','s','`',' ','W','H','E','R','E',' ', + '`','C','L','S','I','D','`',' ','=',' ','\'','%','s','\'',0}; + + + if (!classid) + return -1; + + /* check for classes already loaded */ + for (i = 0; i < package->loaded_classes; i++) + if (strcmpiW(package->classes[i].CLSID,classid)==0) + { + TRACE("found class %s at index %i\n",debugstr_w(classid), i); + return i; + } + + rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, classid); + if (rc != ERROR_SUCCESS) + return -1; + + rc = MSI_ViewExecute(view, 0); + if (rc != ERROR_SUCCESS) + { + MSI_ViewClose(view); + msiobj_release(&view->hdr); + return -1; + } + + rc = MSI_ViewFetch(view,&row); + if (rc != ERROR_SUCCESS) + { + MSI_ViewClose(view); + msiobj_release(&view->hdr); + return -1; + } + + rc = load_class(package, row); + msiobj_release(&row->hdr); + MSI_ViewClose(view); + msiobj_release(&view->hdr); + + return rc; +} + +static INT load_given_extension(MSIPACKAGE *package, LPCWSTR extension); + +static INT load_mime(MSIPACKAGE* package, MSIRECORD *row) +{ + DWORD index = package->loaded_mimes; + DWORD sz; + LPWSTR buffer; + + /* fill in the data */ + + package->loaded_mimes++; + if (package->loaded_mimes== 1) + package->mimes= HeapAlloc(GetProcessHeap(),0,sizeof(MSIMIME)); + else + package->mimes= HeapReAlloc(GetProcessHeap(),0, + package->mimes, package->loaded_mimes* + sizeof(MSIMIME)); + + memset(&package->mimes[index],0,sizeof(MSIMIME)); + + package->mimes[index].ContentType = load_dynamic_stringW(row,1); + TRACE("loading mime %s\n",debugstr_w(package->mimes[index].ContentType)); + + buffer = load_dynamic_stringW(row,2); + package->mimes[index].ExtensionIndex = load_given_extension(package, + buffer); + HeapFree(GetProcessHeap(),0,buffer); + + sz = IDENTIFIER_SIZE; + MSI_RecordGetStringW(row,3,package->mimes[index].CLSID,&sz); + package->mimes[index].ClassIndex= load_given_class(package, + package->mimes[index].CLSID); + + return index; +} + +static INT load_given_mime(MSIPACKAGE *package, LPCWSTR mime) +{ + INT rc; + MSIQUERY *view; + MSIRECORD *row; + INT i; + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','M','I','M','E','`',' ','W','H','E','R','E',' ', + '`','C','o','n','t','e','n','t','T','y','p','e','`',' ','=',' ', + '\'','%','s','\'',0}; + + if (!mime) + return -1; + + /* check for mime already loaded */ + for (i = 0; i < package->loaded_mimes; i++) + if (strcmpiW(package->mimes[i].ContentType,mime)==0) + { + TRACE("found mime %s at index %i\n",debugstr_w(mime), i); + return i; + } + + rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, mime); + if (rc != ERROR_SUCCESS) + return -1; + + rc = MSI_ViewExecute(view, 0); + if (rc != ERROR_SUCCESS) + { + MSI_ViewClose(view); + msiobj_release(&view->hdr); + return -1; + } + + rc = MSI_ViewFetch(view,&row); + if (rc != ERROR_SUCCESS) + { + MSI_ViewClose(view); + msiobj_release(&view->hdr); + return -1; + } + + rc = load_mime(package, row); + msiobj_release(&row->hdr); + MSI_ViewClose(view); + msiobj_release(&view->hdr); + + return rc; +} + +static INT load_extension(MSIPACKAGE* package, MSIRECORD *row) +{ + DWORD index = package->loaded_extensions; + DWORD sz; + LPWSTR buffer; + + /* fill in the data */ + + package->loaded_extensions++; + if (package->loaded_extensions == 1) + package->extensions = HeapAlloc(GetProcessHeap(),0,sizeof(MSIEXTENSION)); + else + package->extensions = HeapReAlloc(GetProcessHeap(),0, + package->extensions, package->loaded_extensions* + sizeof(MSIEXTENSION)); + + memset(&package->extensions[index],0,sizeof(MSIEXTENSION)); + + sz = 256; + MSI_RecordGetStringW(row,1,package->extensions[index].Extension,&sz); + TRACE("loading extension %s\n", + debugstr_w(package->extensions[index].Extension)); + + buffer = load_dynamic_stringW(row,2); + package->extensions[index].ComponentIndex = + get_loaded_component(package,buffer); + HeapFree(GetProcessHeap(),0,buffer); + + package->extensions[index].ProgIDText = load_dynamic_stringW(row,3); + package->extensions[index].ProgIDIndex = load_given_progid(package, + package->extensions[index].ProgIDText); + + buffer = load_dynamic_stringW(row,4); + package->extensions[index].MIMEIndex = load_given_mime(package,buffer); + HeapFree(GetProcessHeap(),0,buffer); + + buffer = load_dynamic_stringW(row,5); + package->extensions[index].FeatureIndex = + get_loaded_feature(package,buffer); + HeapFree(GetProcessHeap(),0,buffer); + + return index; +} + +/* + * While the extension table has 2 primary keys, this function is only looking + * at the Extension key which is what is referenced as a forign key + */ +static INT load_given_extension(MSIPACKAGE *package, LPCWSTR extension) +{ + INT rc; + MSIQUERY *view; + MSIRECORD *row; + INT i; + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','E','x','t','e','n','s','i','o','n','`',' ', + 'W','H','E','R','E',' ', + '`','E','x','t','e','n','s','i','o','n','`',' ','=',' ', + '\'','%','s','\'',0}; + + if (!extension) + return -1; + + /* check for extensions already loaded */ + for (i = 0; i < package->loaded_extensions; i++) + if (strcmpiW(package->extensions[i].Extension,extension)==0) + { + TRACE("extension %s already loaded at %i\n",debugstr_w(extension), + i); + return i; + } + + rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, extension); + if (rc != ERROR_SUCCESS) + return -1; + + rc = MSI_ViewExecute(view, 0); + if (rc != ERROR_SUCCESS) + { + MSI_ViewClose(view); + msiobj_release(&view->hdr); + return -1; + } + + rc = MSI_ViewFetch(view,&row); + if (rc != ERROR_SUCCESS) + { + MSI_ViewClose(view); + msiobj_release(&view->hdr); + return -1; + } + + rc = load_extension(package, row); + msiobj_release(&row->hdr); + MSI_ViewClose(view); + msiobj_release(&view->hdr); + + return rc; +} + +static UINT iterate_load_verb(MSIRECORD *row, LPVOID param) +{ + MSIPACKAGE* package = (MSIPACKAGE*)param; + DWORD index = package->loaded_verbs; + LPWSTR buffer; + + /* fill in the data */ + + package->loaded_verbs++; + if (package->loaded_verbs == 1) + package->verbs = HeapAlloc(GetProcessHeap(),0,sizeof(MSIVERB)); + else + package->verbs = HeapReAlloc(GetProcessHeap(),0, + package->verbs , package->loaded_verbs * sizeof(MSIVERB)); + + memset(&package->verbs[index],0,sizeof(MSIVERB)); + + buffer = load_dynamic_stringW(row,1); + package->verbs[index].ExtensionIndex = load_given_extension(package,buffer); + if (package->verbs[index].ExtensionIndex < 0 && buffer) + ERR("Verb unable to find loaded extension %s\n", debugstr_w(buffer)); + HeapFree(GetProcessHeap(),0,buffer); + + package->verbs[index].Verb = load_dynamic_stringW(row,2); + TRACE("loading verb %s\n",debugstr_w(package->verbs[index].Verb)); + package->verbs[index].Sequence = MSI_RecordGetInteger(row,3); + + buffer = load_dynamic_stringW(row,4); + deformat_string(package,buffer,&package->verbs[index].Command); + HeapFree(GetProcessHeap(),0,buffer); + + buffer = load_dynamic_stringW(row,5); + deformat_string(package,buffer,&package->verbs[index].Argument); + HeapFree(GetProcessHeap(),0,buffer); + + /* assosiate the verb with the correct extension */ + if (package->verbs[index].ExtensionIndex >= 0) + { + MSIEXTENSION* extension = &package->extensions[package->verbs[index]. + ExtensionIndex]; + int count = extension->VerbCount; + + if (count >= 99) + FIXME("Exceeding max verb count! Increase that limit!!!\n"); + else + { + extension->VerbCount++; + extension->Verbs[count] = index; + } + } + + return ERROR_SUCCESS; +} + +static UINT iterate_all_classes(MSIRECORD *rec, LPVOID param) +{ + LPWSTR clsid; + LPWSTR context; + LPWSTR buffer; + INT component_index; + MSIPACKAGE* package =(MSIPACKAGE*)param; + INT i; + BOOL match = FALSE; + + clsid = load_dynamic_stringW(rec,1); + context = load_dynamic_stringW(rec,2); + buffer = load_dynamic_stringW(rec,3); + component_index = get_loaded_component(package,buffer); + + for (i = 0; i < package->loaded_classes; i++) + { + if (strcmpiW(clsid,package->classes[i].CLSID)) + continue; + if (strcmpW(context,package->classes[i].Context)) + continue; + if (component_index == package->classes[i].ComponentIndex) + { + match = TRUE; + break; + } + } + + HeapFree(GetProcessHeap(),0,buffer); + HeapFree(GetProcessHeap(),0,clsid); + HeapFree(GetProcessHeap(),0,context); + + if (!match) + load_class(package, rec); + + return ERROR_SUCCESS; +} + +static VOID load_all_classes(MSIPACKAGE *package) +{ + UINT rc = ERROR_SUCCESS; + MSIQUERY *view; + + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', + '`','C','l','a','s','s','`',0}; + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + return; + + rc = MSI_IterateRecords(view, NULL, iterate_all_classes, package); + msiobj_release(&view->hdr); +} + +static UINT iterate_all_extensions(MSIRECORD *rec, LPVOID param) +{ + LPWSTR buffer; + LPWSTR extension; + INT component_index; + MSIPACKAGE* package =(MSIPACKAGE*)param; + BOOL match = FALSE; + INT i; + + extension = load_dynamic_stringW(rec,1); + buffer = load_dynamic_stringW(rec,2); + component_index = get_loaded_component(package,buffer); + + for (i = 0; i < package->loaded_extensions; i++) + { + if (strcmpiW(extension,package->extensions[i].Extension)) + continue; + if (component_index == package->extensions[i].ComponentIndex) + { + match = TRUE; + break; + } + } + + HeapFree(GetProcessHeap(),0,buffer); + HeapFree(GetProcessHeap(),0,extension); + + if (!match) + load_extension(package, rec); + + return ERROR_SUCCESS; +} + +static VOID load_all_extensions(MSIPACKAGE *package) +{ + UINT rc = ERROR_SUCCESS; + MSIQUERY *view; + + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','E','x','t','e','n','s','i','o','n','`',0}; + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + return; + + rc = MSI_IterateRecords(view, NULL, iterate_all_extensions, package); + msiobj_release(&view->hdr); +} + +static UINT iterate_all_progids(MSIRECORD *rec, LPVOID param) +{ + LPWSTR buffer; + MSIPACKAGE* package =(MSIPACKAGE*)param; + + buffer = load_dynamic_stringW(rec,1); + load_given_progid(package,buffer); + HeapFree(GetProcessHeap(),0,buffer); + return ERROR_SUCCESS; +} + +static VOID load_all_progids(MSIPACKAGE *package) +{ + UINT rc = ERROR_SUCCESS; + MSIQUERY *view; + + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','`','P','r','o','g','I','d','`',' ', + 'F','R','O','M',' ', '`','P','r','o','g','I','d','`',0}; + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + return; + + rc = MSI_IterateRecords(view, NULL, iterate_all_progids, package); + msiobj_release(&view->hdr); +} + +static VOID load_all_verbs(MSIPACKAGE *package) +{ + UINT rc = ERROR_SUCCESS; + MSIQUERY *view; + + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','V','e','r','b','`',0}; + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + return; + + rc = MSI_IterateRecords(view, NULL, iterate_load_verb, package); + msiobj_release(&view->hdr); +} + +static UINT iterate_all_mimes(MSIRECORD *rec, LPVOID param) +{ + LPWSTR buffer; + MSIPACKAGE* package =(MSIPACKAGE*)param; + + buffer = load_dynamic_stringW(rec,1); + load_given_mime(package,buffer); + HeapFree(GetProcessHeap(),0,buffer); + return ERROR_SUCCESS; +} + +static VOID load_all_mimes(MSIPACKAGE *package) +{ + UINT rc = ERROR_SUCCESS; + MSIQUERY *view; + + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ', + '`','C','o','n','t','e','n','t','T','y','p','e','`', + ' ','F','R','O','M',' ', + '`','M','I','M','E','`',0}; + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + return; + + rc = MSI_IterateRecords(view, NULL, iterate_all_mimes, package); + msiobj_release(&view->hdr); +} + +static void load_classes_and_such(MSIPACKAGE *package) +{ + TRACE("Loading all the class info and related tables\n"); + + /* check if already loaded */ + if (package->classes || package->extensions || package->progids || + package->verbs || package->mimes) + return; + + load_all_classes(package); + load_all_extensions(package); + load_all_progids(package); + /* these loads must come after the other loads */ + load_all_verbs(package); + load_all_mimes(package); +} + +static void mark_progid_for_install(MSIPACKAGE* package, INT index) +{ + MSIPROGID* progid; + int i; + + if (index < 0 || index >= package->loaded_progids) + return; + + progid = &package->progids[index]; + + if (progid->InstallMe == TRUE) + return; + + progid->InstallMe = TRUE; + + /* all children if this is a parent also install */ + for (i = 0; i < package->loaded_progids; i++) + if (package->progids[i].ParentIndex == index) + mark_progid_for_install(package,i); +} + +static void mark_mime_for_install(MSIPACKAGE* package, INT index) +{ + MSIMIME* mime; + + if (index < 0 || index >= package->loaded_mimes) + return; + + mime = &package->mimes[index]; + + if (mime->InstallMe == TRUE) + return; + + mime->InstallMe = TRUE; +} + +static UINT register_appid(MSIPACKAGE *package, int appidIndex, LPCWSTR app ) +{ + static const WCHAR szAppID[] = { 'A','p','p','I','D',0 }; + HKEY hkey2,hkey3; + + if (!package) + return ERROR_INVALID_HANDLE; + + RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2); + RegCreateKeyW(hkey2,package->appids[appidIndex].AppID,&hkey3); + RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app, + (strlenW(app)+1)*sizeof(WCHAR)); + + if (package->appids[appidIndex].RemoteServerName) { - LPWSTR deformated=0; UINT size; static const WCHAR szRemoteServerName[] = {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e', 0}; - buffer = load_dynamic_stringW(row,2); - size = deformat_string(package,buffer,&deformated); - RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,(LPVOID)deformated, - size); - HeapFree(GetProcessHeap(),0,deformated); - HeapFree(GetProcessHeap(),0,buffer); + + size = (strlenW(package->appids[appidIndex].RemoteServerName)+1) * + sizeof(WCHAR); + + RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ, + (LPVOID)package->appids[appidIndex].RemoteServerName, + size); } - if (!MSI_RecordIsNull(row,3)) + if (package->appids[appidIndex].LocalServer) { static const WCHAR szLocalService[] = {'L','o','c','a','l','S','e','r','v','i','c','e',0}; UINT size; - buffer = load_dynamic_stringW(row,3); - size = (strlenW(buffer)+1) * sizeof(WCHAR); - RegSetValueExW(hkey3,szLocalService,0,REG_SZ,(LPVOID)buffer,size); - HeapFree(GetProcessHeap(),0,buffer); + size = (strlenW(package->appids[appidIndex].LocalServer)+1) * + sizeof(WCHAR); + + RegSetValueExW(hkey3,szLocalService,0,REG_SZ, + (LPVOID)package->appids[appidIndex].LocalServer,size); } - if (!MSI_RecordIsNull(row,4)) + if (package->appids[appidIndex].ServiceParameters) { static const WCHAR szService[] = {'S','e','r','v','i','c','e', 'P','a','r','a','m','e','t','e','r','s',0}; UINT size; - buffer = load_dynamic_stringW(row,4); - size = (strlenW(buffer)+1) * sizeof(WCHAR); - RegSetValueExW(hkey3,szService,0,REG_SZ,(LPVOID)buffer,size); - HeapFree(GetProcessHeap(),0,buffer); + size = (strlenW(package->appids[appidIndex].ServiceParameters)+1) * + sizeof(WCHAR); + RegSetValueExW(hkey3,szService,0,REG_SZ, + (LPVOID)package->appids[appidIndex].ServiceParameters, + size); } - if (!MSI_RecordIsNull(row,5)) + if (package->appids[appidIndex].DllSurrogate) { static const WCHAR szDLL[] = {'D','l','l','S','u','r','r','o','g','a','t','e',0}; UINT size; - buffer = load_dynamic_stringW(row,5); - size = (strlenW(buffer)+1) * sizeof(WCHAR); - RegSetValueExW(hkey3,szDLL,0,REG_SZ,(LPVOID)buffer,size); - HeapFree(GetProcessHeap(),0,buffer); + size = (strlenW(package->appids[appidIndex].DllSurrogate)+1) * + sizeof(WCHAR); + RegSetValueExW(hkey3,szDLL,0,REG_SZ, + (LPVOID)package->appids[appidIndex].DllSurrogate,size); } - if (!MSI_RecordIsNull(row,6)) + if (package->appids[appidIndex].ActivateAtStorage) { static const WCHAR szActivate[] = {'A','c','t','i','v','a','t','e','A','s', 'S','t','o','r','a','g','e',0}; static const WCHAR szY[] = {'Y',0}; - if (MSI_RecordGetInteger(row,6)) - RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4); + RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4); } - if (!MSI_RecordIsNull(row,7)) + if (package->appids[appidIndex].RunAsInteractiveUser) { static const WCHAR szRunAs[] = {'R','u','n','A','s',0}; static const WCHAR szUser[] = {'I','n','t','e','r','a','c','t','i','v','e',' ', 'U','s','e','r',0}; - if (MSI_RecordGetInteger(row,7)) - RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,34); + RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,sizeof(szUser)); } - msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); RegCloseKey(hkey3); RegCloseKey(hkey2); - return rc; + return ERROR_SUCCESS; } static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package) @@ -4520,389 +5393,271 @@ static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package) /* * Again I am assuming the words, "Whose key file represents" when referring * to a Component as to meaning that Components KeyPath file - * - * Also there is a very strong connection between ClassInfo and ProgID - * that I am mostly glossing over. - * What would be more propper is to load the ClassInfo and the ProgID info - * into memory data structures and then be able to enable and disable them - * based on component. */ UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR ExecSeqQuery[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','C','l','a','s','s','`',0}; + MSIRECORD *uirow; static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 }; static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 }; + static const WCHAR szVIProgID[] = { 'V','e','r','s','i','o','n','I','n','d','e','p','e','n','d','e','n','t','P','r','o','g','I','D',0 }; static const WCHAR szAppID[] = { 'A','p','p','I','D',0 }; static const WCHAR szSpace[] = {' ',0}; HKEY hkey,hkey2,hkey3; - LPWSTR argument,deformated; + int i; if (!package) return ERROR_INVALID_HANDLE; + load_classes_and_such(package); rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey); if (rc != ERROR_SUCCESS) return ERROR_FUNCTION_FAILED; - rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); - if (rc != ERROR_SUCCESS) + for (i = 0; i < package->loaded_classes; i++) { - rc = ERROR_SUCCESS; - goto end; - } + INT index,f_index; + DWORD size, sz; + LPWSTR argument; - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - goto end; - } - - while (1) - { - WCHAR clsid[0x100]; - WCHAR buffer[0x100]; - WCHAR desc[0x100]; - DWORD sz; - INT index; - DWORD size; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) + if (package->classes[i].ComponentIndex < 0) { - rc = ERROR_SUCCESS; - break; - } - - sz=0x100; - MSI_RecordGetStringW(row,3,buffer,&sz); - - index = get_loaded_component(package,buffer); - - if (index < 0) - { - msiobj_release(&row->hdr); continue; } - if ((!ACTION_VerifyComponentForAction(package, index, + index = package->classes[i].ComponentIndex; + f_index = package->classes[i].FeatureIndex; + + /* + * yes. MSDN says that these are based on _Feature_ not on + * Component. So verify the feature is to be installed + */ + if ((!ACTION_VerifyFeatureForAction(package, f_index, INSTALLSTATE_LOCAL)) && - (!ACTION_VerifyComponentForAction(package, index, + (!ACTION_VerifyFeatureForAction(package, f_index, INSTALLSTATE_ADVERTISED))) { - TRACE("Skipping class reg due to disabled component\n"); - msiobj_release(&row->hdr); - - package->components[index].Action = - package->components[index].Installed; + TRACE("Skipping class %s reg due to disabled feature %s\n", + debugstr_w(package->classes[i].CLSID), + debugstr_w(package->features[f_index].Feature)); continue; } - package->components[index].Action = INSTALLSTATE_LOCAL; + TRACE("Registering index %i class %s\n",i, + debugstr_w(package->classes[i].CLSID)); - sz=0x100; - MSI_RecordGetStringW(row,1,clsid,&sz); - RegCreateKeyW(hkey,clsid,&hkey2); + package->classes[i].Installed = TRUE; + if (package->classes[i].ProgIDIndex >= 0) + mark_progid_for_install(package, package->classes[i].ProgIDIndex); - if (!MSI_RecordIsNull(row,5)) - { - sz=0x100; - MSI_RecordGetStringW(row,5,desc,&sz); + RegCreateKeyW(hkey,package->classes[i].CLSID,&hkey2); - RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)desc, - (strlenW(desc)+1)*sizeof(WCHAR)); - } - else - desc[0]=0; - - sz=0x100; - MSI_RecordGetStringW(row,2,buffer,&sz); - - RegCreateKeyW(hkey2,buffer,&hkey3); + if (package->classes[i].Description) + RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)package->classes[i]. + Description, (strlenW(package->classes[i]. + Description)+1)*sizeof(WCHAR)); + RegCreateKeyW(hkey2,package->classes[i].Context,&hkey3); index = get_loaded_file(package,package->components[index].KeyPath); - argument = load_dynamic_stringW(row,11); - size = deformat_string(package,argument,&deformated); - if (deformated) - size+=sizeof(WCHAR); - HeapFree(GetProcessHeap(),0,argument); - size += (strlenW(package->files[index].TargetPath))*sizeof(WCHAR); - argument = HeapAlloc(GetProcessHeap(),0,size+sizeof(WCHAR)); - strcpyW(argument,package->files[index].TargetPath); - if (deformated) + /* the context server is a short path name */ + sz = 0; + sz = GetShortPathNameW(package->files[index].TargetPath, NULL, 0); + if (sz == 0) { - strcatW(argument,szSpace); - strcatW(argument,deformated); + ERR("Unable to find short path for CLSID COM Server\n"); } + else + { + size = sz * sizeof(WCHAR); - RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size); - HeapFree(GetProcessHeap(),0,deformated); - HeapFree(GetProcessHeap(),0,argument); + if (package->classes[i].Argument) + { + size += strlenW(package->classes[i].Argument) * sizeof(WCHAR); + size += sizeof(WCHAR); + } + + argument = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR)); + GetShortPathNameW(package->files[index].TargetPath, argument, sz); + + if (package->classes[i].Argument) + { + strcatW(argument,szSpace); + strcatW(argument,package->classes[i].Argument); + } + + RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size); + HeapFree(GetProcessHeap(),0,argument); + } RegCloseKey(hkey3); - if (!MSI_RecordIsNull(row,4)) + if (package->classes[i].ProgIDIndex >= 0 || + package->classes[i].ProgIDText) { - sz=0x100; - MSI_RecordGetStringW(row,4,buffer,&sz); + LPCWSTR progid; + + if (package->classes[i].ProgIDIndex >= 0) + progid = package->progids[ + package->classes[i].ProgIDIndex].ProgID; + else + progid = package->classes[i].ProgIDText; RegCreateKeyW(hkey2,szProgID,&hkey3); - - RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)buffer, - (strlenW(buffer)+1)*sizeof(WCHAR)); - + RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)progid, + (strlenW(progid)+1) *sizeof(WCHAR)); RegCloseKey(hkey3); - } - if (!MSI_RecordIsNull(row,6)) - { - sz=0x100; - MSI_RecordGetStringW(row,6,buffer,&sz); - - RegSetValueExW(hkey2,szAppID,0,REG_SZ,(LPVOID)buffer, - (strlenW(buffer)+1)*sizeof(WCHAR)); - - register_appid(package,buffer,desc); - } - - - if (!MSI_RecordIsNull(row,7)) - { - FIXME("Process field 7\n"); - } - - if (!MSI_RecordIsNull(row,8)) - { - static const WCHAR szDefaultIcon[] = - {'D','e','f','a','u','l','t','I','c','o','n',0}; - - LPWSTR FileName = load_dynamic_stringW(row,8); - LPWSTR FilePath; - INT index; - - RegCreateKeyW(hkey2,szDefaultIcon,&hkey3); - build_icon_path(package,FileName,&FilePath); - if (!MSI_RecordIsNull(row,9)) + if (package->classes[i].ProgIDIndex >= 0 && + package->progids[package->classes[i].ProgIDIndex].ParentIndex + >= 0) { - static const WCHAR index_fmt[] = {',','%','i',0}; - WCHAR index_buf[20]; - index = MSI_RecordGetInteger(row,9); - sprintfW(index_buf,index_fmt,index); - size = strlenW(FilePath)+strlenW(index_buf)+1; - size *= sizeof(WCHAR); - HeapReAlloc(GetProcessHeap(),0,FilePath,size); - } - RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)FilePath, - (strlenW(FilePath)+1) * sizeof(WCHAR)); - HeapFree(GetProcessHeap(),0,FilePath); - HeapFree(GetProcessHeap(),0,FileName); - RegCloseKey(hkey3); - } - - if (!MSI_RecordIsNull(row,10)) - { - static const WCHAR szInproc32[] = - {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2', - 0}; - static const WCHAR szInproc[] = - {'I','n','p','r','o','c','H','a','n','d','l','e','r',0}; - INT i = MSI_RecordGetInteger(row,10); - if (i != MSI_NULL_INTEGER && i > 0 && i < 4) - { - static const WCHAR ole2[] = {'o','l','e','2','.','d','l','l',0}; - static const WCHAR ole32[] = - {'o','l','e','3','2','.','d','l','l',0}; - switch(i) - { - case 1: - size = strlenW(ole2) * sizeof(WCHAR); - RegCreateKeyW(hkey2,szInproc,&hkey3); - RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole2, size); - RegCloseKey(hkey3); - break; - case 2: - size = strlenW(ole32) * sizeof(WCHAR); - RegCreateKeyW(hkey2,szInproc32,&hkey3); - RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole32,size); - RegCloseKey(hkey3); - break; - case 3: - size = strlenW(ole2) * sizeof(WCHAR); - RegCreateKeyW(hkey2,szInproc,&hkey3); - RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole2, size); - RegCloseKey(hkey3); - size = strlenW(ole32) * sizeof(WCHAR); - RegCreateKeyW(hkey2,szInproc32,&hkey3); - RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole32,size); - RegCloseKey(hkey3); - break; - } - - } - else - { - RegCreateKeyW(hkey2,szInproc32,&hkey3); - argument = load_dynamic_stringW(row,10); - reduce_to_longfilename(argument); - size = strlenW(argument)*sizeof(WCHAR); - - RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size); - HeapFree(GetProcessHeap(),0,argument); + progid = package->progids[package->progids[ + package->classes[i].ProgIDIndex].ParentIndex].ProgID; + RegCreateKeyW(hkey2,szVIProgID,&hkey3); + RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)progid, + (strlenW(progid)+1) *sizeof(WCHAR)); RegCloseKey(hkey3); } } + if (package->classes[i].AppIDIndex >= 0) + { + RegSetValueExW(hkey2,szAppID,0,REG_SZ, + (LPVOID)package->appids[package->classes[i].AppIDIndex].AppID, + (strlenW(package->appids[package->classes[i].AppIDIndex].AppID)+1) + *sizeof(WCHAR)); + + register_appid(package,package->classes[i].AppIDIndex, + package->classes[i].Description); + } + + if (package->classes[i].FileTypeMask) + { + FIXME("Process field 7\n"); + } + + if (package->classes[i].IconPath) + { + static const WCHAR szDefaultIcon[] = + {'D','e','f','a','u','l','t','I','c','o','n',0}; + + RegCreateKeyW(hkey2,szDefaultIcon,&hkey3); + + RegSetValueExW(hkey3,NULL,0,REG_SZ, + (LPVOID)package->classes[i].IconPath, + (strlenW(package->classes[i].IconPath)+1) * + sizeof(WCHAR)); + + RegCloseKey(hkey3); + } + + if (package->classes[i].DefInprocHandler) + { + static const WCHAR szInproc[] = + {'I','n','p','r','o','c','H','a','n','d','l','e','r',0}; + + size = (strlenW(package->classes[i].DefInprocHandler) + 1) * + sizeof(WCHAR); + RegCreateKeyW(hkey2,szInproc,&hkey3); + RegSetValueExW(hkey3,NULL,0,REG_SZ, + (LPVOID)package->classes[i].DefInprocHandler, size); + RegCloseKey(hkey3); + } + + if (package->classes[i].DefInprocHandler32) + { + static const WCHAR szInproc32[] = + {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2', + 0}; + size = (strlenW(package->classes[i].DefInprocHandler32) + 1) * + sizeof(WCHAR); + + RegCreateKeyW(hkey2,szInproc32,&hkey3); + RegSetValueExW(hkey3,NULL,0,REG_SZ, + (LPVOID)package->classes[i].DefInprocHandler32,size); + RegCloseKey(hkey3); + } + RegCloseKey(hkey2); - ui_actiondata(package,szRegisterClassInfo,row); + uirow = MSI_CreateRecord(1); - msiobj_release(&row->hdr); + MSI_RecordSetStringW(uirow,1,package->classes[i].CLSID); + ui_actiondata(package,szRegisterClassInfo,uirow); + msiobj_release(&uirow->hdr); } - MSI_ViewClose(view); - msiobj_release(&view->hdr); -end: RegCloseKey(hkey); return rc; } -static UINT register_progid_base(MSIPACKAGE* package, MSIRECORD * row, - LPWSTR clsid) +static UINT register_progid_base(MSIPACKAGE* package, MSIPROGID* progid, + LPWSTR clsid) { static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 }; static const WCHAR szDefaultIcon[] = {'D','e','f','a','u','l','t','I','c','o','n',0}; HKEY hkey,hkey2; - WCHAR buffer[0x100]; - DWORD sz; + RegCreateKeyW(HKEY_CLASSES_ROOT,progid->ProgID,&hkey); - sz = 0x100; - MSI_RecordGetStringW(row,1,buffer,&sz); - RegCreateKeyW(HKEY_CLASSES_ROOT,buffer,&hkey); - - if (!MSI_RecordIsNull(row,4)) + if (progid->Description) { - sz = 0x100; - MSI_RecordGetStringW(row,4,buffer,&sz); - RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) * + RegSetValueExW(hkey,NULL,0,REG_SZ, + (LPVOID)progid->Description, + (strlenW(progid->Description)+1) * sizeof(WCHAR)); } - if (!MSI_RecordIsNull(row,3)) + if (progid->ClassIndex >= 0) { - sz = 0x100; - - MSI_RecordGetStringW(row,3,buffer,&sz); RegCreateKeyW(hkey,szCLSID,&hkey2); - RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) * - sizeof(WCHAR)); + RegSetValueExW(hkey2,NULL,0,REG_SZ, + (LPVOID)package->classes[progid->ClassIndex].CLSID, + (strlenW(package->classes[progid->ClassIndex].CLSID)+1) + * sizeof(WCHAR)); if (clsid) - strcpyW(clsid,buffer); + strcpyW(clsid,package->classes[progid->ClassIndex].CLSID); RegCloseKey(hkey2); } else { FIXME("UNHANDLED case, Parent progid but classid is NULL\n"); - return ERROR_FUNCTION_FAILED; } - if (!MSI_RecordIsNull(row,5)) + + if (progid->IconPath) { - INT index = MSI_RecordGetInteger(row,6); - LPWSTR FileName = load_dynamic_stringW(row,5); - LPWSTR FilePath,IconPath; - static const WCHAR fmt[] = {'%','s',',','%','i',0}; - RegCreateKeyW(hkey,szDefaultIcon,&hkey2); - build_icon_path(package,FileName,&FilePath); - - IconPath = HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+5)* - sizeof(WCHAR)); - sprintfW(IconPath,fmt,FilePath,index); - RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)IconPath, - (strlenW(IconPath)+1) * sizeof(WCHAR)); - HeapFree(GetProcessHeap(),0,FilePath); - HeapFree(GetProcessHeap(),0,FileName); + RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)progid->IconPath, + (strlenW(progid->IconPath)+1) * sizeof(WCHAR)); RegCloseKey(hkey2); } return ERROR_SUCCESS; } -static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid); - -static UINT register_parent_progid(MSIPACKAGE *package, LPCWSTR parent, - LPWSTR clsid) -{ - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR Query_t[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','P','r','o','g' ,'I','d','`',' ','W','H','E','R','E',' ', - '`','P','r','o','g','I','d','`',' ','=',' ','\'' ,'%','s','\'',0}; - - if (!package) - return ERROR_INVALID_HANDLE; - - rc = MSI_OpenQuery(package->db, &view, Query_t, parent); - if (rc != ERROR_SUCCESS) - return rc; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - register_progid(package,row,clsid); - - msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; -} - -static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid) +static UINT register_progid(MSIPACKAGE *package, MSIPROGID* progid, + LPWSTR clsid) { UINT rc = ERROR_SUCCESS; - if (MSI_RecordIsNull(row,2)) - rc = register_progid_base(package,row,clsid); + if (progid->ParentIndex < 0) + rc = register_progid_base(package, progid, clsid); else { - WCHAR buffer[0x1000]; - DWORD sz, disp; + DWORD disp; HKEY hkey,hkey2; static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 }; static const WCHAR szDefaultIcon[] = {'D','e','f','a','u','l','t','I','c','o','n',0}; /* check if already registered */ - sz = 0x100; - MSI_RecordGetStringW(row,1,buffer,&sz); - RegCreateKeyExW(HKEY_CLASSES_ROOT, buffer, 0, NULL, 0, + RegCreateKeyExW(HKEY_CLASSES_ROOT, progid->ProgID, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disp ); if (disp == REG_OPENED_EXISTING_KEY) { @@ -4911,9 +5666,11 @@ static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid) return rc; } - sz = 0x100; - MSI_RecordGetStringW(row,2,buffer,&sz); - rc = register_parent_progid(package,buffer,clsid); + TRACE("Registering Parent %s index %i\n", + debugstr_w(package->progids[progid->ParentIndex].ProgID), + progid->ParentIndex); + rc = register_progid(package,&package->progids[progid->ParentIndex], + clsid); /* clsid is same as parent */ RegCreateKeyW(hkey,szCLSID,&hkey2); @@ -4923,24 +5680,17 @@ static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid) RegCloseKey(hkey2); - if (!MSI_RecordIsNull(row,4)) + if (progid->Description) { - sz = 0x100; - MSI_RecordGetStringW(row,4,buffer,&sz); - RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer, - (strlenW(buffer)+1) * sizeof(WCHAR)); + RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid->Description, + (strlenW(progid->Description)+1) * sizeof(WCHAR)); } - if (!MSI_RecordIsNull(row,5)) + if (progid->IconPath) { - LPWSTR FileName = load_dynamic_stringW(row,5); - LPWSTR FilePath; RegCreateKeyW(hkey,szDefaultIcon,&hkey2); - build_icon_path(package,FileName,&FilePath); - RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)FilePath, - (strlenW(FilePath)+1) * sizeof(WCHAR)); - HeapFree(GetProcessHeap(),0,FilePath); - HeapFree(GetProcessHeap(),0,FileName); + RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)progid->IconPath, + (strlenW(progid->IconPath)+1) * sizeof(WCHAR)); RegCloseKey(hkey2); } @@ -4951,55 +5701,39 @@ static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid) static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package) { - /* - * Sigh, here I am just brute force registering all progids - * this needs to be linked to the Classes that have been registered - * but the easiest way to do that is to load all these stuff into - * memory for easy checking. - * - * Gives me something to continue to work toward. - */ - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR Query[] = - {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', - '`','P','r','o','g','I','d','`',0}; + INT i; + MSIRECORD *uirow; if (!package) return ERROR_INVALID_HANDLE; - rc = MSI_DatabaseOpenViewW(package->db, Query, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; + load_classes_and_such(package); - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - while (1) + for (i = 0; i < package->loaded_progids; i++) { WCHAR clsid[0x1000]; - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - register_progid(package,row,clsid); - ui_actiondata(package,szRegisterProgIdInfo,row); + /* check if this progid is to be installed */ - msiobj_release(&row->hdr); + if (!package->progids[i].InstallMe) + { + TRACE("progid %s not scheduled to be installed\n", + debugstr_w(package->progids[i].ProgID)); + continue; + } + + TRACE("Registering progid %s index %i\n", + debugstr_w(package->progids[i].ProgID), i); + + register_progid(package,&package->progids[i],clsid); + + uirow = MSI_CreateRecord(1); + MSI_RecordSetStringW(uirow,1,package->progids[i].ProgID); + ui_actiondata(package,szRegisterProgIdInfo,uirow); + msiobj_release(&uirow->hdr); } - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; + + return ERROR_SUCCESS; } static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, @@ -5011,9 +5745,10 @@ static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, UINT rc; static const WCHAR szInstaller[] = - {'I','n','s','t','a','l','l','e','r','\\',0}; + {'M','i','c','r','o','s','o','f','t','\\', + 'I','n','s','t','a','l','l','e','r','\\',0}; static const WCHAR szFolder[] = - {'W','i','n','d','o','w','s','F','o','l','d','e','r',0}; + {'A','p','p','D','a','t','a','F','o','l','d','e','r',0}; ProductCode = load_dynamic_property(package,szProductCode,&rc); if (!ProductCode) @@ -5999,102 +6734,229 @@ UINT ACTION_ResolveSource(MSIPACKAGE* package) return ERROR_SUCCESS; } +static LPWSTR create_component_advertise_string(MSIPACKAGE* package, + MSICOMPONENT* component, LPCWSTR feature) +{ + LPWSTR productid=NULL; + GUID clsid; + WCHAR productid_85[21]; + WCHAR component_85[21]; + /* + * I have a fair bit of confusion as to when a < is used and when a > is + * used. I do not think i have it right... + * + * Ok it appears that the > is used if there is a guid for the compoenent + * and the < is used if not. + */ + static WCHAR fmt1[] = {'%','s','%','s','<',0,0}; + static WCHAR fmt2[] = {'%','s','%','s','>','%','s',0,0}; + LPWSTR output = NULL; + DWORD sz = 0; + + memset(productid_85,0,sizeof(productid_85)); + memset(component_85,0,sizeof(component_85)); + + productid = load_dynamic_property(package,szProductCode,NULL); + CLSIDFromString(productid, &clsid); + + encode_base85_guid(&clsid,productid_85); + + CLSIDFromString(component->ComponentId, &clsid); + encode_base85_guid(&clsid,component_85); + + TRACE("Doing something with this... %s %s %s\n", + debugstr_w(productid_85), debugstr_w(feature), + debugstr_w(component_85)); + + sz = lstrlenW(productid_85) + lstrlenW(feature); + if (component) + sz += lstrlenW(component_85); + + sz+=3; + sz *= sizeof(WCHAR); + + output = HeapAlloc(GetProcessHeap(),0,sz); + memset(output,0,sz); + + if (component) + sprintfW(output,fmt2,productid_85,feature,component_85); + else + sprintfW(output,fmt1,productid_85,feature); + + HeapFree(GetProcessHeap(),0,productid); + + return output; +} + +static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid, + MSICOMPONENT* component, MSIEXTENSION* extension, + MSIVERB* verb, INT* Sequence ) +{ + LPWSTR keyname; + HKEY key; + static const WCHAR szShell[] = {'s','h','e','l','l',0}; + static const WCHAR szCommand[] = {'c','o','m','m','a','n','d',0}; + static const WCHAR fmt[] = {'\"','%','s','\"',' ','%','s',0}; + static const WCHAR fmt2[] = {'\"','%','s','\"',0}; + LPWSTR command; + DWORD size; + LPWSTR advertise; + + keyname = build_directory_name(4, progid, szShell, verb->Verb, szCommand); + + TRACE("Making Key %s\n",debugstr_w(keyname)); + RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key); + size = strlenW(component->FullKeypath); + if (verb->Argument) + size += strlenW(verb->Argument); + size += 4; + + command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR)); + if (verb->Argument) + sprintfW(command, fmt, component->FullKeypath, verb->Argument); + else + sprintfW(command, fmt2, component->FullKeypath); + + RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)command, (strlenW(command)+1)* + sizeof(WCHAR)); + HeapFree(GetProcessHeap(),0,command); + + advertise = create_component_advertise_string(package, component, + package->features[extension->FeatureIndex].Feature); + + size = strlenW(advertise); + + if (verb->Argument) + size += strlenW(verb->Argument); + size += 4; + + command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR)); + memset(command,0,size*sizeof(WCHAR)); + + strcpyW(command,advertise); + if (verb->Argument) + { + static const WCHAR szSpace[] = {' ',0}; + strcatW(command,szSpace); + strcatW(command,verb->Argument); + } + + RegSetValueExW(key, szCommand, 0, REG_MULTI_SZ, (LPBYTE)command, + (strlenW(command)+2)*sizeof(WCHAR)); + + RegCloseKey(key); + HeapFree(GetProcessHeap(),0,keyname); + HeapFree(GetProcessHeap(),0,advertise); + HeapFree(GetProcessHeap(),0,command); + + if (verb->Command) + { + keyname = build_directory_name(3, progid, szShell, verb->Verb); + RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key); + RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)verb->Command, + (strlenW(verb->Command)+1) *sizeof(WCHAR)); + RegCloseKey(key); + HeapFree(GetProcessHeap(),0,keyname); + } + + if (verb->Sequence != MSI_NULL_INTEGER) + { + if (*Sequence == MSI_NULL_INTEGER || verb->Sequence < *Sequence) + { + *Sequence = verb->Sequence; + keyname = build_directory_name(2, progid, szShell); + RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key); + RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)verb->Verb, + (strlenW(verb->Verb)+1) *sizeof(WCHAR)); + RegCloseKey(key); + HeapFree(GetProcessHeap(),0,keyname); + } + } + return ERROR_SUCCESS; +} static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package) { - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR ExecSeqQuery[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','E','x','t','e','n','s','i','o','n','`',0}; static const WCHAR szContentType[] = {'C','o','n','t','e','n','t',' ','T','y','p','e',0 }; HKEY hkey; + INT i; + MSIRECORD *uirow; if (!package) return ERROR_INVALID_HANDLE; - rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - goto end; - } + load_classes_and_such(package); - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) + for (i = 0; i < package->loaded_extensions; i++) { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - goto end; - } - - while (1) - { - WCHAR buffer[0x100]; WCHAR extension[257]; - LPWSTR exten; - DWORD sz; - INT index; + INT index,f_index; - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - sz=0x100; - MSI_RecordGetStringW(row,2,buffer,&sz); - - index = get_loaded_component(package,buffer); + index = package->extensions[i].ComponentIndex; + f_index = package->extensions[i].FeatureIndex; if (index < 0) - { - msiobj_release(&row->hdr); continue; - } - if ((!ACTION_VerifyComponentForAction(package, index, + /* + * yes. MSDN says that these are based on _Feature_ not on + * Component. So verify the feature is to be installed + */ + if ((!ACTION_VerifyFeatureForAction(package, f_index, INSTALLSTATE_LOCAL)) && - (!ACTION_VerifyComponentForAction(package, index, + (!ACTION_VerifyFeatureForAction(package, f_index, INSTALLSTATE_ADVERTISED))) { - TRACE("Skipping extension reg due to disabled component\n"); - msiobj_release(&row->hdr); - - package->components[index].Action = - package->components[index].Installed; + TRACE("Skipping extension %s reg due to disabled feature %s\n", + debugstr_w(package->extensions[i].Extension), + debugstr_w(package->features[f_index].Feature)); continue; } - package->components[index].Action = INSTALLSTATE_LOCAL; + TRACE("Registering extension %s index %i\n", + debugstr_w(package->extensions[i].Extension), i); + + package->extensions[i].Installed = TRUE; + + if (package->extensions[i].ProgIDIndex >= 0) + mark_progid_for_install(package, package->extensions[i].ProgIDIndex); + + if (package->extensions[i].MIMEIndex >= 0) + mark_mime_for_install(package, package->extensions[i].MIMEIndex); - exten = load_dynamic_stringW(row,1); extension[0] = '.'; extension[1] = 0; - strcatW(extension,exten); - HeapFree(GetProcessHeap(),0,exten); + strcatW(extension,package->extensions[i].Extension); RegCreateKeyW(HKEY_CLASSES_ROOT,extension,&hkey); - if (!MSI_RecordIsNull(row,4)) + if (package->extensions[i].MIMEIndex >= 0) { - LPWSTR mime = load_dynamic_stringW(row,4); - RegSetValueExW(hkey,szContentType,0,REG_SZ,(LPVOID)mime, - (strlenW(mime)+1)*sizeof(WCHAR)); - HeapFree(GetProcessHeap(),0,mime); + RegSetValueExW(hkey,szContentType,0,REG_SZ, + (LPVOID)package->mimes[package->extensions[i]. + MIMEIndex].ContentType, + (strlenW(package->mimes[package->extensions[i]. + MIMEIndex].ContentType)+1)*sizeof(WCHAR)); } - if (!MSI_RecordIsNull(row,3)) + if (package->extensions[i].ProgIDIndex >= 0 || + package->extensions[i].ProgIDText) { static const WCHAR szSN[] = {'\\','S','h','e','l','l','N','e','w',0}; HKEY hkey2; LPWSTR newkey; - LPWSTR progid= load_dynamic_stringW(row,3); + LPCWSTR progid; + INT v; + INT Sequence = MSI_NULL_INTEGER; + + if (package->extensions[i].ProgIDIndex >= 0) + progid = package->progids[package->extensions[i]. + ProgIDIndex].ProgID; + else + progid = package->extensions[i].ProgIDText; RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid, (strlenW(progid)+1)*sizeof(WCHAR)); @@ -6107,77 +6969,73 @@ static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package) RegCreateKeyW(hkey,newkey,&hkey2); RegCloseKey(hkey2); - HeapFree(GetProcessHeap(),0,progid); HeapFree(GetProcessHeap(),0,newkey); + + /* do all the verbs */ + for (v = 0; v < package->extensions[i].VerbCount; v++) + register_verb(package, progid, + &package->components[index], + &package->extensions[i], + &package->verbs[package->extensions[i].Verbs[v]], + &Sequence); } - - + RegCloseKey(hkey); - ui_actiondata(package,szRegisterExtensionInfo,row); - - msiobj_release(&row->hdr); + uirow = MSI_CreateRecord(1); + MSI_RecordSetStringW(uirow,1,package->extensions[i].Extension); + ui_actiondata(package,szRegisterExtensionInfo,uirow); + msiobj_release(&uirow->hdr); } - MSI_ViewClose(view); - msiobj_release(&view->hdr); -end: - return rc; + return ERROR_SUCCESS; } static UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package) { - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR ExecSeqQuery[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','M','I','M','E','`',0}; static const WCHAR szExten[] = {'E','x','t','e','n','s','i','o','n',0 }; HKEY hkey; + INT i; + MSIRECORD *uirow; if (!package) return ERROR_INVALID_HANDLE; - rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - goto end; - } + load_classes_and_such(package); - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - goto end; - } - - while (1) + for (i = 0; i < package->loaded_mimes; i++) { WCHAR extension[257]; - LPWSTR exten; - LPWSTR mime; + LPCWSTR exten; + LPCWSTR mime; static const WCHAR fmt[] = {'M','I','M','E','\\','D','a','t','a','b','a','s','e','\\', 'C','o','n','t','e','n','t',' ','T','y','p','e','\\', '%','s',0}; LPWSTR key; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - mime = load_dynamic_stringW(row,1); - exten = load_dynamic_stringW(row,2); + /* + * check if the MIME is to be installed. Either as requesed by an + * extension or Class + */ + package->mimes[i].InstallMe = ((package->mimes[i].InstallMe) || + (package->mimes[i].ClassIndex >= 0 && + package->classes[package->mimes[i].ClassIndex].Installed) || + (package->mimes[i].ExtensionIndex >=0 && + package->extensions[package->mimes[i].ExtensionIndex].Installed)); + + if (!package->mimes[i].InstallMe) + { + TRACE("MIME %s not scheduled to be installed\n", + debugstr_w(package->mimes[i].ContentType)); + continue; + } + + mime = package->mimes[i].ContentType; + exten = package->extensions[package->mimes[i].ExtensionIndex].Extension; extension[0] = '.'; extension[1] = 0; strcatW(extension,exten); - HeapFree(GetProcessHeap(),0,exten); key = HeapAlloc(GetProcessHeap(),0,(strlenW(mime)+strlenW(fmt)+1) * sizeof(WCHAR)); @@ -6186,25 +7044,23 @@ static UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package) RegSetValueExW(hkey,szExten,0,REG_SZ,(LPVOID)extension, (strlenW(extension)+1)*sizeof(WCHAR)); - HeapFree(GetProcessHeap(),0,mime); HeapFree(GetProcessHeap(),0,key); - if (!MSI_RecordIsNull(row,3)) + if (package->mimes[i].CLSID[0]) { FIXME("Handle non null for field 3\n"); } RegCloseKey(hkey); - ui_actiondata(package,szRegisterMIMEInfo,row); - - msiobj_release(&row->hdr); + uirow = MSI_CreateRecord(2); + MSI_RecordSetStringW(uirow,1,package->mimes[i].ContentType); + MSI_RecordSetStringW(uirow,2,exten); + ui_actiondata(package,szRegisterMIMEInfo,uirow); + msiobj_release(&uirow->hdr); } - MSI_ViewClose(view); - msiobj_release(&view->hdr); -end: - return rc; + return ERROR_SUCCESS; } static UINT ACTION_RegisterUser(MSIPACKAGE *package) @@ -6522,101 +7378,71 @@ static UINT ACTION_RegisterFonts(MSIPACKAGE *package) static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param) { MSIPACKAGE *package = (MSIPACKAGE*)param; - LPWSTR productid=NULL, compgroupid=NULL; + LPWSTR compgroupid=NULL; LPWSTR feature=NULL; LPWSTR text = NULL; LPWSTR qualifier = NULL; LPWSTR component = NULL; - GUID clsid; - WCHAR productid_85[21]; - WCHAR component_85[21]; + LPWSTR advertise = NULL; + LPWSTR output = NULL; HKEY hkey; UINT rc = ERROR_SUCCESS; UINT index; - /* - * I have a fair bit of confusion as to when a < is used and when a > is - * used. I do not think i have it right... - * - * Ok it appears that the > is used if there is a guid for the compoenent - * and the < is used if not. - */ - static WCHAR fmt1[] = {'%','s','%','s','<',0,0}; - static WCHAR fmt2[] = {'%','s','%','s','>','%','s',0,0}; - LPWSTR output = NULL; DWORD sz = 0; - INT component_index; component = load_dynamic_stringW(rec,3); - component_index = get_loaded_component(package,component); + index = get_loaded_component(package,component); - if (!ACTION_VerifyComponentForAction(package, component_index, + if (!ACTION_VerifyComponentForAction(package, index, INSTALLSTATE_LOCAL) && - !ACTION_VerifyComponentForAction(package, component_index, + !ACTION_VerifyComponentForAction(package, index, INSTALLSTATE_SOURCE) && - !ACTION_VerifyComponentForAction(package, component_index, + !ACTION_VerifyComponentForAction(package, index, INSTALLSTATE_ADVERTISED)) { TRACE("Skipping: Component %s not scheduled for install\n", debugstr_w(component)); + HeapFree(GetProcessHeap(),0,component); return ERROR_SUCCESS; } - memset(productid_85,0,sizeof(productid_85)); - memset(component_85,0,sizeof(component_85)); compgroupid = load_dynamic_stringW(rec,1); rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE); if (rc != ERROR_SUCCESS) goto end; - productid = load_dynamic_property(package,szProductCode,NULL); - CLSIDFromString(productid, &clsid); - - encode_base85_guid(&clsid,productid_85); - text = load_dynamic_stringW(rec,4); qualifier = load_dynamic_stringW(rec,2); - feature = load_dynamic_stringW(rec,5); - index = get_loaded_component(package, component); - CLSIDFromString(package->components[index].ComponentId, &clsid); - encode_base85_guid(&clsid,component_85); + advertise = create_component_advertise_string(package, + &package->components[index], feature); + + sz = strlenW(advertise); - TRACE("Doing something with this... %s = %s %s %s %s\n", - debugstr_w(qualifier), debugstr_w(productid_85), - debugstr_w(feature), debugstr_w(text), debugstr_w(component_85)); - - sz = lstrlenW(productid_85) + lstrlenW(feature); if (text) sz += lstrlenW(text); - if (component && index >= 0) - sz += lstrlenW(component_85); sz+=3; sz *= sizeof(WCHAR); output = HeapAlloc(GetProcessHeap(),0,sz); memset(output,0,sz); - - if (component && index >= 0) - sprintfW(output,fmt2,productid_85,feature,component_85); - else - sprintfW(output,fmt1,productid_85,feature); + strcpyW(output,advertise); if (text) strcatW(output,text); sz = (lstrlenW(output)+2) * sizeof(WCHAR); - RegSetValueExW(hkey, qualifier,0,REG_MULTI_SZ, (LPBYTE)output, sz); + RegSetValueExW(hkey, qualifier,0,REG_MULTI_SZ, (LPBYTE)output, sz); end: RegCloseKey(hkey); HeapFree(GetProcessHeap(),0,output); HeapFree(GetProcessHeap(),0,compgroupid); HeapFree(GetProcessHeap(),0,component); - HeapFree(GetProcessHeap(),0,productid); HeapFree(GetProcessHeap(),0,feature); HeapFree(GetProcessHeap(),0,text); HeapFree(GetProcessHeap(),0,qualifier); diff --git a/dlls/msi/action.h b/dlls/msi/action.h index a88a07f5e15..5134538667e 100644 --- a/dlls/msi/action.h +++ b/dlls/msi/action.h @@ -18,15 +18,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define IDENTIFIER_SIZE 96 + typedef struct tagMSIFEATURE { - WCHAR Feature[96]; - WCHAR Feature_Parent[96]; + WCHAR Feature[IDENTIFIER_SIZE]; + WCHAR Feature_Parent[IDENTIFIER_SIZE]; WCHAR Title[0x100]; WCHAR Description[0x100]; INT Display; INT Level; - WCHAR Directory[96]; + WCHAR Directory[IDENTIFIER_SIZE]; INT Attributes; INSTALLSTATE Installed; @@ -40,12 +42,12 @@ typedef struct tagMSIFEATURE typedef struct tagMSICOMPONENT { - WCHAR Component[96]; - WCHAR ComponentId[96]; - WCHAR Directory[96]; + WCHAR Component[IDENTIFIER_SIZE]; + WCHAR ComponentId[IDENTIFIER_SIZE]; + WCHAR Directory[IDENTIFIER_SIZE]; INT Attributes; WCHAR Condition[0x100]; - WCHAR KeyPath[96]; + WCHAR KeyPath[IDENTIFIER_SIZE]; INSTALLSTATE Installed; INSTALLSTATE ActionRequest; @@ -56,6 +58,7 @@ typedef struct tagMSICOMPONENT INT RefCount; LPWSTR FullKeypath; + LPWSTR AdvertiseString; } MSICOMPONENT; typedef struct tagMSIFOLDER @@ -100,6 +103,81 @@ typedef struct tagMSIFILE BOOL Temporary; }MSIFILE; +typedef struct tagMSICLASS +{ + WCHAR CLSID[IDENTIFIER_SIZE]; /* Primary Key */ + WCHAR Context[IDENTIFIER_SIZE]; /* Primary Key */ + INT ComponentIndex; /* Primary Key */ + INT ProgIDIndex; + LPWSTR ProgIDText; + LPWSTR Description; + INT AppIDIndex; + LPWSTR FileTypeMask; + LPWSTR IconPath; + LPWSTR DefInprocHandler; + LPWSTR DefInprocHandler32; + LPWSTR Argument; + INT FeatureIndex; + INT Attributes; + /* not in the table, set during instalation */ + BOOL Installed; +} MSICLASS; + +typedef struct tagMSIEXTENSION +{ + WCHAR Extension[256]; /* Primary Key */ + INT ComponentIndex; /* Primary Key */ + INT ProgIDIndex; + LPWSTR ProgIDText; + INT MIMEIndex; + INT FeatureIndex; + /* not in the table, set during instalation */ + BOOL Installed; + INT VerbCount; + INT Verbs[100]; /* yes hard coded limit, but relisticly 100 verbs??? */ +} MSIEXTENSION; + +typedef struct tagMSIPROGID +{ + LPWSTR ProgID; /* Primary Key */ + INT ParentIndex; + INT ClassIndex; + LPWSTR Description; + LPWSTR IconPath; + /* not in the table, set during instalation */ + BOOL InstallMe; +} MSIPROGID; + +typedef struct tagMSIVERB +{ + INT ExtensionIndex; + LPWSTR Verb; + INT Sequence; + LPWSTR Command; + LPWSTR Argument; +} MSIVERB; + +typedef struct tagMSIMIME +{ + LPWSTR ContentType; /* Primary Key */ + INT ExtensionIndex; + WCHAR CLSID[IDENTIFIER_SIZE]; + INT ClassIndex; + /* not in the table, set during instalation */ + BOOL InstallMe; +} MSIMIME; + +typedef struct tagMSIAPPID +{ + WCHAR AppID[IDENTIFIER_SIZE]; /* Primary key */ + LPWSTR RemoteServerName; + LPWSTR LocalServer; + LPWSTR ServiceParameters; + LPWSTR DllSurrogate; + BOOL ActivateAtStorage; + BOOL RunAsInteractiveUser; +} MSIAPPID; + UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action); UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action); diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index 8aa931a198b..778bcee6058 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -197,6 +197,19 @@ typedef struct tagMSIPACKAGE LPWSTR ActionFormat; LPWSTR LastAction; + struct tagMSICLASS *classes; + UINT loaded_classes; + struct tagMSIEXTENSION *extensions; + UINT loaded_extensions; + struct tagMSIPROGID *progids; + UINT loaded_progids; + struct tagMSIVERB *verbs; + UINT loaded_verbs; + struct tagMSIMIME *mimes; + UINT loaded_mimes; + struct tagMSIAPPID *appids; + UINT loaded_appids; + LPWSTR *DeferredAction; UINT DeferredActionCount;