From 6f43c18fe73e30c1bbf66dd82220e328138591f6 Mon Sep 17 00:00:00 2001 From: Aric Stewart Date: Thu, 26 May 2005 12:24:28 +0000 Subject: [PATCH] A big rewrite of the whole RegisterClass, RegisterProgId, RegisterExtension and RegisterMIME actions. We now handle verbs properly, handle dependancies and such properly and keep track of what we need to register and what we do not properly. --- dlls/msi/action.c | 1926 +++++++++++++++++++++++++++++++------------- dlls/msi/action.h | 92 ++- dlls/msi/msipriv.h | 13 + 3 files changed, 1474 insertions(+), 557 deletions(-) diff --git a/dlls/msi/action.c b/dlls/msi/action.c index a115a422bf..322ef60c49 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 a88a07f5e1..5134538667 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 8aa931a198..778bcee605 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;