From b7a1c590295b5a5a20f95a10656c0c81778ef413 Mon Sep 17 00:00:00 2001 From: Christoph von Wittich Date: Mon, 1 Mar 2010 12:01:30 +0000 Subject: [PATCH] [MSI] sync msi to wine 1.1.39 svn path=/trunk/; revision=45738 --- reactos/dll/win32/msi/action.c | 669 +++++++++++++++++++++------- reactos/dll/win32/msi/classes.c | 23 +- reactos/dll/win32/msi/database.c | 46 +- reactos/dll/win32/msi/events.c | 3 - reactos/dll/win32/msi/files.c | 16 +- reactos/dll/win32/msi/font.c | 113 ++++- reactos/dll/win32/msi/helpers.c | 22 - reactos/dll/win32/msi/install.c | 60 ++- reactos/dll/win32/msi/msi.c | 87 ++++ reactos/dll/win32/msi/msi.spec | 4 +- reactos/dll/win32/msi/msi_It.rc | 12 +- reactos/dll/win32/msi/msipriv.h | 8 +- reactos/dll/win32/msi/msiserver.idl | 1 + reactos/dll/win32/msi/package.c | 8 + reactos/dll/win32/msi/streams.c | 24 +- reactos/dll/win32/msi/suminfo.c | 3 - reactos/dll/win32/msi/table.c | 8 +- reactos/dll/win32/msi/tokenize.c | 4 +- reactos/include/psdk/msi.h | 4 + 19 files changed, 836 insertions(+), 279 deletions(-) diff --git a/reactos/dll/win32/msi/action.c b/reactos/dll/win32/msi/action.c index d94d842cae1..20929c6cd1a 100644 --- a/reactos/dll/win32/msi/action.c +++ b/reactos/dll/win32/msi/action.c @@ -886,10 +886,24 @@ static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action, static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param) { MSIPACKAGE *package = param; - LPCWSTR dir; + LPCWSTR dir, component; LPWSTR full_path; MSIRECORD *uirow; MSIFOLDER *folder; + MSICOMPONENT *comp; + + component = MSI_RecordGetString(row, 2); + comp = get_loaded_component(package, component); + if (!comp) + return ERROR_SUCCESS; + + if (comp->ActionRequest != INSTALLSTATE_LOCAL) + { + TRACE("Component not scheduled for installation: %s\n", debugstr_w(component)); + comp->Action = comp->Installed; + return ERROR_SUCCESS; + } + comp->Action = INSTALLSTATE_LOCAL; dir = MSI_RecordGetString(row,1); if (!dir) @@ -951,7 +965,7 @@ UINT msi_create_component_directories( MSIPACKAGE *package ) /* create all the folders required by the components are going to install */ LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) { - if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL)) + if (comp->ActionRequest != INSTALLSTATE_LOCAL) continue; msi_create_directory( package, comp->Directory ); } @@ -983,10 +997,24 @@ static UINT ACTION_CreateFolders(MSIPACKAGE *package) static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param ) { MSIPACKAGE *package = param; - LPCWSTR dir; + LPCWSTR dir, component; LPWSTR full_path; MSIRECORD *uirow; MSIFOLDER *folder; + MSICOMPONENT *comp; + + component = MSI_RecordGetString(row, 2); + comp = get_loaded_component(package, component); + if (!comp) + return ERROR_SUCCESS; + + if (comp->ActionRequest != INSTALLSTATE_ABSENT) + { + TRACE("Component not scheduled for removal: %s\n", debugstr_w(component)); + comp->Action = comp->Installed; + return ERROR_SUCCESS; + } + comp->Action = INSTALLSTATE_ABSENT; dir = MSI_RecordGetString( row, 1 ); if (!dir) @@ -2231,16 +2259,12 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param) if (!comp) return ERROR_SUCCESS; - if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL)) + if (comp->ActionRequest != INSTALLSTATE_LOCAL) { - TRACE("Skipping write due to disabled component %s\n", - debugstr_w(component)); - + TRACE("Component not scheduled for installation: %s\n", debugstr_w(component)); comp->Action = comp->Installed; - return ERROR_SUCCESS; } - comp->Action = INSTALLSTATE_LOCAL; name = MSI_RecordGetString(row, 4); @@ -2623,7 +2647,7 @@ static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp ) { ComponentList *cl; - if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL )) + if (feature->ActionRequest != INSTALLSTATE_LOCAL) continue; LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) @@ -2638,7 +2662,7 @@ static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp ) { ComponentList *cl; - if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT )) + if (feature->ActionRequest != INSTALLSTATE_ABSENT) continue; LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) @@ -2704,8 +2728,8 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) debugstr_w(comp->FullKeypath), comp->RefCount); - if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL) || - ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE)) + if (comp->ActionRequest == INSTALLSTATE_LOCAL || + comp->ActionRequest == INSTALLSTATE_SOURCE) { if (!comp->FullKeypath) continue; @@ -2771,7 +2795,7 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) } RegCloseKey(hkey); } - else if (ACTION_VerifyComponentForAction(comp, INSTALLSTATE_ABSENT)) + else if (comp->ActionRequest == INSTALLSTATE_ABSENT) { if (package->Context == MSIINSTALLCONTEXT_MACHINE) MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid); @@ -2862,28 +2886,25 @@ static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param) HMODULE module; HRESULT hr; - static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0}; - component = MSI_RecordGetString(row,3); comp = get_loaded_component(package,component); if (!comp) return ERROR_SUCCESS; - if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL)) + if (comp->ActionRequest != INSTALLSTATE_LOCAL) { - TRACE("Skipping typelib reg due to disabled component\n"); - + TRACE("Component not scheduled for installation: %s\n", debugstr_w(component)); comp->Action = comp->Installed; - return ERROR_SUCCESS; } - comp->Action = INSTALLSTATE_LOCAL; file = get_loaded_file( package, comp->KeyPath ); if (!file) return ERROR_SUCCESS; + ui_actiondata( package, szRegisterTypeLibraries, row ); + module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE ); if (module) { @@ -2913,11 +2934,7 @@ static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param) ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path)); else - { - ui_actiondata(package,szRegisterTypeLibraries,row); - TRACE("Registered %s\n", debugstr_w(tl_struct.path)); - } ITypeLib_Release(tl_struct.ptLib); msi_free(tl_struct.path); @@ -2935,7 +2952,7 @@ static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param) if (FAILED(hr)) { ERR("Failed to load type library: %08x\n", hr); - return ERROR_FUNCTION_FAILED; + return ERROR_INSTALL_FAILURE; } ITypeLib_Release(tlib); @@ -2967,31 +2984,119 @@ static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package) return rc; } +static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param ) +{ + MSIPACKAGE *package = param; + LPCWSTR component, guid; + MSICOMPONENT *comp; + GUID libid; + UINT version; + LCID language; + SYSKIND syskind; + HRESULT hr; + + component = MSI_RecordGetString( row, 3 ); + comp = get_loaded_component( package, component ); + if (!comp) + return ERROR_SUCCESS; + + if (comp->ActionRequest != INSTALLSTATE_ABSENT) + { + TRACE("Component not scheduled for removal %s\n", debugstr_w(component)); + comp->Action = comp->Installed; + return ERROR_SUCCESS; + } + comp->Action = INSTALLSTATE_ABSENT; + + ui_actiondata( package, szUnregisterTypeLibraries, row ); + + guid = MSI_RecordGetString( row, 1 ); + CLSIDFromString( (LPWSTR)guid, &libid ); + version = MSI_RecordGetInteger( row, 4 ); + language = MSI_RecordGetInteger( row, 2 ); + +#ifdef _WIN64 + syskind = SYS_WIN64; +#else + syskind = SYS_WIN32; +#endif + + hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind ); + if (FAILED(hr)) + { + WARN("Failed to unregister typelib: %08x\n", hr); + } + + return ERROR_SUCCESS; +} + +static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package ) +{ + UINT rc; + MSIQUERY *view; + static const WCHAR query[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','T','y','p','e','L','i','b','`',0}; + + rc = MSI_DatabaseOpenViewW( package->db, query, &view ); + if (rc != ERROR_SUCCESS) + return ERROR_SUCCESS; + + rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package ); + msiobj_release( &view->hdr ); + return rc; +} + +static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row ) +{ + static const WCHAR szlnk[] = {'.','l','n','k',0}; + LPCWSTR directory, extension; + LPWSTR link_folder, link_file, filename; + + directory = MSI_RecordGetString( row, 2 ); + link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL ); + + /* may be needed because of a bug somewhere else */ + create_full_pathW( link_folder ); + + filename = msi_dup_record_field( row, 3 ); + reduce_to_longfilename( filename ); + + extension = strchrW( filename, '.' ); + if (!extension || strcmpiW( extension, szlnk )) + { + int len = strlenW( filename ); + filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) ); + memcpy( filename + len, szlnk, sizeof(szlnk) ); + } + link_file = build_directory_name( 2, link_folder, filename ); + msi_free( link_folder ); + msi_free( filename ); + + return link_file; +} + static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param) { MSIPACKAGE *package = param; - LPWSTR target_file, target_folder, filename; - LPCWSTR buffer, extension; + LPWSTR link_file, deformated, path; + LPCWSTR component, target; MSICOMPONENT *comp; - static const WCHAR szlnk[]={'.','l','n','k',0}; IShellLinkW *sl = NULL; IPersistFile *pf = NULL; HRESULT res; - buffer = MSI_RecordGetString(row,4); - comp = get_loaded_component(package,buffer); + component = MSI_RecordGetString(row, 4); + comp = get_loaded_component(package, component); if (!comp) return ERROR_SUCCESS; - if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL )) + if (comp->ActionRequest != INSTALLSTATE_LOCAL) { - TRACE("Skipping shortcut creation due to disabled component\n"); - + TRACE("Component not scheduled for installation %s\n", debugstr_w(component)); comp->Action = comp->Installed; - return ERROR_SUCCESS; } - comp->Action = INSTALLSTATE_LOCAL; ui_actiondata(package,szCreateShortcuts,row); @@ -3012,31 +3117,10 @@ static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param) goto err; } - buffer = MSI_RecordGetString(row,2); - target_folder = resolve_folder(package, buffer,FALSE,FALSE,TRUE,NULL); - - /* may be needed because of a bug somewhere else */ - create_full_pathW(target_folder); - - filename = msi_dup_record_field( row, 3 ); - reduce_to_longfilename(filename); - - extension = strchrW(filename,'.'); - if (!extension || strcmpiW(extension,szlnk)) + target = MSI_RecordGetString(row, 5); + if (strchrW(target, '[')) { - int len = strlenW(filename); - filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk)); - memcpy(filename + len, szlnk, sizeof(szlnk)); - } - target_file = build_directory_name(2, target_folder, filename); - msi_free(target_folder); - msi_free(filename); - - buffer = MSI_RecordGetString(row,5); - if (strchrW(buffer,'[')) - { - LPWSTR deformated; - deformat_string(package,buffer,&deformated); + deformat_string(package, target, &deformated); IShellLinkW_SetPath(sl,deformated); msi_free(deformated); } @@ -3048,17 +3132,16 @@ static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param) if (!MSI_RecordIsNull(row,6)) { - LPWSTR deformated; - buffer = MSI_RecordGetString(row,6); - deformat_string(package,buffer,&deformated); + LPCWSTR arguments = MSI_RecordGetString(row, 6); + deformat_string(package, arguments, &deformated); IShellLinkW_SetArguments(sl,deformated); msi_free(deformated); } if (!MSI_RecordIsNull(row,7)) { - buffer = MSI_RecordGetString(row,7); - IShellLinkW_SetDescription(sl,buffer); + LPCWSTR description = MSI_RecordGetString(row, 7); + IShellLinkW_SetDescription(sl, description); } if (!MSI_RecordIsNull(row,8)) @@ -3066,20 +3149,18 @@ static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param) if (!MSI_RecordIsNull(row,9)) { - LPWSTR Path; INT index; + LPCWSTR icon = MSI_RecordGetString(row, 9); - buffer = MSI_RecordGetString(row,9); - - Path = build_icon_path(package,buffer); + path = build_icon_path(package, icon); index = MSI_RecordGetInteger(row,10); /* no value means 0 */ if (index == MSI_NULL_INTEGER) index = 0; - IShellLinkW_SetIconLocation(sl,Path,index); - msi_free(Path); + IShellLinkW_SetIconLocation(sl, path, index); + msi_free(path); } if (!MSI_RecordIsNull(row,11)) @@ -3087,18 +3168,19 @@ static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param) if (!MSI_RecordIsNull(row,12)) { - LPWSTR Path; - buffer = MSI_RecordGetString(row,12); - Path = resolve_folder(package, buffer, FALSE, FALSE, TRUE, NULL); - if (Path) - IShellLinkW_SetWorkingDirectory(sl,Path); - msi_free(Path); + LPCWSTR wkdir = MSI_RecordGetString(row, 12); + path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL); + if (path) + IShellLinkW_SetWorkingDirectory(sl, path); + msi_free(path); } - TRACE("Writing shortcut to %s\n",debugstr_w(target_file)); - IPersistFile_Save(pf,target_file,FALSE); + link_file = get_link_file(package, row); - msi_free(target_file); + TRACE("Writing shortcut to %s\n", debugstr_w(link_file)); + IPersistFile_Save(pf, link_file, FALSE); + + msi_free(link_file); err: if (pf) @@ -3133,6 +3215,58 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package) return rc; } +static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param ) +{ + MSIPACKAGE *package = param; + LPWSTR link_file; + LPCWSTR component; + MSICOMPONENT *comp; + + component = MSI_RecordGetString( row, 4 ); + comp = get_loaded_component( package, component ); + if (!comp) + return ERROR_SUCCESS; + + if (comp->ActionRequest != INSTALLSTATE_ABSENT) + { + TRACE("Component not scheduled for removal %s\n", debugstr_w(component)); + comp->Action = comp->Installed; + return ERROR_SUCCESS; + } + comp->Action = INSTALLSTATE_ABSENT; + + ui_actiondata( package, szRemoveShortcuts, row ); + + link_file = get_link_file( package, row ); + + TRACE("Removing shortcut file %s\n", debugstr_w( link_file )); + if (!DeleteFileW( link_file )) + { + WARN("Failed to remove shortcut file %u\n", GetLastError()); + } + msi_free( link_file ); + + return ERROR_SUCCESS; +} + +static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package ) +{ + UINT rc; + MSIQUERY *view; + static const WCHAR query[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','S','h','o','r','t','c','u','t','`',0}; + + rc = MSI_DatabaseOpenViewW( package->db, query, &view ); + if (rc != ERROR_SUCCESS) + return ERROR_SUCCESS; + + rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package ); + msiobj_release( &view->hdr ); + + return rc; +} + static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param) { MSIPACKAGE* package = param; @@ -3510,17 +3644,15 @@ static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param) component = MSI_RecordGetString(row, 8); comp = get_loaded_component(package,component); + if (!comp) + return ERROR_SUCCESS; - if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL)) + if (comp->ActionRequest != INSTALLSTATE_LOCAL) { - TRACE("Skipping ini file due to disabled component %s\n", - debugstr_w(component)); - + TRACE("Component not scheduled for installation %s\n", debugstr_w(component)); comp->Action = comp->Installed; - return ERROR_SUCCESS; } - comp->Action = INSTALLSTATE_LOCAL; identifier = MSI_RecordGetString(row,1); @@ -3818,10 +3950,9 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package) BOOL absent = FALSE; MSIRECORD *uirow; - if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) && - !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) && - !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED )) - absent = TRUE; + if (feature->ActionRequest != INSTALLSTATE_LOCAL && + feature->ActionRequest != INSTALLSTATE_SOURCE && + feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE; size = 1; LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) @@ -4359,32 +4490,34 @@ static UINT ACTION_ExecuteAction(MSIPACKAGE *package) static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param) { MSIPACKAGE *package = param; - LPCWSTR compgroupid=NULL; - LPCWSTR feature=NULL; - LPCWSTR text = NULL; - LPCWSTR qualifier = NULL; - LPCWSTR component = NULL; - LPWSTR advertise = NULL; - LPWSTR output = NULL; + LPCWSTR compgroupid, component, feature, qualifier, text; + LPWSTR advertise = NULL, output = NULL; HKEY hkey; - UINT rc = ERROR_SUCCESS; + UINT rc; MSICOMPONENT *comp; - DWORD sz = 0; + MSIFEATURE *feat; + DWORD sz; MSIRECORD *uirow; - component = MSI_RecordGetString(rec,3); - comp = get_loaded_component(package,component); + feature = MSI_RecordGetString(rec, 5); + feat = get_loaded_feature(package, feature); + if (!feat) + return ERROR_SUCCESS; - if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) && - !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) && - !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED )) + if (feat->ActionRequest != INSTALLSTATE_LOCAL && + feat->ActionRequest != INSTALLSTATE_SOURCE && + feat->ActionRequest != INSTALLSTATE_ADVERTISED) { - TRACE("Skipping: Component %s not scheduled for install\n", - debugstr_w(component)); - + TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature)); + feat->Action = feat->Installed; return ERROR_SUCCESS; } + component = MSI_RecordGetString(rec, 3); + comp = get_loaded_component(package, component); + if (!comp) + return ERROR_SUCCESS; + compgroupid = MSI_RecordGetString(rec,1); qualifier = MSI_RecordGetString(rec,2); @@ -4393,8 +4526,6 @@ static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param) goto end; text = MSI_RecordGetString(rec,4); - feature = MSI_RecordGetString(rec,5); - advertise = create_component_advertise_string(package, comp, feature); sz = strlenW(advertise); @@ -4452,6 +4583,80 @@ static UINT ACTION_PublishComponents(MSIPACKAGE *package) return rc; } +static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param ) +{ + static const WCHAR szInstallerComponents[] = { + 'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\', + 'I','n','s','t','a','l','l','e','r','\\', + 'C','o','m','p','o','n','e','n','t','s','\\',0}; + + MSIPACKAGE *package = param; + LPCWSTR compgroupid, component, feature, qualifier; + MSICOMPONENT *comp; + MSIFEATURE *feat; + MSIRECORD *uirow; + WCHAR squashed[GUID_SIZE], keypath[MAX_PATH]; + LONG res; + + feature = MSI_RecordGetString( rec, 5 ); + feat = get_loaded_feature( package, feature ); + if (!feat) + return ERROR_SUCCESS; + + if (feat->ActionRequest != INSTALLSTATE_ABSENT) + { + TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature)); + feat->Action = feat->Installed; + return ERROR_SUCCESS; + } + + component = MSI_RecordGetString( rec, 3 ); + comp = get_loaded_component( package, component ); + if (!comp) + return ERROR_SUCCESS; + + compgroupid = MSI_RecordGetString( rec, 1 ); + qualifier = MSI_RecordGetString( rec, 2 ); + + squash_guid( compgroupid, squashed ); + strcpyW( keypath, szInstallerComponents ); + strcatW( keypath, squashed ); + + res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath ); + if (res != ERROR_SUCCESS) + { + WARN("Unable to delete component key %d\n", res); + } + + uirow = MSI_CreateRecord( 2 ); + MSI_RecordSetStringW( uirow, 1, compgroupid ); + MSI_RecordSetStringW( uirow, 2, qualifier ); + ui_actiondata( package, szUnpublishComponents, uirow ); + msiobj_release( &uirow->hdr ); + + return ERROR_SUCCESS; +} + +static UINT ACTION_UnpublishComponents( MSIPACKAGE *package ) +{ + UINT rc; + MSIQUERY *view; + static const WCHAR query[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','P','u','b','l','i','s','h', + 'C','o','m','p','o','n','e','n','t','`',0}; + + rc = MSI_DatabaseOpenViewW( package->db, query, &view ); + if (rc != ERROR_SUCCESS) + return ERROR_SUCCESS; + + rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package ); + msiobj_release( &view->hdr ); + + return rc; +} + static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param) { MSIPACKAGE *package = param; @@ -4597,7 +4802,7 @@ static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param) { MSIPACKAGE *package = param; MSICOMPONENT *comp; - SC_HANDLE scm, service = NULL; + SC_HANDLE scm = NULL, service = NULL; LPCWSTR *vector = NULL; LPWSTR name, args; DWORD event, numargs; @@ -4612,7 +4817,10 @@ static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param) event = MSI_RecordGetInteger(rec, 3); if (!(event & msidbServiceControlEventStart)) - return ERROR_SUCCESS; + { + r = ERROR_SUCCESS; + goto done; + } scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); if (!scm) @@ -4893,15 +5101,17 @@ static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param ) driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4)); setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5)); - if (!driver_file || !setup_file) + if (!driver_file) { ERR("ODBC Driver entry not found!\n"); return ERROR_FUNCTION_FAILED; } - len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) + - lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + - lstrlenW(usage_fmt) + 1; + len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName); + if (setup_file) + len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName); + len += lstrlenW(usage_fmt) + 1; + driver = msi_alloc(len * sizeof(WCHAR)); if (!driver) return ERROR_OUTOFMEMORY; @@ -4913,8 +5123,11 @@ static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param ) sprintfW(ptr, driver_fmt, driver_file->FileName); ptr += lstrlenW(ptr) + 1; - sprintfW(ptr, setup_fmt, setup_file->FileName); - ptr += lstrlenW(ptr) + 1; + if (setup_file) + { + sprintfW(ptr, setup_fmt, setup_file->FileName); + ptr += lstrlenW(ptr) + 1; + } lstrcpyW(ptr, usage_fmt); ptr += lstrlenW(ptr) + 1; @@ -4957,14 +5170,16 @@ static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param ) translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4)); setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5)); - if (!translator_file || !setup_file) + if (!translator_file) { ERR("ODBC Translator entry not found!\n"); return ERROR_FUNCTION_FAILED; } - len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + - lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + 1; + len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 1; + if (setup_file) + len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName); + translator = msi_alloc(len * sizeof(WCHAR)); if (!translator) return ERROR_OUTOFMEMORY; @@ -4976,8 +5191,11 @@ static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param ) sprintfW(ptr, translator_fmt, translator_file->FileName); ptr += lstrlenW(ptr) + 1; - sprintfW(ptr, setup_fmt, setup_file->FileName); - ptr += lstrlenW(ptr) + 1; + if (setup_file) + { + sprintfW(ptr, setup_fmt, setup_file->FileName); + ptr += lstrlenW(ptr) + 1; + } *ptr = '\0'; translator_path = strdupW(translator_file->TargetPath); @@ -5021,8 +5239,8 @@ static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param ) if (!attrs) return ERROR_OUTOFMEMORY; - sprintfW(attrs, attrs_fmt, desc); - attrs[len - 1] = '\0'; + len = sprintfW(attrs, attrs_fmt, desc); + attrs[len + 1] = 0; if (!SQLConfigDataSourceW(NULL, request, driver, attrs)) { @@ -5076,6 +5294,120 @@ static UINT ACTION_InstallODBC( MSIPACKAGE *package ) return rc; } +static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param ) +{ + DWORD usage; + LPCWSTR desc; + + desc = MSI_RecordGetString( rec, 3 ); + if (!SQLRemoveDriverW( desc, FALSE, &usage )) + { + WARN("Failed to remove ODBC driver\n"); + } + else if (!usage) + { + FIXME("Usage count reached 0\n"); + } + + return ERROR_SUCCESS; +} + +static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param ) +{ + DWORD usage; + LPCWSTR desc; + + desc = MSI_RecordGetString( rec, 3 ); + if (!SQLRemoveTranslatorW( desc, &usage )) + { + WARN("Failed to remove ODBC translator\n"); + } + else if (!usage) + { + FIXME("Usage count reached 0\n"); + } + + return ERROR_SUCCESS; +} + +static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param ) +{ + LPWSTR attrs; + LPCWSTR desc, driver; + WORD request = ODBC_REMOVE_SYS_DSN; + INT registration; + DWORD len; + + static const WCHAR attrs_fmt[] = { + 'D','S','N','=','%','s',0 }; + + desc = MSI_RecordGetString( rec, 3 ); + driver = MSI_RecordGetString( rec, 4 ); + registration = MSI_RecordGetInteger( rec, 5 ); + + if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN; + else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN; + + len = strlenW( attrs_fmt ) + strlenW( desc ) + 1 + 1; + attrs = msi_alloc( len * sizeof(WCHAR) ); + if (!attrs) + return ERROR_OUTOFMEMORY; + + FIXME("Use ODBCSourceAttribute table\n"); + + len = sprintfW( attrs, attrs_fmt, desc ); + attrs[len + 1] = 0; + + if (!SQLConfigDataSourceW( NULL, request, driver, attrs )) + { + WARN("Failed to remove ODBC data source\n"); + } + msi_free( attrs ); + + return ERROR_SUCCESS; +} + +static UINT ACTION_RemoveODBC( MSIPACKAGE *package ) +{ + UINT rc; + MSIQUERY *view; + + static const WCHAR driver_query[] = { + 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + 'O','D','B','C','D','r','i','v','e','r',0 }; + + static const WCHAR translator_query[] = { + 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 }; + + static const WCHAR source_query[] = { + 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 }; + + rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view ); + if (rc != ERROR_SUCCESS) + return ERROR_SUCCESS; + + rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package ); + msiobj_release( &view->hdr ); + + rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view ); + if (rc != ERROR_SUCCESS) + return ERROR_SUCCESS; + + rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package ); + msiobj_release( &view->hdr ); + + rc = MSI_DatabaseOpenViewW( package->db, source_query, &view ); + if (rc != ERROR_SUCCESS) + return ERROR_SUCCESS; + + rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package ); + msiobj_release( &view->hdr ); + + return rc; +} + #define ENV_ACT_SETALWAYS 0x1 #define ENV_ACT_SETABSENT 0x2 #define ENV_ACT_REMOVE 0x4 @@ -6125,6 +6457,30 @@ done: return r; } +static UINT ACTION_ValidateProductID( MSIPACKAGE *package ) +{ + LPWSTR key, template, id; + UINT r = ERROR_SUCCESS; + + id = msi_dup_property( package, szProductID ); + if (id) + { + msi_free( id ); + return ERROR_SUCCESS; + } + template = msi_dup_property( package, szPIDTemplate ); + key = msi_dup_property( package, szPIDKEY ); + + if (key && template) + { + FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) ); + r = MSI_SetPropertyW( package, szProductID, key ); + } + msi_free( template ); + msi_free( key ); + return r; +} + static UINT ACTION_ScheduleReboot( MSIPACKAGE *package ) { TRACE("\n"); @@ -6132,6 +6488,24 @@ static UINT ACTION_ScheduleReboot( MSIPACKAGE *package ) return ERROR_SUCCESS; } +static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package ) +{ + TRACE("%p\n", package); + return ERROR_SUCCESS; +} + +static UINT ACTION_DisableRollback( MSIPACKAGE *package ) +{ + FIXME("%p\n", package); + return ERROR_SUCCESS; +} + +static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package ) +{ + FIXME("%p\n", package); + return ERROR_SUCCESS; +} + static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table ) { @@ -6156,12 +6530,6 @@ static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, return ERROR_SUCCESS; } -static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package ) -{ - TRACE("%p\n", package); - return ERROR_SUCCESS; -} - static UINT ACTION_RemoveIniValues( MSIPACKAGE *package ) { static const WCHAR table[] = @@ -6194,13 +6562,6 @@ static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package ) return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table ); } -static UINT ACTION_ValidateProductID( MSIPACKAGE *package ) -{ - static const WCHAR table[] = { - 'P','r','o','d','u','c','t','I','D',0 }; - return msi_unimplemented_action_stub( package, "ValidateProductID", table ); -} - static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package ) { static const WCHAR table[] = { @@ -6215,12 +6576,6 @@ static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package ) return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table ); } -static UINT ACTION_UnregisterFonts( MSIPACKAGE *package ) -{ - static const WCHAR table[] = { 'F','o','n','t',0 }; - return msi_unimplemented_action_stub( package, "UnregisterFonts", table ); -} - static UINT ACTION_RMCCPSearch( MSIPACKAGE *package ) { static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 }; @@ -6257,36 +6612,18 @@ static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package ) return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table ); } -static UINT ACTION_RemoveODBC( MSIPACKAGE *package ) -{ - static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 }; - return msi_unimplemented_action_stub( package, "RemoveODBC", table ); -} - static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package ) { static const WCHAR table[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 }; return msi_unimplemented_action_stub( package, "RemoveRegistryValues", table ); } -static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package ) -{ - static const WCHAR table[] = { 'S','h','o','r','t','c','u','t',0 }; - return msi_unimplemented_action_stub( package, "RemoveShortcuts", table ); -} - static UINT ACTION_SetODBCFolders( MSIPACKAGE *package ) { static const WCHAR table[] = { 'D','i','r','e','c','t','o','r','y',0 }; return msi_unimplemented_action_stub( package, "SetODBCFolders", table ); } -static UINT ACTION_UnpublishComponents( MSIPACKAGE *package ) -{ - static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 }; - return msi_unimplemented_action_stub( package, "UnpublishComponents", table ); -} - static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package ) { static const WCHAR table[] = { 'A','p','p','I','d',0 }; @@ -6311,12 +6648,6 @@ static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package ) return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table ); } -static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package ) -{ - static const WCHAR table[] = { 'T','y','p','e','L','i','b',0 }; - return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table ); -} - typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*); static const struct @@ -6335,13 +6666,13 @@ StandardActions[] = { szCreateFolders, ACTION_CreateFolders }, { szCreateShortcuts, ACTION_CreateShortcuts }, { szDeleteServices, ACTION_DeleteServices }, - { szDisableRollback, NULL }, + { szDisableRollback, ACTION_DisableRollback }, { szDuplicateFiles, ACTION_DuplicateFiles }, { szExecuteAction, ACTION_ExecuteAction }, { szFileCost, ACTION_FileCost }, { szFindRelatedProducts, ACTION_FindRelatedProducts }, { szForceReboot, ACTION_ForceReboot }, - { szInstallAdminPackage, NULL }, + { szInstallAdminPackage, ACTION_InstallAdminPackage }, { szInstallExecute, ACTION_InstallExecute }, { szInstallExecuteAgain, ACTION_InstallExecute }, { szInstallFiles, ACTION_InstallFiles}, diff --git a/reactos/dll/win32/msi/classes.c b/reactos/dll/win32/msi/classes.c index 6ca35b9735a..acd8429bec4 100644 --- a/reactos/dll/win32/msi/classes.c +++ b/reactos/dll/win32/msi/classes.c @@ -809,16 +809,17 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package) continue; feature = cls->Feature; + if (!feature) + continue; /* * MSDN says that these are based on Feature not on Component. */ - if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) && - !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED )) + if (feature->ActionRequest != INSTALLSTATE_LOCAL && + feature->ActionRequest != INSTALLSTATE_ADVERTISED ) { - TRACE("Skipping class %s reg due to disabled feature %s\n", - debugstr_w(cls->clsid), debugstr_w(feature->Feature)); - + TRACE("Feature %s not scheduled for installation, skipping regstration of class %s\n", + debugstr_w(feature->Feature), debugstr_w(cls->clsid)); continue; } @@ -1142,18 +1143,18 @@ UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package) continue; feature = ext->Feature; + if (!feature) + continue; /* * yes. MSDN says that these are based on _Feature_ not on * Component. So verify the feature is to be installed */ - if ((!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL )) && - !(install_on_demand && - ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))) + if (feature->ActionRequest != INSTALLSTATE_LOCAL && + !(install_on_demand && feature->ActionRequest == INSTALLSTATE_ADVERTISED)) { - TRACE("Skipping extension %s reg due to disabled feature %s\n", - debugstr_w(ext->Extension), debugstr_w(feature->Feature)); - + TRACE("Feature %s not scheduled for installation, skipping registration of extension %s\n", + debugstr_w(feature->Feature), debugstr_w(ext->Extension)); continue; } diff --git a/reactos/dll/win32/msi/database.c b/reactos/dll/win32/msi/database.c index 7855fea9186..8ec2411cb59 100644 --- a/reactos/dll/win32/msi/database.c +++ b/reactos/dll/win32/msi/database.c @@ -125,20 +125,14 @@ static UINT clone_open_stream( MSIDATABASE *db, LPCWSTR name, IStream **stm ) UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm ) { - LPWSTR encname; HRESULT r; - encname = encode_streamname(FALSE, stname); + TRACE("%s\n", debugstr_w(stname)); - TRACE("%s -> %s\n",debugstr_w(stname),debugstr_w(encname)); - - if (clone_open_stream( db, encname, stm ) == ERROR_SUCCESS) - { - msi_free( encname ); + if (clone_open_stream( db, stname, stm ) == ERROR_SUCCESS) return ERROR_SUCCESS; - } - r = IStorage_OpenStream( db->storage, encname, NULL, + r = IStorage_OpenStream( db->storage, stname, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm ); if( FAILED( r ) ) { @@ -147,15 +141,13 @@ UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm ) LIST_FOR_EACH_ENTRY( transform, &db->transforms, MSITRANSFORM, entry ) { TRACE("looking for %s in transform storage\n", debugstr_w(stname) ); - r = IStorage_OpenStream( transform->stg, encname, NULL, + r = IStorage_OpenStream( transform->stg, stname, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm ); if (SUCCEEDED(r)) break; } } - msi_free( encname ); - if( SUCCEEDED(r) ) { MSISTREAM *stream; @@ -181,10 +173,15 @@ UINT read_raw_stream_data( MSIDATABASE *db, LPCWSTR stname, ULONG sz, count; IStream *stm = NULL; STATSTG stat; + LPWSTR encname; + + encname = encode_streamname( FALSE, stname ); + r = db_get_raw_stream( db, encname, &stm ); + msi_free( encname ); - r = db_get_raw_stream( db, stname, &stm ); if( r != ERROR_SUCCESS) return ret; + r = IStream_Stat(stm, &stat, STATFLAG_NONAME ); if( FAILED( r ) ) { @@ -225,16 +222,6 @@ end: return ret; } -void append_storage_to_db( MSIDATABASE *db, IStorage *stg ) -{ - MSITRANSFORM *t; - - t = msi_alloc( sizeof *t ); - t->stg = stg; - IStorage_AddRef( stg ); - list_add_tail( &db->transforms, &t->entry ); -} - static void free_transforms( MSIDATABASE *db ) { while( !list_empty( &db->transforms ) ) @@ -259,6 +246,19 @@ static void free_streams( MSIDATABASE *db ) } } +void append_storage_to_db( MSIDATABASE *db, IStorage *stg ) +{ + MSITRANSFORM *t; + + t = msi_alloc( sizeof *t ); + t->stg = stg; + IStorage_AddRef( stg ); + list_add_tail( &db->transforms, &t->entry ); + + /* the transform may add or replace streams */ + free_streams( db ); +} + static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg ) { MSIDATABASE *db = (MSIDATABASE *) arg; diff --git a/reactos/dll/win32/msi/events.c b/reactos/dll/win32/msi/events.c index f4697dd0a34..e8f22975594 100644 --- a/reactos/dll/win32/msi/events.c +++ b/reactos/dll/win32/msi/events.c @@ -386,9 +386,6 @@ static UINT ControlEvent_ReinstallMode(MSIPACKAGE *package, LPCWSTR argument, static UINT ControlEvent_ValidateProductID(MSIPACKAGE *package, LPCWSTR argument, msi_dialog *dialog) { - static const WCHAR szProductID[] = {'P','r','o','d','u','c','t','I','D',0}; - static const WCHAR szPIDTemplate[] = {'P','I','D','T','e','m','p','l','a','t','e',0}; - static const WCHAR szPIDKEY[] = {'P','I','D','K','E','Y',0}; LPWSTR key, template; UINT ret = ERROR_SUCCESS; diff --git a/reactos/dll/win32/msi/files.c b/reactos/dll/win32/msi/files.c index b7af4d39416..d64195020aa 100644 --- a/reactos/dll/win32/msi/files.c +++ b/reactos/dll/win32/msi/files.c @@ -108,7 +108,7 @@ static void schedule_install_files(MSIPACKAGE *package) LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry) { - if (!ACTION_VerifyComponentForAction(file->Component, INSTALLSTATE_LOCAL)) + if (file->Component->ActionRequest != INSTALLSTATE_LOCAL) { TRACE("File %s is not scheduled for install\n", debugstr_w(file->File)); @@ -358,19 +358,15 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param) component = MSI_RecordGetString(row,2); comp = get_loaded_component(package,component); + if (!comp) + return ERROR_SUCCESS; - if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL )) + if (comp->ActionRequest != INSTALLSTATE_LOCAL) { - TRACE("Skipping copy due to disabled component %s\n", - debugstr_w(component)); - - /* the action taken was the same as the current install state */ - if (comp) - comp->Action = comp->Installed; - + TRACE("Component not scheduled for installation %s\n", debugstr_w(component)); + comp->Action = comp->Installed; return ERROR_SUCCESS; } - comp->Action = INSTALLSTATE_LOCAL; file_key = MSI_RecordGetString(row,3); diff --git a/reactos/dll/win32/msi/font.c b/reactos/dll/win32/msi/font.c index 085d400a7b9..1b2c3c729dd 100644 --- a/reactos/dll/win32/msi/font.c +++ b/reactos/dll/win32/msi/font.c @@ -66,6 +66,21 @@ typedef struct _tagTT_NAME_RECORD { static const WCHAR szRegisterFonts[] = {'R','e','g','i','s','t','e','r','F','o','n','t','s',0}; +static const WCHAR szUnregisterFonts[] = + {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0}; + +static const WCHAR regfont1[] = + {'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\', + 'W','i','n','d','o','w','s',' ','N','T','\\', + 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', + 'F','o','n','t','s',0}; +static const WCHAR regfont2[] = + {'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\', + 'W','i','n','d','o','w','s','\\', + 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', + 'F','o','n','t','s',0}; /* * Code based off of code located here @@ -174,20 +189,7 @@ static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param) LPWSTR name; LPCWSTR filename; MSIFILE *file; - static const WCHAR regfont1[] = - {'S','o','f','t','w','a','r','e','\\', - 'M','i','c','r','o','s','o','f','t','\\', - 'W','i','n','d','o','w','s',' ','N','T','\\', - 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', - 'F','o','n','t','s',0}; - static const WCHAR regfont2[] = - {'S','o','f','t','w','a','r','e','\\', - 'M','i','c','r','o','s','o','f','t','\\', - 'W','i','n','d','o','w','s','\\', - 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', - 'F','o','n','t','s',0}; - HKEY hkey1; - HKEY hkey2; + HKEY hkey1, hkey2; MSIRECORD *uirow; LPWSTR uipath, p; @@ -199,10 +201,9 @@ static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param) return ERROR_SUCCESS; } - /* check to make sure that component is installed */ - if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL)) + if (file->Component->ActionRequest != INSTALLSTATE_LOCAL) { - TRACE("Skipping: Component not scheduled for install\n"); + TRACE("Component not scheduled for installation\n"); return ERROR_SUCCESS; } @@ -259,3 +260,81 @@ UINT ACTION_RegisterFonts(MSIPACKAGE *package) return ERROR_SUCCESS; } + +static UINT ITERATE_UnregisterFonts( MSIRECORD *row, LPVOID param ) +{ + MSIPACKAGE *package = param; + LPWSTR name; + LPCWSTR filename; + MSIFILE *file; + HKEY hkey1, hkey2; + MSIRECORD *uirow; + LPWSTR uipath, p; + + filename = MSI_RecordGetString( row, 1 ); + file = get_loaded_file( package, filename ); + if (!file) + { + ERR("Unable to load file\n"); + return ERROR_SUCCESS; + } + + if (file->Component->ActionRequest != INSTALLSTATE_ABSENT) + { + TRACE("Component not scheduled for removal\n"); + return ERROR_SUCCESS; + } + + RegCreateKeyW( HKEY_LOCAL_MACHINE, regfont1, &hkey1 ); + RegCreateKeyW( HKEY_LOCAL_MACHINE, regfont2, &hkey2 ); + + if (MSI_RecordIsNull( row, 2 )) + name = load_ttfname_from( file->TargetPath ); + else + name = msi_dup_record_field( row, 2 ); + + if (name) + { + RegDeleteValueW( hkey1, name ); + RegDeleteValueW( hkey2, name ); + } + + msi_free( name ); + RegCloseKey( hkey1 ); + RegCloseKey( hkey2 ); + + /* the UI chunk */ + uirow = MSI_CreateRecord( 1 ); + uipath = strdupW( file->TargetPath ); + p = strrchrW( uipath,'\\' ); + if (p) p++; + else p = uipath; + MSI_RecordSetStringW( uirow, 1, p ); + ui_actiondata( package, szUnregisterFonts, uirow ); + msiobj_release( &uirow->hdr ); + msi_free( uipath ); + /* FIXME: call ui_progress? */ + + return ERROR_SUCCESS; +} + +UINT ACTION_UnregisterFonts( MSIPACKAGE *package ) +{ + UINT r; + MSIQUERY *view; + static const WCHAR query[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','F','o','n','t','`',0}; + + r = MSI_DatabaseOpenViewW( package->db, query, &view ); + if (r != ERROR_SUCCESS) + { + TRACE("MSI_DatabaseOpenViewW failed: %u\n", r); + return ERROR_SUCCESS; + } + + MSI_IterateRecords( view, NULL, ITERATE_UnregisterFonts, package ); + msiobj_release( &view->hdr ); + + return ERROR_SUCCESS; +} diff --git a/reactos/dll/win32/msi/helpers.c b/reactos/dll/win32/msi/helpers.c index e3009f7bce7..e763a113073 100644 --- a/reactos/dll/win32/msi/helpers.c +++ b/reactos/dll/win32/msi/helpers.c @@ -604,28 +604,6 @@ void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record) msiobj_release(&row->hdr); } -BOOL ACTION_VerifyComponentForAction( const MSICOMPONENT* comp, INSTALLSTATE check ) -{ - if (!comp) - return FALSE; - - if (comp->ActionRequest == check) - return TRUE; - else - return FALSE; -} - -BOOL ACTION_VerifyFeatureForAction( const MSIFEATURE* feature, INSTALLSTATE check ) -{ - if (!feature) - return FALSE; - - if (feature->ActionRequest == check) - return TRUE; - else - return FALSE; -} - void reduce_to_longfilename(WCHAR* filename) { LPWSTR p = strchrW(filename,'|'); diff --git a/reactos/dll/win32/msi/install.c b/reactos/dll/win32/msi/install.c index b1d741a1625..c23075d61d3 100644 --- a/reactos/dll/win32/msi/install.c +++ b/reactos/dll/win32/msi/install.c @@ -661,6 +661,8 @@ BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode) MSIPACKAGE *package; BOOL r = FALSE; + TRACE("%d %d\n", hInstall, iRunMode); + package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); if (!package) { @@ -706,8 +708,16 @@ BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode) r = package->commit_action_running; break; + case MSIRUNMODE_MAINTENANCE: + r = msi_get_property_int( package, szInstalled, 0 ) != 0; + break; + + case MSIRUNMODE_REBOOTATEND: + r = package->need_reboot; + break; + default: - FIXME("%d %d\n", hInstall, iRunMode); + FIXME("unimplemented run mode: %d\n", iRunMode); r = TRUE; } @@ -719,8 +729,52 @@ BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode) */ UINT WINAPI MsiSetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode, BOOL fState) { - FIXME("%d %d %d\n", hInstall, iRunMode, fState); - return ERROR_SUCCESS; + MSIPACKAGE *package; + UINT r; + + TRACE("%d %d %d\n", hInstall, iRunMode, fState); + + package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE ); + if (!package) + { + HRESULT hr; + IWineMsiRemotePackage *remote_package; + + remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall ); + if (!remote_package) + return FALSE; + + hr = IWineMsiRemotePackage_SetMode( remote_package, iRunMode, fState ); + IWineMsiRemotePackage_Release( remote_package ); + + if (FAILED(hr)) + { + if (HRESULT_FACILITY(hr) == FACILITY_WIN32) + return HRESULT_CODE(hr); + + return ERROR_FUNCTION_FAILED; + } + + return ERROR_SUCCESS; + } + + switch (iRunMode) + { + case MSIRUNMODE_REBOOTATEND: + package->need_reboot = 1; + r = ERROR_SUCCESS; + break; + + case MSIRUNMODE_REBOOTNOW: + FIXME("unimplemented run mode: %d\n", iRunMode); + r = ERROR_FUNCTION_FAILED; + break; + + default: + r = ERROR_ACCESS_DENIED; + } + + return r; } /*********************************************************************** diff --git a/reactos/dll/win32/msi/msi.c b/reactos/dll/win32/msi/msi.c index 4d9da4cd68f..07356405718 100644 --- a/reactos/dll/win32/msi/msi.c +++ b/reactos/dll/win32/msi/msi.c @@ -1613,6 +1613,93 @@ done: return r; } +UINT WINAPI MsiGetPatchInfoA( LPCSTR patch, LPCSTR attr, LPSTR buffer, LPDWORD buflen ) +{ + UINT r = ERROR_OUTOFMEMORY; + DWORD size; + LPWSTR patchW = NULL, attrW = NULL, bufferW = NULL; + + TRACE("%s %s %p %p\n", debugstr_a(patch), debugstr_a(attr), buffer, buflen); + + if (!patch || !attr) + return ERROR_INVALID_PARAMETER; + + if (!(patchW = strdupAtoW( patch ))) + goto done; + + if (!(attrW = strdupAtoW( attr ))) + goto done; + + size = 0; + r = MsiGetPatchInfoW( patchW, attrW, NULL, &size ); + if (r != ERROR_SUCCESS) + goto done; + + size++; + if (!(bufferW = msi_alloc( size * sizeof(WCHAR) ))) + { + r = ERROR_OUTOFMEMORY; + goto done; + } + + r = MsiGetPatchInfoW( patchW, attrW, bufferW, &size ); + if (r == ERROR_SUCCESS) + { + int len = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL ); + if (len > *buflen) + r = ERROR_MORE_DATA; + else if (buffer) + WideCharToMultiByte( CP_ACP, 0, bufferW, -1, buffer, *buflen, NULL, NULL ); + + *buflen = len - 1; + } + +done: + msi_free( patchW ); + msi_free( attrW ); + msi_free( bufferW ); + return r; +} + +UINT WINAPI MsiGetPatchInfoW( LPCWSTR patch, LPCWSTR attr, LPWSTR buffer, LPDWORD buflen ) +{ + UINT r; + WCHAR product[GUID_SIZE]; + DWORD index; + + TRACE("%s %s %p %p\n", debugstr_w(patch), debugstr_w(attr), buffer, buflen); + + if (!patch || !attr) + return ERROR_INVALID_PARAMETER; + + if (strcmpW( INSTALLPROPERTY_LOCALPACKAGEW, attr )) + return ERROR_UNKNOWN_PROPERTY; + + index = 0; + while (1) + { + r = MsiEnumProductsW( index, product ); + if (r != ERROR_SUCCESS) + break; + + r = MsiGetPatchInfoExW( patch, product, NULL, MSIINSTALLCONTEXT_USERMANAGED, attr, buffer, buflen ); + if (r == ERROR_SUCCESS || r == ERROR_MORE_DATA) + return r; + + r = MsiGetPatchInfoExW( patch, product, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, attr, buffer, buflen ); + if (r == ERROR_SUCCESS || r == ERROR_MORE_DATA) + return r; + + r = MsiGetPatchInfoExW( patch, product, NULL, MSIINSTALLCONTEXT_MACHINE, attr, buffer, buflen ); + if (r == ERROR_SUCCESS || r == ERROR_MORE_DATA) + return r; + + index++; + } + + return ERROR_UNKNOWN_PRODUCT; +} + UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes) { LPWSTR szwLogFile = NULL; diff --git a/reactos/dll/win32/msi/msi.spec b/reactos/dll/win32/msi/msi.spec index 147502811be..30daec931a6 100644 --- a/reactos/dll/win32/msi/msi.spec +++ b/reactos/dll/win32/msi/msi.spec @@ -171,8 +171,8 @@ 175 stdcall MsiApplyPatchW(wstr wstr long wstr) 176 stdcall MsiAdvertiseScriptA(str long ptr long) 177 stdcall MsiAdvertiseScriptW(wstr long ptr long) -178 stub MsiGetPatchInfoA -179 stub MsiGetPatchInfoW +178 stdcall MsiGetPatchInfoA(str str ptr ptr) +179 stdcall MsiGetPatchInfoW(wstr wstr ptr ptr) 180 stdcall MsiEnumPatchesA(str long ptr ptr ptr) 181 stdcall MsiEnumPatchesW(str long ptr ptr ptr) 182 stdcall -private DllGetVersion(ptr) diff --git a/reactos/dll/win32/msi/msi_It.rc b/reactos/dll/win32/msi/msi_It.rc index 9864806fd80..11525add056 100644 --- a/reactos/dll/win32/msi/msi_It.rc +++ b/reactos/dll/win32/msi/msi_It.rc @@ -20,17 +20,21 @@ #include "windef.h" +/*UTF-8*/ +#pragma code_page(65001) + LANGUAGE LANG_ITALIAN, SUBLANG_NEUTRAL STRINGTABLE DISCARDABLE { - 4 "The specified installation package could not be opened. Please check the file path and try again." + 4 "Impossibile aprire il pacchetto di installazione specificato. Per favore controlla l'indirizzo del file e riprova." 5 "percorso %s non trovato" 9 "inserire disco %s" 10 "parametri incorretti" 11 "immettere il nome della cartella che contiene %s" - 12 "sorgente di installazione per la funzionalità mancante" - 13 "periferica di rete per la funzionalità mancante" - 14 "funzionalità da:" + 12 "sorgente di installazione per la funzionalità mancante" + 13 "periferica di rete per la funzionalità mancante" + 14 "funzionalità da:" 15 "selezionare la cartella che contiene %s" } +#pragma code_page(default) diff --git a/reactos/dll/win32/msi/msipriv.h b/reactos/dll/win32/msi/msipriv.h index 43486e0a830..2278ff7c2c8 100644 --- a/reactos/dll/win32/msi/msipriv.h +++ b/reactos/dll/win32/msi/msipriv.h @@ -961,6 +961,7 @@ extern UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package); extern UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package); extern UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package); extern UINT ACTION_RegisterFonts(MSIPACKAGE *package); +extern UINT ACTION_UnregisterFonts(MSIPACKAGE *package); /* Helpers */ extern DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data ); @@ -981,8 +982,6 @@ extern void msi_free_action_script(MSIPACKAGE *package, UINT script); extern LPWSTR build_icon_path(MSIPACKAGE *, LPCWSTR); extern LPWSTR build_directory_name(DWORD , ...); extern BOOL create_full_pathW(const WCHAR *path); -extern BOOL ACTION_VerifyComponentForAction(const MSICOMPONENT*, INSTALLSTATE); -extern BOOL ACTION_VerifyFeatureForAction(const MSIFEATURE*, INSTALLSTATE); extern void reduce_to_longfilename(WCHAR*); extern LPWSTR create_component_advertise_string(MSIPACKAGE*, MSICOMPONENT*, LPCWSTR); extern void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature); @@ -1071,6 +1070,11 @@ static const WCHAR szFindRelatedProducts[] = {'F','i','n','d','R','e','l','a','t static const WCHAR szAllUsers[] = {'A','L','L','U','S','E','R','S',0}; static const WCHAR szCustomActionData[] = {'C','u','s','t','o','m','A','c','t','i','o','n','D','a','t','a',0}; static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0}; +static const WCHAR szProductID[] = {'P','r','o','d','u','c','t','I','D',0}; +static const WCHAR szPIDTemplate[] = {'P','I','D','T','e','m','p','l','a','t','e',0}; +static const WCHAR szPIDKEY[] = {'P','I','D','K','E','Y',0}; +static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0}; +static const WCHAR szSumInfo[] = {5 ,'S','u','m','m','a','r','y','I','n','f','o','r','m','a','t','i','o','n',0}; /* memory allocation macro functions */ static void *msi_alloc( size_t len ) __WINE_ALLOC_SIZE(1); diff --git a/reactos/dll/win32/msi/msiserver.idl b/reactos/dll/win32/msi/msiserver.idl index a8146957b06..aa934361b49 100644 --- a/reactos/dll/win32/msi/msiserver.idl +++ b/reactos/dll/win32/msi/msiserver.idl @@ -64,6 +64,7 @@ interface IWineMsiRemotePackage : IUnknown HRESULT SetTargetPath( [in] BSTR folder, [in] BSTR value ); HRESULT GetSourcePath( [in] BSTR folder, [out] BSTR *value, [out] DWORD *size ); HRESULT GetMode( [in] MSIRUNMODE mode, [out] BOOL *ret ); + HRESULT SetMode( [in] MSIRUNMODE mode, [in] BOOL state ); HRESULT GetFeatureState( [in] BSTR feature, [out] INSTALLSTATE *installed, [out] INSTALLSTATE *action ); HRESULT SetFeatureState( [in] BSTR feature, [in] INSTALLSTATE state ); HRESULT GetComponentState( [in] BSTR component, [out] INSTALLSTATE *installed, [out] INSTALLSTATE *action ); diff --git a/reactos/dll/win32/msi/package.c b/reactos/dll/win32/msi/package.c index 53804e22e56..ad6d4c65830 100644 --- a/reactos/dll/win32/msi/package.c +++ b/reactos/dll/win32/msi/package.c @@ -2104,6 +2104,13 @@ static HRESULT WINAPI mrp_GetMode( IWineMsiRemotePackage *iface, MSIRUNMODE mode return S_OK; } +static HRESULT WINAPI mrp_SetMode( IWineMsiRemotePackage *iface, MSIRUNMODE mode, BOOL state ) +{ + msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface ); + UINT r = MsiSetMode(This->package, mode, state); + return HRESULT_FROM_WIN32(r); +} + static HRESULT WINAPI mrp_GetFeatureState( IWineMsiRemotePackage *iface, BSTR feature, INSTALLSTATE *installed, INSTALLSTATE *action ) { @@ -2196,6 +2203,7 @@ static const IWineMsiRemotePackageVtbl msi_remote_package_vtbl = mrp_SetTargetPath, mrp_GetSourcePath, mrp_GetMode, + mrp_SetMode, mrp_GetFeatureState, mrp_SetFeatureState, mrp_GetComponentState, diff --git a/reactos/dll/win32/msi/streams.c b/reactos/dll/win32/msi/streams.c index 8d2e748e64d..8ec2ad9accb 100644 --- a/reactos/dll/win32/msi/streams.c +++ b/reactos/dll/win32/msi/streams.c @@ -32,6 +32,7 @@ #include "query.h" #include "wine/debug.h" +#include "wine/unicode.h" WINE_DEFAULT_DEBUG_CHANNEL(msidb); @@ -486,7 +487,8 @@ static INT add_streams_to_table(MSISTREAMSVIEW *sv) STATSTG stat; STREAM *stream = NULL; HRESULT hr; - UINT count = 0, size; + UINT r, count = 0, size; + LPWSTR encname; hr = IStorage_EnumElements(sv->db->storage, 0, NULL, 0, &stgenum); if (FAILED(hr)) @@ -505,7 +507,10 @@ static INT add_streams_to_table(MSISTREAMSVIEW *sv) break; if (stat.type != STGTY_STREAM) + { + CoTaskMemFree(stat.pwcsName); continue; + } /* table streams are not in the _Streams table */ if (*stat.pwcsName == 0x4840) @@ -522,13 +527,22 @@ static INT add_streams_to_table(MSISTREAMSVIEW *sv) break; } - hr = IStorage_OpenStream(sv->db->storage, stat.pwcsName, 0, - STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stream->stream); + if (!strcmpW(stat.pwcsName, szSumInfo)) + { + /* summary information stream is not encoded */ + r = db_get_raw_stream(sv->db, stat.pwcsName, &stream->stream); + } + else + { + encname = encode_streamname(FALSE, stat.pwcsName); + r = db_get_raw_stream(sv->db, encname, &stream->stream); + msi_free(encname); + } CoTaskMemFree(stat.pwcsName); - if (FAILED(hr)) + if (r != ERROR_SUCCESS) { - WARN("failed to open stream: %08x\n", hr); + WARN("unable to get stream %u\n", r); count = -1; break; } diff --git a/reactos/dll/win32/msi/suminfo.c b/reactos/dll/win32/msi/suminfo.c index df35c4d0d4c..902a61f6544 100644 --- a/reactos/dll/win32/msi/suminfo.c +++ b/reactos/dll/win32/msi/suminfo.c @@ -86,9 +86,6 @@ static HRESULT (WINAPI *pPropVariantChangeType) #define SECT_HDR_SIZE (sizeof(PROPERTYSECTIONHEADER)) -static const WCHAR szSumInfo[] = { 5 ,'S','u','m','m','a','r','y', - 'I','n','f','o','r','m','a','t','i','o','n',0 }; - static void free_prop( PROPVARIANT *prop ) { if (prop->vt == VT_LPSTR ) diff --git a/reactos/dll/win32/msi/table.c b/reactos/dll/win32/msi/table.c index cc40515e664..6737ac59168 100644 --- a/reactos/dll/win32/msi/table.c +++ b/reactos/dll/win32/msi/table.c @@ -1168,7 +1168,7 @@ static UINT TABLE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, ISt { MSITABLEVIEW *tv = (MSITABLEVIEW*)view; UINT r; - LPWSTR full_name = NULL; + LPWSTR encname, full_name = NULL; if( !view->ops->fetch_int ) return ERROR_INVALID_PARAMETER; @@ -1180,11 +1180,13 @@ static UINT TABLE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, ISt return r; } - r = db_get_raw_stream( tv->db, full_name, stm ); + encname = encode_streamname( FALSE, full_name ); + r = db_get_raw_stream( tv->db, encname, stm ); if( r ) ERR("fetching stream %s, error = %d\n",debugstr_w(full_name), r); - msi_free( full_name ); + msi_free( full_name ); + msi_free( encname ); return r; } diff --git a/reactos/dll/win32/msi/tokenize.c b/reactos/dll/win32/msi/tokenize.c index 04824562de4..e17ded88861 100644 --- a/reactos/dll/win32/msi/tokenize.c +++ b/reactos/dll/win32/msi/tokenize.c @@ -166,9 +166,9 @@ static int sqliteKeywordCode(const WCHAR *z, int n){ */ static const char isIdChar[] = { /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */ + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, /* 2x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */ diff --git a/reactos/include/psdk/msi.h b/reactos/include/psdk/msi.h index 5c2f38cc824..b331057d53c 100644 --- a/reactos/include/psdk/msi.h +++ b/reactos/include/psdk/msi.h @@ -503,6 +503,10 @@ UINT WINAPI MsiGetPatchInfoExA(LPCSTR, LPCSTR, LPCSTR, MSIINSTALLCONTEXT, LPCSTR UINT WINAPI MsiGetPatchInfoExW(LPCWSTR, LPCWSTR, LPCWSTR, MSIINSTALLCONTEXT, LPCWSTR, LPWSTR, LPDWORD); #define MsiGetPatchInfoEx WINELIB_NAME_AW(MsiGetPatchInfoEx) +UINT WINAPI MsiGetPatchInfoA(LPCSTR, LPCSTR, LPSTR, LPDWORD); +UINT WINAPI MsiGetPatchInfoW(LPCWSTR, LPCWSTR, LPWSTR, LPDWORD); +#define MsiGetPatchInfo WINELIB_NAME_AW(MsiGetPatchInfo) + UINT WINAPI MsiEnableLogA(DWORD, LPCSTR, DWORD); UINT WINAPI MsiEnableLogW(DWORD, LPCWSTR, DWORD); #define MsiEnableLog WINELIB_NAME_AW(MsiEnableLog)