From 5b9aceccd3185e74ecd540ce1dbcc4e70b7a3810 Mon Sep 17 00:00:00 2001 From: =?utf8?q?G=C3=A9=20van=20Geldorp?= Date: Fri, 12 Aug 2005 17:07:28 +0000 Subject: [PATCH] Sync to Wine-20050725: Robert Shearman - In MsiLocateComponent pcchBuf can be NULL so don't try to dereference it. Alexandre Julliard - Use the official names for the Unicode string constants. Aric Stewart - Implement MsiGetLanguage. - Relocate the msi file to prevent cd locking, corrected to properly not try to relocated #nnnn handles as files. - Use the SourceList functions to get the source path in ConfigureProductExW. - Handle installs off multiple volumes and properly pull the prompt string from the error table. - If MsiGetProperty(A/W) is called with a NULL for the value buffer but a value in the size for the value buffer, then Msi fills in the size of the value into the pointer for size. This is tested and confirmed with native MSI. - Bail out if the reg key is empty. This prevents us from writing garbage to the property table. - Properly resize the buffer based on ERROR_MORE_DATA. Also remember to free the allocated buffer. - Further testing shows that when CustomActionData needs to be blank it is an empty string not ' '. - Correct an error where I was not properly advancing a pointer. - Add source.c to start handling the various MsiSourceList apis used in v3 of MSI, and now internally. - Update files.c to use the MsiSourceList apis to make sure our SourceList keys in the registry are included and correct. - Use the strings defined in msi.h. - Use SOURCEDIR instead of PackagePath. Because the PackagePath may be local, while SOURCEDIR is more proper and will be a full directory. - InstallShield does a number of actions using DoAction before the Install starts so the PackageCode needs to be loaded on OpenPackage instead of the beginning of the install process. - When working toward install on demand support we need to reset all the constant values so that multiple install process do not get confused by leftover values from the previous install. - Fill and use the ProductCode part of the MSIPACKAGE structure. - Add the string constants located in msi.h and make use of them in files.c and source.c. - Keep track of what sequence we are in and register unique actions. This allows us to make sure actions and custom actions flagged to run only once, actually run only once. - Also clean up some of the numeric constants in custom.c using the defined values from msidefs.h. Mike McCormack - gcc 4.0 -Wpointer-sign fixes. - Display icons in buttons that have them. - Use LoadImage to load bitmaps and icons. - Set the initial focus on the control specified by Control_First in the Dialog table. - Move to the next mask edit field when the current one becomes full. - Make the tab order in msi dialogs right. - Don't crash when cancelling out of a modeless dialog. - Stop the install when cancelling from a modeless dialog. svn path=/trunk/; revision=17331 --- reactos/lib/msi/Makefile.in | 1 + reactos/lib/msi/action.c | 233 +++++---------- reactos/lib/msi/action.h | 11 +- reactos/lib/msi/appsearch.c | 7 + reactos/lib/msi/custom.c | 63 +++- reactos/lib/msi/dialog.c | 367 ++++++++++++++--------- reactos/lib/msi/events.c | 21 +- reactos/lib/msi/files.c | 170 ++++++++++- reactos/lib/msi/helpers.c | 111 ++++++- reactos/lib/msi/install.c | 23 ++ reactos/lib/msi/msi.c | 104 +++---- reactos/lib/msi/msi.spec | 2 +- reactos/lib/msi/msi.xml | 1 + reactos/lib/msi/msipriv.h | 10 +- reactos/lib/msi/package.c | 41 ++- reactos/lib/msi/registry.c | 13 +- reactos/lib/msi/source.c | 560 +++++++++++++++++++++++++++++++++++ reactos/lib/msi/string.c | 4 +- reactos/lib/msi/suminfo.c | 2 +- reactos/lib/msi/upgrade.c | 22 +- reactos/w32api/include/msi.h | 208 ++++++++++++- 21 files changed, 1562 insertions(+), 412 deletions(-) create mode 100644 reactos/lib/msi/source.c diff --git a/reactos/lib/msi/Makefile.in b/reactos/lib/msi/Makefile.in index 38098fab66f..e1216aec360 100644 --- a/reactos/lib/msi/Makefile.in +++ b/reactos/lib/msi/Makefile.in @@ -33,6 +33,7 @@ C_SRCS = \ registry.c \ regsvr.c \ select.c \ + source.c \ string.c \ suminfo.c \ table.c \ diff --git a/reactos/lib/msi/action.c b/reactos/lib/msi/action.c index 6f6ca2e12c9..e16f356fb9b 100644 --- a/reactos/lib/msi/action.c +++ b/reactos/lib/msi/action.c @@ -432,7 +432,7 @@ static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start, *****************************************************/ UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath, - LPCWSTR szCommandLine) + LPCWSTR szCommandLine, LPCWSTR msiFilePath) { DWORD sz; WCHAR buffer[10]; @@ -447,6 +447,10 @@ UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath, package->script = HeapAlloc(GetProcessHeap(),0,sizeof(MSISCRIPT)); memset(package->script,0,sizeof(MSISCRIPT)); + package->script->InWhatSequence = SEQUENCE_INSTALL; + + package->msiFilePath= strdupW(msiFilePath); + if (szPackagePath) { LPWSTR p, check, path; @@ -538,10 +542,14 @@ UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath, { if (atoiW(buffer) >= INSTALLUILEVEL_REDUCED) { + package->script->InWhatSequence |= SEQUENCE_UI; rc = ACTION_ProcessUISequence(package); ui = TRUE; if (rc == ERROR_SUCCESS) + { + package->script->InWhatSequence |= SEQUENCE_EXEC; rc = ACTION_ProcessExecSequence(package,TRUE); + } } else rc = ACTION_ProcessExecSequence(package,FALSE); @@ -666,6 +674,11 @@ static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param) else rc = ACTION_PerformAction(iap->package,action,FALSE); + msi_dialog_check_messages( NULL ); + + if (iap->package->CurrentInstallState != ERROR_SUCCESS ) + rc = iap->package->CurrentInstallState; + if (rc == ERROR_FUNCTION_NOT_CALLED) rc = ERROR_SUCCESS; @@ -814,18 +827,6 @@ static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, return ret; } -static BOOL ACTION_HandleDialogBox( MSIPACKAGE *package, LPCWSTR dialog, UINT* rc ) -{ - BOOL ret = FALSE; - - if (ACTION_DialogBox(package,dialog) == ERROR_SUCCESS) - { - *rc = package->CurrentInstallState; - ret = TRUE; - } - return ret; -} - static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action, UINT* rc, BOOL force ) { @@ -868,7 +869,6 @@ UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force) rc = ERROR_FUNCTION_NOT_CALLED; } - package->CurrentInstallState = rc; return rc; } @@ -884,10 +884,8 @@ UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action) if (!handled) handled = ACTION_HandleCustomAction(package, action, &rc, FALSE); - if (!handled) - handled = ACTION_HandleDialogBox(package, action, &rc); - - msi_dialog_check_messages( NULL ); + if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS ) + handled = TRUE; if (!handled) { @@ -895,7 +893,6 @@ UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action) rc = ERROR_FUNCTION_NOT_CALLED; } - package->CurrentInstallState = rc; return rc; } @@ -1371,9 +1368,6 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir) if (targetdir[0] == '.' && targetdir[1] == 0) targetdir = NULL; - if (srcdir && srcdir[0] == '.' && srcdir[1] == 0) - srcdir = NULL; - if (targetdir) { TRACE(" TargetDefault = %s\n",debugstr_w(targetdir)); @@ -1414,14 +1408,11 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir) static void ACTION_UpdateInstallStates(MSIPACKAGE *package) { int i; - LPWSTR productcode; - - productcode = load_dynamic_property(package,szProductCode,NULL); for (i = 0; i < package->loaded_components; i++) { INSTALLSTATE res; - res = MsiGetComponentPathW(productcode, + res = MsiGetComponentPathW(package->ProductCode, package->components[i].ComponentId , NULL, NULL); if (res < 0) res = INSTALLSTATE_ABSENT; @@ -2127,7 +2118,7 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param) { TRACE("Setting value %s of %s\n",debugstr_w(deformated), debugstr_w(uikey)); - RegSetValueExW(hkey, deformated, 0, type, value_data, size); + RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size); } else { @@ -2143,7 +2134,7 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param) TRACE("Checked and setting value %s of %s\n", debugstr_w(deformated), debugstr_w(uikey)); if (deformated || size) - RegSetValueExW(hkey, deformated, 0, type, value_data, size); + RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size); } } RegCloseKey(hkey); @@ -2500,7 +2491,6 @@ static void ACTION_RefCountComponent( MSIPACKAGE* package, UINT index) */ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) { - LPWSTR productcode; WCHAR squished_pc[GUID_SIZE]; WCHAR squished_cc[GUID_SIZE]; UINT rc; @@ -2511,15 +2501,12 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) return ERROR_INVALID_HANDLE; /* writes the Component and Features values to the registry */ - productcode = load_dynamic_property(package,szProductCode,&rc); - if (!productcode) - return rc; rc = MSIREG_OpenComponents(&hkey); if (rc != ERROR_SUCCESS) goto end; - squash_guid(productcode,squished_pc); + squash_guid(package->ProductCode,squished_pc); ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0); for (i = 0; i < package->loaded_components; i++) { @@ -2555,7 +2542,7 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) if (keypath) { - RegSetValueExW(hkey2,squished_pc,0,REG_SZ,(LPVOID)keypath, + RegSetValueExW(hkey2,squished_pc,0,REG_SZ,(LPBYTE)keypath, (strlenW(keypath)+1)*sizeof(WCHAR)); if (package->components[i].Attributes & @@ -2567,7 +2554,7 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) '0','0','0','0','0','0','0','0',0}; RegSetValueExW(hkey2,szPermKey,0,REG_SZ, - (LPVOID)keypath, + (LPBYTE)keypath, (strlenW(keypath)+1)*sizeof(WCHAR)); } @@ -2575,7 +2562,7 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) /* UI stuff */ uirow = MSI_CreateRecord(3); - MSI_RecordSetStringW(uirow,1,productcode); + MSI_RecordSetStringW(uirow,1,package->ProductCode); MSI_RecordSetStringW(uirow,2,package->components[i]. ComponentId); MSI_RecordSetStringW(uirow,3,keypath); @@ -2602,7 +2589,7 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) /* UI stuff */ uirow = MSI_CreateRecord(2); - MSI_RecordSetStringW(uirow,1,productcode); + MSI_RecordSetStringW(uirow,1,package->ProductCode); MSI_RecordSetStringW(uirow,2,package->components[i]. ComponentId); ui_actiondata(package,szProcessComponents,uirow); @@ -2611,7 +2598,6 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) } } end: - HeapFree(GetProcessHeap(), 0, productcode); RegCloseKey(hkey); return rc; } @@ -3019,25 +3005,14 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package) {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', '`','I','c','o','n','`',0}; /* for registry stuff */ - LPWSTR productcode; HKEY hkey=0; HKEY hukey=0; - static const WCHAR szProductName[] = - {'P','r','o','d','u','c','t','N','a','m','e',0}; - static const WCHAR szPackageCode[] = - {'P','a','c','k','a','g','e','C','o','d','e',0}; - static const WCHAR szLanguage[] = - {'L','a','n','g','u','a','g','e',0}; static const WCHAR szProductLanguage[] = {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0}; - static const WCHAR szProductIcon[] = - {'P','r','o','d','u','c','t','I','c','o','n',0}; static const WCHAR szARPProductIcon[] = {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0}; static const WCHAR szProductVersion[] = {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0}; - static const WCHAR szVersion[] = - {'V','e','r','s','i','o','n',0}; DWORD langid; LPWSTR buffer; DWORD size; @@ -3057,28 +3032,26 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package) /* ok there is a lot more done here but i need to figure out what */ - productcode = load_dynamic_property(package,szProductCode,&rc); - if (!productcode) - return rc; - - rc = MSIREG_OpenProductsKey(productcode,&hkey,TRUE); + rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE); if (rc != ERROR_SUCCESS) goto end; - rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE); + rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE); if (rc != ERROR_SUCCESS) goto end; - buffer = load_dynamic_property(package,szProductName,NULL); + buffer = load_dynamic_property(package,INSTALLPROPERTY_PRODUCTNAMEW,NULL); size = strlenW(buffer)*sizeof(WCHAR); - RegSetValueExW(hukey,szProductName,0,REG_SZ, (BYTE *)buffer,size); + RegSetValueExW(hukey,INSTALLPROPERTY_PRODUCTNAMEW,0,REG_SZ, + (LPBYTE)buffer,size); HeapFree(GetProcessHeap(),0,buffer); buffer = load_dynamic_property(package,szProductLanguage,NULL); size = sizeof(DWORD); langid = atoiW(buffer); - RegSetValueExW(hukey,szLanguage,0,REG_DWORD, (BYTE *)&langid,size); + RegSetValueExW(hukey,INSTALLPROPERTY_LANGUAGEW,0,REG_DWORD, + (LPBYTE)&langid,size); HeapFree(GetProcessHeap(),0,buffer); buffer = load_dynamic_property(package,szARPProductIcon,NULL); @@ -3087,7 +3060,8 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package) LPWSTR path; build_icon_path(package,buffer,&path); size = strlenW(path) * sizeof(WCHAR); - RegSetValueExW(hukey,szProductIcon,0,REG_SZ, (BYTE *)path,size); + RegSetValueExW(hukey,INSTALLPROPERTY_PRODUCTICONW,0,REG_SZ, + (LPBYTE)path,size); } HeapFree(GetProcessHeap(),0,buffer); @@ -3096,7 +3070,8 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package) { DWORD verdword = build_version_dword(buffer); size = sizeof(DWORD); - RegSetValueExW(hukey,szVersion,0,REG_DWORD, (BYTE *)&verdword,size); + RegSetValueExW(hukey,INSTALLPROPERTY_VERSIONW,0,REG_DWORD, (LPBYTE + )&verdword,size); } HeapFree(GetProcessHeap(),0,buffer); @@ -3119,8 +3094,8 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package) if (ptr) *ptr = 0; squash_guid(guidbuffer,squashed); size = strlenW(squashed)*sizeof(WCHAR); - RegSetValueExW(hukey,szPackageCode,0,REG_SZ, (LPSTR)squashed, - size); + RegSetValueExW(hukey,INSTALLPROPERTY_PACKAGECODEW,0,REG_SZ, + (LPBYTE)squashed, size); } else { @@ -3137,7 +3112,6 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package) end: - HeapFree(GetProcessHeap(),0,productcode); RegCloseKey(hkey); RegCloseKey(hukey); @@ -3331,7 +3305,6 @@ static UINT ACTION_SelfRegModules(MSIPACKAGE *package) static UINT ACTION_PublishFeatures(MSIPACKAGE *package) { - LPWSTR productcode; UINT rc; DWORD i; HKEY hkey=0; @@ -3340,15 +3313,11 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package) if (!package) return ERROR_INVALID_HANDLE; - productcode = load_dynamic_property(package,szProductCode,&rc); - if (!productcode) - return rc; - - rc = MSIREG_OpenFeaturesKey(productcode,&hkey,TRUE); + rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE); if (rc != ERROR_SUCCESS) goto end; - rc = MSIREG_OpenUserFeaturesKey(productcode,&hukey,TRUE); + rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE); if (rc != ERROR_SUCCESS) goto end; @@ -3400,14 +3369,14 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package) size = (strlenW(data)+1)*sizeof(WCHAR); RegSetValueExW(hkey,package->features[i].Feature,0,REG_SZ, - (LPSTR)data,size); + (LPBYTE)data,size); HeapFree(GetProcessHeap(),0,data); if (!absent) { size = strlenW(package->features[i].Feature_Parent)*sizeof(WCHAR); RegSetValueExW(hukey,package->features[i].Feature,0,REG_SZ, - (LPSTR)package->features[i].Feature_Parent,size); + (LPBYTE)package->features[i].Feature_Parent,size); } else { @@ -3417,7 +3386,7 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package) data[0] = 0x6; strcpyW(&data[1],package->features[i].Feature_Parent); RegSetValueExW(hukey,package->features[i].Feature,0,REG_SZ, - (LPSTR)data,size); + (LPBYTE)data,size); HeapFree(GetProcessHeap(),0,data); } } @@ -3425,7 +3394,6 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package) end: RegCloseKey(hkey); RegCloseKey(hukey); - HeapFree(GetProcessHeap(), 0, productcode); return rc; } @@ -3433,7 +3401,6 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package) { HKEY hkey=0; LPWSTR buffer = NULL; - LPWSTR productcode; UINT rc,i; DWORD size; static WCHAR szNONE[] = {0}; @@ -3484,8 +3451,6 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package) '%','s','\\', 'I','n','s','t','a','l','l','e','r','\\', '%','x','.','m','s','i',0}; - static const WCHAR szLocalPackage[]= - {'L','o','c','a','l','P','a','c','k','a','g','e',0}; static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0}; static const WCHAR modpath_fmt[] = @@ -3496,20 +3461,10 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package) {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0}; static const WCHAR szEstimatedSize[] = {'E','s','t','i','m','a','t','e','d','S','i','z','e',0}; - static const WCHAR szInstallDate[] = - {'I','n','s','t','a','l','l','D','a','t','e',0}; - static const WCHAR szLanguage[] = - {'L','a','n','g','u','a','g','e',0}; static const WCHAR szProductLanguage[] = {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0}; static const WCHAR szProductVersion[] = {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0}; - static const WCHAR szVersion[] = - {'V','e','r','s','i','o','n',0}; - static const WCHAR szVersionMajor[] = - {'V','e','r','s','i','o','n','M','a','j','o','r',0}; - static const WCHAR szVersionMinor[] = - {'V','e','r','s','i','o','n','M','i','n','o','r',0}; SYSTEMTIME systime; static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0}; @@ -3520,11 +3475,7 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package) if (!package) return ERROR_INVALID_HANDLE; - productcode = load_dynamic_property(package,szProductCode,&rc); - if (!productcode) - return rc; - - rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE); + rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE); if (rc != ERROR_SUCCESS) goto end; @@ -3538,14 +3489,14 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package) if (rc != ERROR_SUCCESS) buffer = szNONE; size = strlenW(buffer)*sizeof(WCHAR); - RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size); + RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPBYTE)buffer,size); HeapFree(GetProcessHeap(),0,buffer); i++; } rc = 0x1; size = sizeof(rc); - RegSetValueExW(hkey,szWindowsInstaler,0,REG_DWORD,(LPSTR)&rc,size); + RegSetValueExW(hkey,szWindowsInstaler,0,REG_DWORD,(LPBYTE)&rc,size); /* copy the package locally */ num = GetTickCount() & 0xffff; @@ -3574,34 +3525,37 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package) snprintfW(path,sizeof(path)/sizeof(path[0]),installerPathFmt,windir); create_full_pathW(path); TRACE("Copying to local package %s\n",debugstr_w(packagefile)); - if (!CopyFileW(package->PackagePath,packagefile,FALSE)) + if (!CopyFileW(package->msiFilePath,packagefile,FALSE)) ERR("Unable to copy package (%s -> %s) (error %ld)\n", - debugstr_w(package->PackagePath), debugstr_w(packagefile), + debugstr_w(package->msiFilePath), debugstr_w(packagefile), GetLastError()); size = strlenW(packagefile)*sizeof(WCHAR); - RegSetValueExW(hkey,szLocalPackage,0,REG_SZ,(LPSTR)packagefile,size); + RegSetValueExW(hkey,INSTALLPROPERTY_LOCALPACKAGEW,0,REG_SZ, + (LPBYTE)packagefile,size); /* do ModifyPath and UninstallString */ size = deformat_string(package,modpath_fmt,&buffer); - RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPSTR)buffer,size); - RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPSTR)buffer,size); + RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size); + RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size); HeapFree(GetProcessHeap(),0,buffer); FIXME("Write real Estimated Size when we have it\n"); size = 0; - RegSetValueExW(hkey,szEstimatedSize,0,REG_DWORD,(LPSTR)&size,sizeof(DWORD)); + RegSetValueExW(hkey,szEstimatedSize,0,REG_DWORD,(LPBYTE)&size,sizeof(DWORD)); GetLocalTime(&systime); size = 9*sizeof(WCHAR); buffer= HeapAlloc(GetProcessHeap(),0,size); sprintfW(buffer,date_fmt,systime.wYear,systime.wMonth,systime.wDay); size = strlenW(buffer)*sizeof(WCHAR); - RegSetValueExW(hkey,szInstallDate,0,REG_SZ,(LPSTR)buffer,size); + RegSetValueExW(hkey,INSTALLPROPERTY_INSTALLDATEW,0,REG_SZ, + (LPBYTE)buffer,size); HeapFree(GetProcessHeap(),0,buffer); buffer = load_dynamic_property(package,szProductLanguage,NULL); size = atoiW(buffer); - RegSetValueExW(hkey,szLanguage,0,REG_DWORD, (LPSTR)&size,sizeof(DWORD)); + RegSetValueExW(hkey,INSTALLPROPERTY_LANGUAGEW,0,REG_DWORD, + (LPBYTE)&size,sizeof(DWORD)); HeapFree(GetProcessHeap(),1,buffer); buffer = load_dynamic_property(package,szProductVersion,NULL); @@ -3611,9 +3565,12 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package) DWORD vermajor = verdword>>24; DWORD verminor = (verdword>>16)&0x00FF; size = sizeof(DWORD); - RegSetValueExW(hkey,szVersion,0,REG_DWORD,(LPSTR)&verdword,size); - RegSetValueExW(hkey,szVersionMajor,0,REG_DWORD,(LPSTR)&vermajor,size); - RegSetValueExW(hkey,szVersionMinor,0,REG_DWORD,(LPSTR)&verminor,size); + RegSetValueExW(hkey,INSTALLPROPERTY_VERSIONW,0,REG_DWORD, + (LPBYTE)&verdword,size); + RegSetValueExW(hkey,INSTALLPROPERTY_VERSIONMAJORW,0,REG_DWORD, + (LPBYTE)&vermajor,size); + RegSetValueExW(hkey,INSTALLPROPERTY_VERSIONMINORW,0,REG_DWORD, + (LPBYTE)&verminor,size); } HeapFree(GetProcessHeap(),0,buffer); @@ -3624,11 +3581,11 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package) HKEY hkey2; WCHAR squashed[33]; MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE); - squash_guid(productcode,squashed); + squash_guid(package->ProductCode,squashed); RegSetValueExW(hkey2, squashed, 0,REG_SZ,NULL,0); RegCloseKey(hkey2); MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE); - squash_guid(productcode,squashed); + squash_guid(package->ProductCode,squashed); RegSetValueExW(hkey2, squashed, 0,REG_SZ,NULL,0); RegCloseKey(hkey2); @@ -3636,7 +3593,6 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package) } end: - HeapFree(GetProcessHeap(),0,productcode); RegCloseKey(hkey); return ERROR_SUCCESS; @@ -3700,26 +3656,14 @@ static UINT ACTION_ForceReboot(MSIPACKAGE *package) 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ', 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0}; WCHAR buffer[256], sysdir[MAX_PATH]; - HKEY hkey,hukey; - LPWSTR productcode; + HKEY hkey; WCHAR squished_pc[100]; - INT rc; DWORD size; - static const WCHAR szLUS[] = { - 'L','a','s','t','U','s','e','d','S','o','u','r','c','e',0}; - static const WCHAR szSourceList[] = { - 'S','o','u','r','c','e','L','i','s','t',0}; - static const WCHAR szPackageName[] = { - 'P','a','c','k','a','g','e','N','a','m','e',0}; if (!package) return ERROR_INVALID_HANDLE; - productcode = load_dynamic_property(package,szProductCode,&rc); - if (!productcode) - return rc; - - squash_guid(productcode,squished_pc); + squash_guid(package->ProductCode,squished_pc); GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0])); RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey); @@ -3727,41 +3671,18 @@ static UINT ACTION_ForceReboot(MSIPACKAGE *package) squished_pc); size = strlenW(buffer)*sizeof(WCHAR); - RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size); + RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPBYTE)buffer,size); RegCloseKey(hkey); TRACE("Reboot command %s\n",debugstr_w(buffer)); RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey); - sprintfW(buffer,install_fmt,productcode,squished_pc); + sprintfW(buffer,install_fmt,package->ProductCode,squished_pc); size = strlenW(buffer)*sizeof(WCHAR); - RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size); + RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPBYTE)buffer,size); RegCloseKey(hkey); - rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE); - if (rc == ERROR_SUCCESS) - { - HKEY hukey2; - LPWSTR buf; - RegCreateKeyW(hukey, szSourceList, &hukey2); - buf = load_dynamic_property(package,cszSourceDir,NULL); - size = strlenW(buf)*sizeof(WCHAR); - RegSetValueExW(hukey2,szLUS,0,REG_SZ,(LPSTR)buf,size); - HeapFree(GetProcessHeap(),0,buf); - - buf = strrchrW(package->PackagePath,'\\'); - if (buf) - { - buf++; - size = strlenW(buf)*sizeof(WCHAR); - RegSetValueExW(hukey2,szPackageName,0,REG_SZ,(LPSTR)buf,size); - } - - RegCloseKey(hukey2); - } - HeapFree(GetProcessHeap(),0,productcode); - return ERROR_INSTALL_SUSPEND; } @@ -3776,11 +3697,8 @@ UINT ACTION_ResolveSource(MSIPACKAGE* package) static UINT ACTION_RegisterUser(MSIPACKAGE *package) { - static const WCHAR szProductID[]= - {'P','r','o','d','u','c','t','I','D',0}; HKEY hkey=0; LPWSTR buffer; - LPWSTR productcode; LPWSTR productid; UINT rc,i; DWORD size; @@ -3804,15 +3722,12 @@ static UINT ACTION_RegisterUser(MSIPACKAGE *package) if (!package) return ERROR_INVALID_HANDLE; - productid = load_dynamic_property(package,szProductID,&rc); + productid = load_dynamic_property(package,INSTALLPROPERTY_PRODUCTIDW, + &rc); if (!productid) return ERROR_SUCCESS; - productcode = load_dynamic_property(package,szProductCode,&rc); - if (!productcode) - return rc; - - rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE); + rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE); if (rc != ERROR_SUCCESS) goto end; @@ -3823,7 +3738,7 @@ static UINT ACTION_RegisterUser(MSIPACKAGE *package) if (rc == ERROR_SUCCESS) { size = strlenW(buffer)*sizeof(WCHAR); - RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size); + RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPBYTE)buffer,size); } else RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,NULL,0); @@ -3831,7 +3746,6 @@ static UINT ACTION_RegisterUser(MSIPACKAGE *package) } end: - HeapFree(GetProcessHeap(),0,productcode); HeapFree(GetProcessHeap(),0,productid); RegCloseKey(hkey); @@ -3848,6 +3762,7 @@ static UINT ACTION_ExecuteAction(MSIPACKAGE *package) level = load_dynamic_property(package,szUILevel,NULL); MSI_SetPropertyW(package,szUILevel,szTwo); + package->script->InWhatSequence |= SEQUENCE_EXEC; rc = ACTION_ProcessExecSequence(package,FALSE); MSI_SetPropertyW(package,szUILevel,level); HeapFree(GetProcessHeap(),0,level); diff --git a/reactos/lib/msi/action.h b/reactos/lib/msi/action.h index 9c472a53f15..b8914074b9c 100644 --- a/reactos/lib/msi/action.h +++ b/reactos/lib/msi/action.h @@ -187,13 +187,19 @@ enum SCRIPTS { TOTAL_SCRIPTS = 3 }; +#define SEQUENCE_UI 0x1 +#define SEQUENCE_EXEC 0x2 +#define SEQUENCE_INSTALL 0x10 + typedef struct tagMSISCRIPT { LPWSTR *Actions[TOTAL_SCRIPTS]; UINT ActionCount[TOTAL_SCRIPTS]; BOOL ExecuteSequenceRun; - BOOL FindRelatedProductsRun; BOOL CurrentlyScripting; + UINT InWhatSequence; + LPWSTR *UniqueActions; + UINT UniqueActionsCount; }MSISCRIPT; @@ -234,6 +240,9 @@ void reduce_to_longfilename(WCHAR*); void reduce_to_shortfilename(WCHAR*); LPWSTR create_component_advertise_string(MSIPACKAGE*, MSICOMPONENT*, LPCWSTR); void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature); +UINT register_unique_action(MSIPACKAGE *, LPCWSTR); +BOOL check_unique_action(MSIPACKAGE *, LPCWSTR); +WCHAR* generate_error_string(MSIPACKAGE *, UINT, DWORD, ... ); /* control event stuff */ diff --git a/reactos/lib/msi/appsearch.c b/reactos/lib/msi/appsearch.c index 42ea8a44de9..4f080fa4c61 100644 --- a/reactos/lib/msi/appsearch.c +++ b/reactos/lib/msi/appsearch.c @@ -334,6 +334,13 @@ static UINT ACTION_AppSearchReg(MSIPACKAGE *package, BOOL *appFound, goto end; } + /* bail out if the registry key is empty */ + if (sz == 0) + { + rc = ERROR_SUCCESS; + goto end; + } + switch (regType) { case REG_SZ: diff --git a/reactos/lib/msi/custom.c b/reactos/lib/msi/custom.c index 17645e999cc..5475fa5b3ea 100644 --- a/reactos/lib/msi/custom.c +++ b/reactos/lib/msi/custom.c @@ -36,6 +36,7 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/summa #include "wine/debug.h" #include "fdi.h" #include "msi.h" +#include "msidefs.h" #include "msiquery.h" #include "fcntl.h" #include "objbase.h" @@ -74,6 +75,45 @@ static UINT HANDLE_CustomType50(MSIPACKAGE *package, LPCWSTR source, static UINT HANDLE_CustomType34(MSIPACKAGE *package, LPCWSTR source, LPCWSTR target, const INT type, LPCWSTR action); + +static BOOL check_execution_scheduling_options(MSIPACKAGE *package, LPCWSTR action, UINT options) +{ + if (!package->script) + return TRUE; + + if ((options & msidbCustomActionTypeClientRepeat) == + msidbCustomActionTypeClientRepeat) + { + if (!(package->script->InWhatSequence & SEQUENCE_UI && + package->script->InWhatSequence & SEQUENCE_EXEC)) + { + TRACE("Skipping action due to dbCustomActionTypeClientRepeat option.\n"); + return FALSE; + } + } + else if (options & msidbCustomActionTypeFirstSequence) + { + if (package->script->InWhatSequence & SEQUENCE_UI && + package->script->InWhatSequence & SEQUENCE_EXEC ) + { + TRACE("Skipping action due to msidbCustomActionTypeFirstSequence option.\n"); + return FALSE; + } + } + else if (options & msidbCustomActionTypeOncePerProcess) + { + if (check_unique_action(package,action)) + { + TRACE("Skipping action due to msidbCustomActionTypeOncePerProcess option.\n"); + return FALSE; + } + else + register_unique_action(package,action); + } + + return TRUE; +} + UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute) { UINT rc = ERROR_SUCCESS; @@ -101,9 +141,15 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute) debugstr_w(source), debugstr_w(target)); /* handle some of the deferred actions */ - if (type & 0x400) + if (type & msidbCustomActionTypeTSAware) + FIXME("msidbCustomActionTypeTSAware not handled\n"); + + if (type & msidbCustomActionTypeInScript) { - if (type & 0x100) + if (type & msidbCustomActionTypeNoImpersonate) + FIXME("msidbCustomActionTypeNoImpersonate not handled\n"); + + if (type & msidbCustomActionTypeRollback) { FIXME("Rollback only action... rollbacks not supported yet\n"); schedule_action(package, ROLLBACK_SCRIPT, action); @@ -114,7 +160,7 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute) } if (!execute) { - if (type & 0x200) + if (type & msidbCustomActionTypeCommit) { TRACE("Deferring Commit Action!\n"); schedule_action(package, COMMIT_SCRIPT, action); @@ -136,11 +182,16 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute) static const WCHAR szActionData[] = { 'C','u','s','t','o','m','A','c','t','i','o','n','D','a','t','a',0}; + static const WCHAR szBlank[] = {0}; LPWSTR actiondata = load_dynamic_property(package,action,NULL); if (actiondata) MSI_SetPropertyW(package,szActionData,actiondata); + else + MSI_SetPropertyW(package,szActionData,szBlank); } } + else if (!check_execution_scheduling_options(package,action,type)) + return ERROR_SUCCESS; switch (type & CUSTOM_ACTION_TYPE_MASK) { @@ -304,7 +355,7 @@ static UINT process_handle(MSIPACKAGE* package, UINT type, { UINT rc = ERROR_SUCCESS; - if (!(type & 0x80)) + if (!(type & msidbCustomActionTypeAsync)) { /* synchronous */ TRACE("Synchronous Execution of action %s\n",debugstr_w(Name)); @@ -313,7 +364,7 @@ static UINT process_handle(MSIPACKAGE* package, UINT type, else msi_dialog_check_messages(ThreadHandle); - if (!(type & 0x40)) + if (!(type & msidbCustomActionTypeContinue)) { if (ProcessHandle) rc = process_action_return_value(2,ProcessHandle); @@ -331,7 +382,7 @@ static UINT process_handle(MSIPACKAGE* package, UINT type, { TRACE("Asynchronous Execution of action %s\n",debugstr_w(Name)); /* asynchronous */ - if (type & 0x40) + if (type & msidbCustomActionTypeContinue) { if (ProcessHandle) { diff --git a/reactos/lib/msi/dialog.c b/reactos/lib/msi/dialog.c index 69e2b1e6fd7..be98cbc9f7a 100644 --- a/reactos/lib/msi/dialog.c +++ b/reactos/lib/msi/dialog.c @@ -53,8 +53,9 @@ struct msi_control_tag msi_handler handler; LPWSTR property; LPWSTR value; - IPicture *pic; + HBITMAP hBitmap; HICON hIcon; + LPWSTR tabnext; WCHAR name[1]; }; @@ -76,6 +77,7 @@ struct msi_dialog_tag LPWSTR default_font; msi_font *font_list; msi_control *control_list; + HWND hWndFocus; WCHAR name[1]; }; @@ -143,6 +145,8 @@ static msi_control *msi_dialog_find_control( msi_dialog *dialog, LPCWSTR name ) { msi_control *control; + if( !name ) + return NULL; for( control = dialog->control_list; control; control = control->next ) if( !strcmpW( control->name, name ) ) /* FIXME: case sensitive? */ break; @@ -297,8 +301,9 @@ static msi_control *msi_dialog_create_window( msi_dialog *dialog, control->handler = NULL; control->property = NULL; control->value = NULL; - control->pic = NULL; + control->hBitmap = NULL; control->hIcon = NULL; + control->tabnext = strdupW( MSI_RecordGetString( rec, 11) ); x = MSI_RecordGetInteger( rec, 4 ); y = MSI_RecordGetInteger( rec, 5 ); @@ -331,6 +336,97 @@ static msi_control *msi_dialog_create_window( msi_dialog *dialog, return control; } +static MSIRECORD *msi_get_binary_record( MSIDATABASE *db, LPCWSTR name ) +{ + const static WCHAR query[] = { + 's','e','l','e','c','t',' ','*',' ', + 'f','r','o','m',' ','B','i','n','a','r','y',' ', + 'w','h','e','r','e',' ', + '`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0 + }; + + return MSI_QueryGetRecord( db, query, name ); +} + +static LPWSTR msi_create_tmp_path(void) +{ + WCHAR tmp[MAX_PATH]; + LPWSTR path = NULL; + static const WCHAR prefix[] = { 'm','s','i',0 }; + DWORD len, r; + + r = GetTempPathW( MAX_PATH, tmp ); + if( !r ) + return path; + len = lstrlenW( tmp ) + 20; + path = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) ); + if( path ) + { + r = GetTempFileNameW( tmp, prefix, 0, path ); + if (!r) + { + HeapFree( GetProcessHeap(), 0, path ); + path = NULL; + } + } + return path; +} + + +static HANDLE msi_load_image( MSIDATABASE *db, LPCWSTR name, UINT type, + UINT cx, UINT cy, UINT flags ) +{ + MSIRECORD *rec = NULL; + HANDLE himage = NULL; + LPWSTR tmp; + UINT r; + + TRACE("%p %s %u %u %08x\n", db, debugstr_w(name), cx, cy, flags); + + tmp = msi_create_tmp_path(); + if( !tmp ) + return himage; + + rec = msi_get_binary_record( db, name ); + if( rec ) + { + r = MSI_RecordStreamToFile( rec, 2, tmp ); + if( r == ERROR_SUCCESS ) + { + himage = LoadImageW( 0, tmp, type, cx, cy, flags ); + DeleteFileW( tmp ); + } + msiobj_release( &rec->hdr ); + } + + HeapFree( GetProcessHeap(), 0, tmp ); + return himage; +} + +static HICON msi_load_icon( MSIDATABASE *db, LPCWSTR text, UINT attributes ) +{ + DWORD cx = 0, cy = 0, flags; + + flags = LR_LOADFROMFILE | LR_DEFAULTSIZE; + if( attributes & msidbControlAttributesFixedSize ) + { + flags &= ~LR_DEFAULTSIZE; + if( attributes & msidbControlAttributesIconSize16 ) + { + cx += 16; + cy += 16; + } + if( attributes & msidbControlAttributesIconSize32 ) + { + cx += 32; + cy += 32; + } + /* msidbControlAttributesIconSize48 handled by above logic */ + } + return msi_load_image( db, text, IMAGE_ICON, cx, cy, flags ); +} + + /* called from the Control Event subscription code */ void msi_dialog_handle_event( msi_dialog* dialog, LPCWSTR control, LPCWSTR attribute, MSIRECORD *rec ) @@ -475,12 +571,28 @@ static UINT msi_dialog_text_control( msi_dialog *dialog, MSIRECORD *rec ) static UINT msi_dialog_button_control( msi_dialog *dialog, MSIRECORD *rec ) { msi_control *control; + UINT attributes, style; + LPCWSTR text; TRACE("%p %p\n", dialog, rec); - control = msi_dialog_add_control( dialog, rec, szButton, WS_TABSTOP ); + style = WS_TABSTOP; + attributes = MSI_RecordGetInteger( rec, 8 ); + if( attributes & msidbControlAttributesIcon ) + style |= BS_ICON; + + control = msi_dialog_add_control( dialog, rec, szButton, style ); + if( !control ) + return ERROR_FUNCTION_FAILED; + control->handler = msi_dialog_button_handler; + /* set the icon */ + text = MSI_RecordGetString( rec, 10 ); + control->hIcon = msi_load_icon( dialog->package->db, text, attributes ); + if( attributes & msidbControlAttributesIcon ) + SendMessageW( control->hwnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM) control->hIcon ); + return ERROR_SUCCESS; } @@ -611,161 +723,56 @@ static UINT msi_dialog_scrolltext_control( msi_dialog *dialog, MSIRECORD *rec ) return ERROR_SUCCESS; } -static MSIRECORD *msi_get_binary_record( MSIDATABASE *db, LPCWSTR name ) -{ - const static WCHAR query[] = { - 's','e','l','e','c','t',' ','*',' ', - 'f','r','o','m',' ','B','i','n','a','r','y',' ', - 'w','h','e','r','e',' ', - '`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0 - }; - - return MSI_QueryGetRecord( db, query, name ); -} - -static UINT msi_load_bitmap( MSIDATABASE *db, LPCWSTR name, IPicture **pic ) -{ - MSIRECORD *rec = NULL; - IStream *stm = NULL; - UINT r; - - rec = msi_get_binary_record( db, name ); - if( !rec ) - return ERROR_FUNCTION_FAILED; - - r = MSI_RecordGetIStream( rec, 2, &stm ); - msiobj_release( &rec->hdr ); - if( r != ERROR_SUCCESS ) - return r; - - r = OleLoadPicture( stm, 0, TRUE, &IID_IPicture, (LPVOID*) pic ); - IStream_Release( stm ); - if( FAILED( r ) ) - return ERROR_FUNCTION_FAILED; - - return ERROR_SUCCESS; -} - static UINT msi_dialog_bitmap_control( msi_dialog *dialog, MSIRECORD *rec ) { - IPicture *pic = NULL; + UINT cx, cy, flags, style, attributes; msi_control *control; - OLE_HANDLE hBitmap = 0; LPCWSTR text; - UINT r; - control = msi_dialog_add_control( dialog, rec, szStatic, - SS_BITMAP | SS_LEFT | SS_CENTERIMAGE ); - text = MSI_RecordGetString( rec, 10 ); - r = msi_load_bitmap( dialog->package->db, text, &pic ); - if( r == ERROR_SUCCESS ) - { - r = IPicture_get_Handle( pic, &hBitmap ); - if( SUCCEEDED( r ) ) - SendMessageW( control->hwnd, STM_SETIMAGE, IMAGE_BITMAP, hBitmap ); - control->pic = pic; - } - - return ERROR_SUCCESS; -} - -static LPWSTR msi_create_tmp_path(void) -{ - WCHAR tmp[MAX_PATH]; - LPWSTR path = NULL; - static const WCHAR prefix[] = { 'm','s','i',0 }; - DWORD len, r; + flags = LR_LOADFROMFILE; + style = SS_BITMAP | SS_LEFT | WS_GROUP; - r = GetTempPathW( MAX_PATH, tmp ); - if( !r ) - return path; - len = lstrlenW( tmp ) + 20; - path = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) ); - if( path ) - { - r = GetTempFileNameW( tmp, prefix, 0, path ); - if (!r) - { - HeapFree( GetProcessHeap(), 0, path ); - path = NULL; - } - } - return path; -} - -static UINT -msi_load_icon( MSIDATABASE *db, LPCWSTR name, DWORD attributes, HICON *picon ) -{ - UINT r = ERROR_FUNCTION_FAILED; - LPWSTR tmp; - MSIRECORD *rec; - HICON hicon = 0; - - TRACE("loading %s\n", debugstr_w( name ) ); - - tmp = msi_create_tmp_path(); - if( !tmp ) - return r; - - rec = msi_get_binary_record( db, name ); - if( rec ) + attributes = MSI_RecordGetInteger( rec, 8 ); + if( attributes & msidbControlAttributesFixedSize ) { - r = MSI_RecordStreamToFile( rec, 2, tmp ); - if( r == ERROR_SUCCESS ) - { - DWORD cx = 0, cy = 0, flags = LR_LOADFROMFILE | LR_DEFAULTSIZE; - - if( attributes & msidbControlAttributesFixedSize ) - { - flags &= ~LR_DEFAULTSIZE; - if( attributes & msidbControlAttributesIconSize16 ) - { - cx += 16; - cy += 16; - } - if( attributes & msidbControlAttributesIconSize32 ) - { - cx += 32; - cy += 32; - } - /* msidbControlAttributesIconSize48 handled by above logic */ - } - - hicon = LoadImageW( 0, tmp, IMAGE_ICON, cx, cy, flags ); - if( hicon ) - *picon = hicon; - else - ERR("failed to load icon from %s\n", debugstr_w( tmp )); - DeleteFileW( tmp ); - } - msiobj_release( &rec->hdr ); + flags |= LR_DEFAULTSIZE; + style |= SS_CENTERIMAGE; } - HeapFree( GetProcessHeap(), 0, tmp ); - - return r; + control = msi_dialog_add_control( dialog, rec, szStatic, style ); + text = MSI_RecordGetString( rec, 10 ); + cx = MSI_RecordGetInteger( rec, 6 ); + cy = MSI_RecordGetInteger( rec, 7 ); + cx = msi_dialog_scale_unit( dialog, cx ); + cy = msi_dialog_scale_unit( dialog, cy ); + + control->hBitmap = msi_load_image( dialog->package->db, text, + IMAGE_BITMAP, cx, cy, flags ); + if( control->hBitmap ) + SendMessageW( control->hwnd, STM_SETIMAGE, + IMAGE_BITMAP, (LPARAM) control->hBitmap ); + else + ERR("Failed to load bitmap %s\n", debugstr_w(text)); + + return ERROR_SUCCESS; } static UINT msi_dialog_icon_control( msi_dialog *dialog, MSIRECORD *rec ) { msi_control *control; DWORD attributes; - HICON hIcon = 0; LPCWSTR text; - UINT r; TRACE("\n"); control = msi_dialog_add_control( dialog, rec, szStatic, SS_ICON | SS_CENTERIMAGE | WS_GROUP ); - text = MSI_RecordGetString( rec, 10 ); + attributes = MSI_RecordGetInteger( rec, 8 ); - r = msi_load_icon( dialog->package->db, text, attributes, &hIcon ); - if( r == ERROR_SUCCESS ) - { - r = SendMessageW( control->hwnd, STM_SETICON, (WPARAM) hIcon, 0 ); - control->hIcon = hIcon; - } + text = MSI_RecordGetString( rec, 10 ); + control->hIcon = msi_load_icon( dialog->package->db, text, attributes ); + if( control->hIcon ) + SendMessageW( control->hwnd, STM_SETICON, (WPARAM) control->hIcon, 0 ); else ERR("Failed to load bitmap %s\n", debugstr_w(text)); return ERROR_SUCCESS; @@ -853,6 +860,28 @@ static void msi_mask_control_change( struct msi_maskedit_info *info ) HeapFree( GetProcessHeap(), 0, val ); } +/* now move to the next control if necessary */ +static VOID msi_mask_next_control( struct msi_maskedit_info *info, HWND hWnd ) +{ + HWND hWndNext; + UINT len, i; + + for( i=0; inum_groups; i++ ) + if( info->group[i].hwnd == hWnd ) + break; + + /* don't move from the last control */ + if( i >= (info->num_groups-1) ) + return; + + len = SendMessageW( hWnd, WM_GETTEXTLENGTH, 0, 0 ); + if( len < info->group[i].len ) + return; + + hWndNext = GetNextDlgTabItem( GetParent( hWnd ), hWnd, FALSE ); + SetFocus( hWndNext ); +} + static LRESULT WINAPI MSIMaskedEdit_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { @@ -869,7 +898,10 @@ MSIMaskedEdit_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { case WM_COMMAND: if (HIWORD(wParam) == EN_CHANGE) + { msi_mask_control_change( info ); + msi_mask_next_control( info, (HWND) lParam ); + } break; case WM_NCDESTROY: HeapFree( GetProcessHeap(), 0, info->prop ); @@ -1351,6 +1383,39 @@ static void msi_dialog_adjust_dialog_size( msi_dialog *dialog, LPSIZE sz ) sz->cy = rect.bottom - rect.top; } +static BOOL msi_control_set_next( msi_control *control, msi_control *next ) +{ + return SetWindowPos( next->hwnd, control->hwnd, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOREDRAW | + SWP_NOREPOSITION | SWP_NOSENDCHANGING | SWP_NOSIZE ); +} + +static UINT msi_dialog_set_tab_order( msi_dialog *dialog ) +{ + msi_control *control, *tab_next; + + for( control = dialog->control_list; control; control = control->next ) + { + tab_next = msi_dialog_find_control( dialog, control->tabnext ); + if( !tab_next ) + continue; + msi_control_set_next( control, tab_next ); + } + + return ERROR_SUCCESS; +} + +static void msi_dialog_set_first_control( msi_dialog* dialog, LPCWSTR name ) +{ + msi_control *control; + + control = msi_dialog_find_control( dialog, name ); + if( control ) + dialog->hWndFocus = control->hwnd; + else + dialog->hWndFocus = NULL; +} + static LRESULT msi_dialog_oncreate( HWND hwnd, LPCREATESTRUCTW cs ) { static const WCHAR df[] = { @@ -1390,11 +1455,13 @@ static LRESULT msi_dialog_oncreate( HWND hwnd, LPCREATESTRUCTW cs ) SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW ); HeapFree( GetProcessHeap(), 0, title ); - msiobj_release( &rec->hdr ); msi_dialog_build_font_list( dialog ); msi_dialog_fill_controls( dialog ); msi_dialog_evaluate_control_conditions( dialog ); + msi_dialog_set_tab_order( dialog ); + msi_dialog_set_first_control( dialog, MSI_RecordGetString( rec, 8 ) ); + msiobj_release( &rec->hdr ); return 0; } @@ -1617,6 +1684,16 @@ static LRESULT msi_dialog_oncommand( msi_dialog *dialog, WPARAM param, HWND hwnd return 0; } +static void msi_dialog_setfocus( msi_dialog *dialog ) +{ + HWND hwnd = dialog->hWndFocus; + + hwnd = GetNextDlgTabItem( dialog->hwnd, hwnd, TRUE); + hwnd = GetNextDlgTabItem( dialog->hwnd, hwnd, FALSE); + SetFocus( hwnd ); + dialog->hWndFocus = hwnd; +} + static LRESULT WINAPI MSIDialog_WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) { @@ -1632,6 +1709,17 @@ static LRESULT WINAPI MSIDialog_WndProc( HWND hwnd, UINT msg, case WM_COMMAND: return msi_dialog_oncommand( dialog, wParam, (HWND)lParam ); + case WM_ACTIVATE: + if( LOWORD(wParam) == WA_INACTIVE ) + dialog->hWndFocus = GetFocus(); + else + msi_dialog_setfocus( dialog ); + return 0; + + case WM_SETFOCUS: + msi_dialog_setfocus( dialog ); + return 0; + /* bounce back to our subclassed static control */ case WM_CTLCOLORSTATIC: return SendMessageW( (HWND) lParam, WM_CTLCOLORSTATIC, wParam, lParam ); @@ -1821,10 +1909,11 @@ void msi_dialog_destroy( msi_dialog *dialog ) /* leave dialog->hwnd - destroying parent destroys child windows */ HeapFree( GetProcessHeap(), 0, t->property ); HeapFree( GetProcessHeap(), 0, t->value ); - if( t->pic ) - IPicture_Release( t->pic ); + if( t->hBitmap ) + DeleteObject( t->hBitmap ); if( t->hIcon ) DestroyIcon( t->hIcon ); + HeapFree( GetProcessHeap(), 0, t->tabnext ); HeapFree( GetProcessHeap(), 0, t ); } diff --git a/reactos/lib/msi/events.c b/reactos/lib/msi/events.c index 6d6682bb91f..1c44b9577b2 100644 --- a/reactos/lib/msi/events.c +++ b/reactos/lib/msi/events.c @@ -57,21 +57,23 @@ UINT ControlEvent_HandleControlEvent(MSIPACKAGE *, LPCWSTR, LPCWSTR, msi_dialog* /* * Create a dialog box and run it if it's modal */ -static UINT event_do_dialog( MSIPACKAGE *package, LPCWSTR name ) +static UINT event_do_dialog( MSIPACKAGE *package, LPCWSTR name, BOOL destroy_modeless ) { msi_dialog *dialog; UINT r; - /* kill the current modeless dialog */ - if( package->dialog ) - msi_dialog_destroy( package->dialog ); - package->dialog = NULL; - /* create a new dialog */ dialog = msi_dialog_create( package, name, ControlEvent_HandleControlEvent ); if( dialog ) { + /* kill the current modeless dialog */ + if( destroy_modeless && package->dialog ) + { + msi_dialog_destroy( package->dialog ); + package->dialog = NULL; + } + /* modeless dialogs return an error message */ r = msi_dialog_run_message_loop( dialog ); if( r == ERROR_SUCCESS ) @@ -139,7 +141,8 @@ static UINT ControlEvent_NewDialog(MSIPACKAGE* package, LPCWSTR argument, static UINT ControlEvent_SpawnDialog(MSIPACKAGE* package, LPCWSTR argument, msi_dialog *dialog) { - event_do_dialog( package, argument ); + /* don't destroy a modeless dialogs that might be our parent */ + event_do_dialog( package, argument, FALSE ); if( package->CurrentInstallState != ERROR_SUCCESS ) msi_dialog_end_dialog( dialog ); return ERROR_SUCCESS; @@ -339,13 +342,13 @@ UINT ACTION_DialogBox( MSIPACKAGE* package, LPCWSTR szDialogName ) * dialog, as it returns ERROR_IO_PENDING when we try to run * its message loop. */ - r = event_do_dialog( package, szDialogName ); + r = event_do_dialog( package, szDialogName, TRUE ); while( r == ERROR_SUCCESS && package->next_dialog ) { LPWSTR name = package->next_dialog; package->next_dialog = NULL; - r = event_do_dialog( package, name ); + r = event_do_dialog( package, name, TRUE ); HeapFree( GetProcessHeap(), 0, name ); } diff --git a/reactos/lib/msi/files.c b/reactos/lib/msi/files.c index a4fd40e493d..c7f0862c109 100644 --- a/reactos/lib/msi/files.c +++ b/reactos/lib/msi/files.c @@ -37,6 +37,7 @@ #include "winerror.h" #include "wine/debug.h" #include "fdi.h" +#include "msi.h" #include "msidefs.h" #include "msvcrt/fcntl.h" #include "msipriv.h" @@ -359,7 +360,81 @@ static VOID set_file_source(MSIPACKAGE* package, MSIFILE* file, MSICOMPONENT* file->SourcePath = build_directory_name(2, path, file->File); } -static UINT ready_media_for_file(MSIPACKAGE *package, int fileindex, +static BOOL check_volume(LPCWSTR path, LPCWSTR want_volume, LPWSTR volume, + UINT *intype) +{ + WCHAR drive[4]; + WCHAR name[MAX_PATH]; + UINT type; + + if (!(path[0] && path[1] == ':')) + return TRUE; + + drive[0] = path[0]; + drive[1] = path[1]; + drive[2] = '\\'; + drive[3] = 0; + TRACE("Checking volume %s .. (%s)\n",debugstr_w(drive), debugstr_w(want_volume)); + type = GetDriveTypeW(drive); + TRACE("drive is of type %x\n",type); + + if (type == DRIVE_UNKNOWN || type == DRIVE_NO_ROOT_DIR || + type == DRIVE_FIXED || type == DRIVE_RAMDISK) + return TRUE; + + GetVolumeInformationW(drive, name, MAX_PATH, NULL, NULL, NULL, NULL, 0); + TRACE("Drive contains %s\n", debugstr_w(name)); + volume = strdupW(name); + if (*intype) + *intype=type; + return (strcmpiW(want_volume,name)==0); +} + +static BOOL check_for_sourcefile(LPCWSTR source) +{ + DWORD attrib = GetFileAttributesW(source); + return (!(attrib == INVALID_FILE_ATTRIBUTES)); +} + +static UINT ready_volume(MSIPACKAGE* package, LPCWSTR path, LPWSTR last_volume, + MSIRECORD *row,UINT *type ) +{ + LPWSTR volume = NULL; + LPCWSTR want_volume = MSI_RecordGetString(row, 5); + BOOL ok = check_volume(path, want_volume, volume, type); + + TRACE("Readying Volume for %s (%s, %s)\n",debugstr_w(path), debugstr_w(want_volume), debugstr_w(last_volume)); + + if (check_for_sourcefile(path) && !ok) + { + FIXME("Found the Sourcefile but not on the correct volume.(%s,%s,%s)\n", + debugstr_w(path),debugstr_w(want_volume), debugstr_w(volume)); + return ERROR_SUCCESS; + } + + while (!ok) + { + INT rc; + LPCWSTR prompt; + LPWSTR msg; + + prompt = MSI_RecordGetString(row,3); + msg = generate_error_string(package, 1302, 1, prompt); + rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL); + HeapFree(GetProcessHeap(),0,volume); + HeapFree(GetProcessHeap(),0,msg); + if (rc == IDOK) + ok = check_for_sourcefile(path); + else + return ERROR_INSTALL_USEREXIT; + } + + HeapFree(GetProcessHeap(),0,last_volume); + last_volume = strdupW(volume); + return ERROR_SUCCESS; +} + +static UINT ready_media_for_file(MSIPACKAGE *package, int fileindex, MSICOMPONENT* comp) { UINT rc = ERROR_SUCCESS; @@ -371,17 +446,27 @@ static UINT ready_media_for_file(MSIPACKAGE *package, int fileindex, '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=', ' ','%', 'i',' ','O','R','D','E','R',' ','B','Y',' ', '`','L','a','s','t','S','e','q','u','e','n','c','e','`',0}; - LPCWSTR cab; + LPCWSTR cab, volume; DWORD sz; INT seq; static UINT last_sequence = 0; + static LPWSTR last_volume = NULL; static LPWSTR last_path = NULL; MSIFILE* file = NULL; + UINT type; + LPCWSTR prompt; + static DWORD count = 0; /* cleanup signal */ if (!package) { HeapFree(GetProcessHeap(),0,last_path); + HeapFree(GetProcessHeap(),0,last_volume); + last_sequence = 0; + last_path = NULL; + last_volume = NULL; + count = 0; + memset(source,0,sizeof(source)); return ERROR_SUCCESS; } @@ -394,6 +479,7 @@ static UINT ready_media_for_file(MSIPACKAGE *package, int fileindex, return ERROR_SUCCESS; } + count ++; row = MSI_QueryGetRecord(package->db, ExecSeqQuery, file->Sequence); if (!row) { @@ -404,6 +490,9 @@ static UINT ready_media_for_file(MSIPACKAGE *package, int fileindex, seq = MSI_RecordGetInteger(row,2); last_sequence = seq; + volume = MSI_RecordGetString(row, 5); + prompt = MSI_RecordGetString(row, 3); + HeapFree(GetProcessHeap(),0,last_path); last_path = NULL; @@ -411,6 +500,23 @@ static UINT ready_media_for_file(MSIPACKAGE *package, int fileindex, { last_path = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL); set_file_source(package,file,comp,last_path); + rc = ready_volume(package, file->SourcePath, last_volume, row,&type); + + MsiSourceListAddMediaDiskW(package->ProductCode, NULL, + MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT, count, volume, + prompt); + + if (type == DRIVE_REMOVABLE || type == DRIVE_CDROM || + type == DRIVE_RAMDISK) + MsiSourceListSetInfoW(package->ProductCode, NULL, + MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT|MSISOURCETYPE_MEDIA, + INSTALLPROPERTY_LASTUSEDSOURCEW, last_path); + else + MsiSourceListSetInfoW(package->ProductCode, NULL, + MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT|MSISOURCETYPE_NETWORK, + INSTALLPROPERTY_LASTUSEDSOURCEW, last_path); msiobj_release(&row->hdr); return rc; } @@ -422,9 +528,24 @@ static UINT ready_media_for_file(MSIPACKAGE *package, int fileindex, /* the stream does not contain the # character */ if (cab[0]=='#') { + LPWSTR path; + writeout_cabinet_stream(package,&cab[1],source); last_path = strdupW(source); *(strrchrW(last_path,'\\')+1)=0; + + path = load_dynamic_property(package,cszSourceDir,NULL); + + MsiSourceListAddMediaDiskW(package->ProductCode, NULL, + MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT, count, + volume, prompt); + + MsiSourceListSetInfoW(package->ProductCode, NULL, + MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT|MSISOURCETYPE_NETWORK, + INSTALLPROPERTY_LASTUSEDSOURCEW, path); + + HeapFree(GetProcessHeap(),0,path); } else { @@ -439,6 +560,20 @@ static UINT ready_media_for_file(MSIPACKAGE *package, int fileindex, { strcpyW(last_path,source); strcatW(source,cab); + + rc = ready_volume(package, source, last_volume, row, &type); + if (type == DRIVE_REMOVABLE || type == DRIVE_CDROM || + type == DRIVE_RAMDISK) + MsiSourceListSetInfoW(package->ProductCode, NULL, + MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT|MSISOURCETYPE_MEDIA, + INSTALLPROPERTY_LASTUSEDSOURCEW, last_path); + else + MsiSourceListSetInfoW(package->ProductCode, NULL, + MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT|MSISOURCETYPE_NETWORK, + INSTALLPROPERTY_LASTUSEDSOURCEW, last_path); + /* extract the cab file into a folder in the temp folder */ sz = MAX_PATH; if (MSI_GetPropertyW(package, cszTempFolder,last_path, &sz) @@ -456,8 +591,26 @@ static UINT ready_media_for_file(MSIPACKAGE *package, int fileindex, last_path = HeapAlloc(GetProcessHeap(),0,MAX_PATH*sizeof(WCHAR)); MSI_GetPropertyW(package,cszSourceDir,source,&sz); strcpyW(last_path,source); + rc = ready_volume(package, last_path, last_volume, row, &type); + + if (type == DRIVE_REMOVABLE || type == DRIVE_CDROM || + type == DRIVE_RAMDISK) + MsiSourceListSetInfoW(package->ProductCode, NULL, + MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT|MSISOURCETYPE_MEDIA, + INSTALLPROPERTY_LASTUSEDSOURCEW, last_path); + else + MsiSourceListSetInfoW(package->ProductCode, NULL, + MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT|MSISOURCETYPE_NETWORK, + INSTALLPROPERTY_LASTUSEDSOURCEW, last_path); } set_file_source(package, file, comp, last_path); + + MsiSourceListAddMediaDiskW(package->ProductCode, NULL, + MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT, count, volume, + prompt); + msiobj_release(&row->hdr); return rc; @@ -499,6 +652,7 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package) { UINT rc = ERROR_SUCCESS; DWORD index; + LPWSTR ptr; if (!package) return ERROR_INVALID_HANDLE; @@ -506,6 +660,18 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package) /* increment progress bar each time action data is sent */ ui_progress(package,1,1,0,0); + /* handle the keys for the SouceList */ + ptr = strrchrW(package->PackagePath,'\\'); + if (ptr) + { + ptr ++; + MsiSourceListSetInfoW(package->ProductCode, NULL, + MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT, + INSTALLPROPERTY_PACKAGENAMEW, ptr); + } + FIXME("Write DiskPrompt\n"); + /* Pass 1 */ for (index = 0; index < package->loaded_files; index++) { diff --git a/reactos/lib/msi/helpers.c b/reactos/lib/msi/helpers.c index e9e12f12214..f44e339e22e 100644 --- a/reactos/lib/msi/helpers.c +++ b/reactos/lib/msi/helpers.c @@ -40,7 +40,6 @@ static const WCHAR cszTargetDir[] = {'T','A','R','G','E','T','D','I','R',0}; static const WCHAR cszDatabase[]={'D','A','T','A','B','A','S','E',0}; const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0}; -const WCHAR szProductCode[]= {'P','r','o','d','u','c','t','C','o','d','e',0}; const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0}; const WCHAR cszbs[]={'\\',0}; @@ -88,10 +87,8 @@ DWORD build_version_dword(LPCWSTR version_string) UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, LPWSTR *FilePath) { - LPWSTR ProductCode; LPWSTR SystemFolder; LPWSTR dest; - UINT rc; static const WCHAR szInstaller[] = {'M','i','c','r','o','s','o','f','t','\\', @@ -99,20 +96,15 @@ UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, static const WCHAR szFolder[] = {'A','p','p','D','a','t','a','F','o','l','d','e','r',0}; - ProductCode = load_dynamic_property(package,szProductCode,&rc); - if (!ProductCode) - return rc; - SystemFolder = load_dynamic_property(package,szFolder,NULL); - dest = build_directory_name(3, SystemFolder, szInstaller, ProductCode); + dest = build_directory_name(3, SystemFolder, szInstaller, package->ProductCode); create_full_pathW(dest); *FilePath = build_directory_name(2, dest, icon_name); HeapFree(GetProcessHeap(),0,SystemFolder); - HeapFree(GetProcessHeap(),0,ProductCode); HeapFree(GetProcessHeap(),0,dest); return ERROR_SUCCESS; } @@ -576,10 +568,17 @@ void ACTION_free_package_structures( MSIPACKAGE* package) HeapFree(GetProcessHeap(),0,package->script->Actions[i]); } + + for (i = 0; i < package->script->UniqueActionsCount; i++) + HeapFree(GetProcessHeap(),0,package->script->UniqueActions[i]); + + HeapFree(GetProcessHeap(),0,package->script->UniqueActions); HeapFree(GetProcessHeap(),0,package->script); } HeapFree(GetProcessHeap(),0,package->PackagePath); + HeapFree(GetProcessHeap(),0,package->msiFilePath); + HeapFree(GetProcessHeap(),0,package->ProductCode); /* cleanup control event subscriptions */ ControlEvent_CleanupSubscriptions(package); @@ -795,7 +794,6 @@ void reduce_to_shortfilename(WCHAR* filename) LPWSTR create_component_advertise_string(MSIPACKAGE* package, MSICOMPONENT* component, LPCWSTR feature) { - LPWSTR productid=NULL; GUID clsid; WCHAR productid_85[21]; WCHAR component_85[21]; @@ -814,8 +812,7 @@ LPWSTR create_component_advertise_string(MSIPACKAGE* package, memset(productid_85,0,sizeof(productid_85)); memset(component_85,0,sizeof(component_85)); - productid = load_dynamic_property(package,szProductCode,NULL); - CLSIDFromString(productid, &clsid); + CLSIDFromString(package->ProductCode, &clsid); encode_base85_guid(&clsid,productid_85); @@ -840,8 +837,6 @@ LPWSTR create_component_advertise_string(MSIPACKAGE* package, sprintfW(output,fmt2,productid_85,feature,component_85); else sprintfW(output,fmt1,productid_85,feature); - - HeapFree(GetProcessHeap(),0,productid); return output; } @@ -911,3 +906,91 @@ void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature) component->Action, component->ActionRequest); } } + +UINT register_unique_action(MSIPACKAGE *package, LPCWSTR action) +{ + UINT count; + LPWSTR *newbuf = NULL; + + if (!package || !package->script) + return FALSE; + + TRACE("Registering Action %s as having fun\n",debugstr_w(action)); + + count = package->script->UniqueActionsCount; + package->script->UniqueActionsCount++; + if (count != 0) + newbuf = HeapReAlloc(GetProcessHeap(),0, + package->script->UniqueActions, + package->script->UniqueActionsCount* sizeof(LPWSTR)); + else + newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR)); + + newbuf[count] = strdupW(action); + package->script->UniqueActions = newbuf; + + return ERROR_SUCCESS; +} + +BOOL check_unique_action(MSIPACKAGE *package, LPCWSTR action) +{ + INT i; + + if (!package || !package->script) + return FALSE; + + for (i = 0; i < package->script->UniqueActionsCount; i++) + if (!strcmpW(package->script->UniqueActions[i],action)) + return TRUE; + + return FALSE; +} + +WCHAR* generate_error_string(MSIPACKAGE *package, UINT error, DWORD count, ... ) +{ + static const WCHAR query[] = {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ','F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ','`','E','r','r','o','r','`',' ','=',' ','%','i',0}; + + MSIRECORD *rec; + MSIRECORD *row; + DWORD size = 0; + DWORD i; + va_list va; + LPCWSTR str; + LPWSTR data; + + row = MSI_QueryGetRecord(package->db, query, error); + if (!row) + return 0; + + rec = MSI_CreateRecord(count+2); + + str = MSI_RecordGetString(row,1); + MSI_RecordSetStringW(rec,0,str); + msiobj_release( &row->hdr ); + MSI_RecordSetInteger(rec,1,error); + + va_start(va,count); + for (i = 0; i < count; i++) + { + str = va_arg(va,LPCWSTR); + MSI_RecordSetStringW(rec,(i+2),str); + } + va_end(va); + + MSI_FormatRecordW(package,rec,NULL,&size); + if (size >= 0) + { + size++; + data = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR)); + if (size > 1) + MSI_FormatRecordW(package,rec,data,&size); + else + data[0] = 0; + msiobj_release( &rec->hdr ); + return data; + } + + msiobj_release( &rec->hdr ); + data = NULL; + return data; +} diff --git a/reactos/lib/msi/install.c b/reactos/lib/msi/install.c index 9b9ea41dcf7..78f02d0f435 100644 --- a/reactos/lib/msi/install.c +++ b/reactos/lib/msi/install.c @@ -585,3 +585,26 @@ UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPWSTR szComponent, msiobj_release( &package->hdr ); return ret; } + +/*********************************************************************** + * MsiGetLanguage (MSI.@) + */ +LANGID WINAPI MsiGetLanguage(MSIHANDLE hInstall) +{ + MSIPACKAGE* package; + LANGID langid; + LPWSTR buffer; + static const WCHAR szProductLanguage[] = + {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0}; + + package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); + if (!package) + return ERROR_INVALID_HANDLE; + + buffer = load_dynamic_property(package,szProductLanguage,NULL); + langid = atoiW(buffer); + + HeapFree(GetProcessHeap(),0,buffer); + msiobj_release (&package->hdr); + return langid; +} diff --git a/reactos/lib/msi/msi.c b/reactos/lib/msi/msi.c index bec3ccbf05a..cf3bf608d3a 100644 --- a/reactos/lib/msi/msi.c +++ b/reactos/lib/msi/msi.c @@ -83,9 +83,6 @@ UINT WINAPI MsiOpenProductA(LPCSTR szProduct, MSIHANDLE *phProduct) UINT WINAPI MsiOpenProductW(LPCWSTR szProduct, MSIHANDLE *phProduct) { - static const WCHAR szLocalPackage[] = { - 'L','o','c','a','l','P','a','c','k','a','g','e', 0 - }; LPWSTR path = NULL; UINT r; HKEY hKeyProduct = NULL; @@ -102,7 +99,7 @@ UINT WINAPI MsiOpenProductW(LPCWSTR szProduct, MSIHANDLE *phProduct) /* find the size of the path */ type = count = 0; - r = RegQueryValueExW( hKeyProduct, szLocalPackage, + r = RegQueryValueExW( hKeyProduct, INSTALLPROPERTY_LOCALPACKAGEW, NULL, &type, NULL, &count ); if( r != ERROR_SUCCESS ) { @@ -115,7 +112,7 @@ UINT WINAPI MsiOpenProductW(LPCWSTR szProduct, MSIHANDLE *phProduct) if( !path ) goto end; - r = RegQueryValueExW( hKeyProduct, szLocalPackage, + r = RegQueryValueExW( hKeyProduct, INSTALLPROPERTY_LOCALPACKAGEW, NULL, &type, (LPBYTE) path, &count ); if( r != ERROR_SUCCESS ) { @@ -202,6 +199,9 @@ UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine) MSIPACKAGE *package = NULL; UINT r; MSIHANDLE handle; + WCHAR path[MAX_PATH]; + WCHAR filename[MAX_PATH]; + static const WCHAR szMSI[] = {'M','S','I',0}; FIXME("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine)); @@ -209,16 +209,31 @@ UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine) if (r != ERROR_SUCCESS) return r; - r = MSI_OpenPackageW(szPackagePath,&package); + /* copy the msi file to a temp file to pervent locking a CD + * with a multi disc install + */ + GetTempPathW(MAX_PATH, path); + GetTempFileNameW(path, szMSI, 0, filename); + + CopyFileW(szPackagePath, filename, FALSE); + + TRACE("Opening relocated package %s\n",debugstr_w(filename)); + r = MSI_OpenPackageW(filename, &package); if (r != ERROR_SUCCESS) + { + DeleteFileW(filename); return r; + } handle = alloc_msihandle( &package->hdr ); - r = ACTION_DoTopLevelINSTALL(package, szPackagePath, szCommandLine); + r = ACTION_DoTopLevelINSTALL(package, szPackagePath, szCommandLine, + filename); MsiCloseHandle(handle); msiobj_release( &package->hdr ); + + DeleteFileW(filename); return r; } @@ -256,13 +271,9 @@ UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel, MSIHANDLE handle = -1; MSIPACKAGE* package; UINT rc; - HKEY hkey=0,hkey1=0; DWORD sz; - static const WCHAR szSouceList[] = { - 'S','o','u','r','c','e','L','i','s','t',0}; - static const WCHAR szLUS[] = { - 'L','a','s','t','U','s','e','d','S','o','u','r','c','e',0}; - WCHAR sourcepath[0x200]; + WCHAR sourcepath[MAX_PATH]; + WCHAR filename[MAX_PATH]; static const WCHAR szInstalled[] = { ' ','I','n','s','t','a','l','l','e','d','=','1',0}; LPWSTR commandline; @@ -277,20 +288,17 @@ UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel, return ERROR_CALL_NOT_IMPLEMENTED; } - rc = MSIREG_OpenUserProductsKey(szProduct,&hkey,FALSE); - if (rc != ERROR_SUCCESS) - goto end; + sz = sizeof(sourcepath); + MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, + &sz); - rc = RegOpenKeyW(hkey,szSouceList,&hkey1); - if (rc != ERROR_SUCCESS) - goto end; + sz = sizeof(filename); + MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz); - sz = sizeof(sourcepath); - rc = RegQueryValueExW(hkey1, szLUS, NULL, NULL,(LPBYTE)sourcepath, &sz); - if (rc != ERROR_SUCCESS) - goto end; + strcatW(sourcepath,filename); - RegCloseKey(hkey1); /* * ok 1, we need to find the msi file for this product. * 2, find the source dir for the files @@ -324,13 +332,12 @@ UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel, if (MsiQueryProductStateW(szProduct) != INSTALLSTATE_UNKNOWN) lstrcatW(commandline,szInstalled); - rc = ACTION_DoTopLevelINSTALL(package, sourcepath, commandline); + rc = ACTION_DoTopLevelINSTALL(package, sourcepath, commandline, sourcepath); msiobj_release( &package->hdr ); HeapFree(GetProcessHeap(),0,commandline); end: - RegCloseKey(hkey); if (handle != -1) MsiCloseHandle(handle); @@ -509,16 +516,8 @@ UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, { MSIHANDLE hProduct; UINT r; - static const WCHAR szPackageCode[] = - {'P','a','c','k','a','g','e','C','o','d','e',0}; - static const WCHAR szVersionString[] = - {'V','e','r','s','i','o','n','S','t','r','i','n','g',0}; static const WCHAR szProductVersion[] = {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0}; - static const WCHAR szAssignmentType[] = - {'A','s','s','i','g','n','m','e','n','t','T','y','p','e',0}; - static const WCHAR szLanguage[] = - {'L','a','n','g','u','a','g','e',0}; static const WCHAR szProductLanguage[] = {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0}; @@ -531,7 +530,7 @@ UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, return ERROR_INVALID_PARAMETER; /* check for special properties */ - if (strcmpW(szAttribute, szPackageCode)==0) + if (strcmpW(szAttribute, INSTALLPROPERTY_PACKAGECODEW)==0) { HKEY hkey; WCHAR squished[GUID_SIZE]; @@ -542,7 +541,7 @@ UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, if (r != ERROR_SUCCESS) return ERROR_UNKNOWN_PRODUCT; - r = RegQueryValueExW(hkey, szPackageCode, NULL, NULL, + r = RegQueryValueExW(hkey, INSTALLPROPERTY_PACKAGECODEW, NULL, NULL, (LPBYTE)squished, &sz); if (r != ERROR_SUCCESS) { @@ -563,7 +562,7 @@ UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, RegCloseKey(hkey); r = ERROR_SUCCESS; } - else if (strcmpW(szAttribute, szVersionString)==0) + else if (strcmpW(szAttribute, INSTALLPROPERTY_VERSIONSTRINGW)==0) { r = MsiOpenProductW(szProduct, &hProduct); if (ERROR_SUCCESS != r) @@ -572,7 +571,7 @@ UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, r = MsiGetPropertyW(hProduct, szProductVersion, szBuffer, pcchValueBuf); MsiCloseHandle(hProduct); } - else if (strcmpW(szAttribute, szAssignmentType)==0) + else if (strcmpW(szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW)==0) { FIXME("0 (zero) if advertised or per user , 1(one) if per machine.\n"); if (szBuffer) @@ -584,7 +583,7 @@ UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, *pcchValueBuf = 1; r = ERROR_SUCCESS; } - else if (strcmpW(szAttribute, szLanguage)==0) + else if (strcmpW(szAttribute, INSTALLPROPERTY_LANGUAGEW)==0) { r = MsiOpenProductW(szProduct, &hProduct); if (ERROR_SUCCESS != r) @@ -835,14 +834,14 @@ LANGID WINAPI MsiLoadStringA( MSIHANDLE handle, UINT id, LPSTR lpBuffer, INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf, DWORD *pcchBuf) { - FIXME("%s %p %08lx\n", debugstr_a(szComponent), lpPathBuf, *pcchBuf); + FIXME("%s %p %p\n", debugstr_a(szComponent), lpPathBuf, pcchBuf); return INSTALLSTATE_UNKNOWN; } INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf, DWORD *pcchBuf) { - FIXME("%s %p %08lx\n", debugstr_w(szComponent), lpPathBuf, *pcchBuf); + FIXME("%s %p %p\n", debugstr_w(szComponent), lpPathBuf, pcchBuf); return INSTALLSTATE_UNKNOWN; } @@ -1569,9 +1568,6 @@ USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct, LPWSTR lpUserNameBuf, HKEY hkey; DWORD sz; UINT rc = ERROR_SUCCESS,rc2 = ERROR_SUCCESS; - static const WCHAR szOwner[] = {'R','e','g','O','w','n','e','r',0}; - static const WCHAR szCompany[] = {'R','e','g','C','o','m','p','a','n','y',0}; - static const WCHAR szSerial[] = {'P','r','o','d','u','c','t','I','D',0}; TRACE("%s %p %p %p %p %p %p\n",debugstr_w(szProduct), lpUserNameBuf, pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf, @@ -1584,13 +1580,15 @@ USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct, LPWSTR lpUserNameBuf, if (lpUserNameBuf) { sz = *lpUserNameBuf * sizeof(WCHAR); - rc = RegQueryValueExW( hkey, szOwner, NULL, NULL, (LPBYTE)lpUserNameBuf, + rc = RegQueryValueExW( hkey, INSTALLPROPERTY_REGOWNERW, NULL, + NULL, (LPBYTE)lpUserNameBuf, &sz); } if (!lpUserNameBuf && pcchUserNameBuf) { sz = 0; - rc = RegQueryValueExW( hkey, szOwner, NULL, NULL, NULL, &sz); + rc = RegQueryValueExW( hkey, INSTALLPROPERTY_REGOWNERW, NULL, + NULL, NULL, &sz); } if (pcchUserNameBuf) @@ -1599,13 +1597,14 @@ USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct, LPWSTR lpUserNameBuf, if (lpOrgNameBuf) { sz = *pcchOrgNameBuf * sizeof(WCHAR); - rc2 = RegQueryValueExW( hkey, szCompany, NULL, NULL, - (LPBYTE)lpOrgNameBuf, &sz); + rc2 = RegQueryValueExW( hkey, INSTALLPROPERTY_REGCOMPANYW, NULL, + NULL, (LPBYTE)lpOrgNameBuf, &sz); } if (!lpOrgNameBuf && pcchOrgNameBuf) { sz = 0; - rc2 = RegQueryValueExW( hkey, szCompany, NULL, NULL, NULL, &sz); + rc2 = RegQueryValueExW( hkey, INSTALLPROPERTY_REGCOMPANYW, NULL, + NULL, NULL, &sz); } if (pcchOrgNameBuf) @@ -1621,13 +1620,14 @@ USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct, LPWSTR lpUserNameBuf, if (lpSerialBuf) { sz = *pcchSerialBuf * sizeof(WCHAR); - RegQueryValueExW( hkey, szSerial, NULL, NULL, (LPBYTE)lpSerialBuf, - &sz); + RegQueryValueExW( hkey, INSTALLPROPERTY_PRODUCTIDW, NULL, NULL, + (LPBYTE)lpSerialBuf, &sz); } if (!lpSerialBuf && pcchSerialBuf) { sz = 0; - rc = RegQueryValueExW( hkey, szSerial, NULL, NULL, NULL, &sz); + rc = RegQueryValueExW( hkey, INSTALLPROPERTY_PRODUCTIDW, NULL, + NULL, NULL, &sz); } if (pcchSerialBuf) *pcchSerialBuf = sz / sizeof(WCHAR); diff --git a/reactos/lib/msi/msi.spec b/reactos/lib/msi/msi.spec index ecb7621ff39..1cd59449ec6 100644 --- a/reactos/lib/msi/msi.spec +++ b/reactos/lib/msi/msi.spec @@ -60,7 +60,7 @@ 60 stdcall MsiGetFeatureUsageW(wstr wstr ptr ptr) 61 stub MsiGetFeatureValidStatesA 62 stub MsiGetFeatureValidStatesW -63 stub MsiGetLanguage +63 stdcall MsiGetLanguage(long) 64 stdcall MsiGetMode(long long) 65 stdcall MsiGetProductCodeA(str str) 66 stdcall MsiGetProductCodeW(wstr wstr) diff --git a/reactos/lib/msi/msi.xml b/reactos/lib/msi/msi.xml index 81bb068d370..ed7fdd280b4 100644 --- a/reactos/lib/msi/msi.xml +++ b/reactos/lib/msi/msi.xml @@ -47,6 +47,7 @@ registry.c regsvr.c select.c + source.c sql.tab.c string.c suminfo.c diff --git a/reactos/lib/msi/msipriv.h b/reactos/lib/msi/msipriv.h index dde612992fe..eaef4f50883 100644 --- a/reactos/lib/msi/msipriv.h +++ b/reactos/lib/msi/msipriv.h @@ -55,7 +55,7 @@ struct tagMSIOBJECTHDR { UINT magic; UINT type; - DWORD refcount; + LONG refcount; msihandledestructor destructor; struct tagMSIOBJECTHDR *next; struct tagMSIOBJECTHDR *prev; @@ -216,6 +216,8 @@ typedef struct tagMSIPACKAGE UINT RunningActionCount; LPWSTR PackagePath; + LPWSTR msiFilePath; + LPWSTR ProductCode; UINT CurrentInstallState; msi_dialog *dialog; @@ -281,8 +283,8 @@ extern HRESULT init_string_table( IStorage *stg ); /* string table functions */ -extern BOOL msi_addstring( string_table *st, int string_no, const CHAR *data, int len, UINT refcount ); -extern BOOL msi_addstringW( string_table *st, int string_no, const WCHAR *data, int len, UINT refcount ); +extern BOOL msi_addstring( string_table *st, UINT string_no, const CHAR *data, int len, UINT refcount ); +extern BOOL msi_addstringW( string_table *st, UINT string_no, const WCHAR *data, int len, UINT refcount ); extern UINT msi_id2stringW( string_table *st, UINT string_no, LPWSTR buffer, UINT *sz ); extern UINT msi_id2stringA( string_table *st, UINT string_no, LPSTR buffer, UINT *sz ); @@ -307,7 +309,7 @@ extern UINT read_raw_stream_data( MSIDATABASE*, LPCWSTR stname, USHORT **pdata, UINT *psz ); /* action internals */ -extern UINT ACTION_DoTopLevelINSTALL( MSIPACKAGE *, LPCWSTR, LPCWSTR ); +extern UINT ACTION_DoTopLevelINSTALL( MSIPACKAGE *, LPCWSTR, LPCWSTR, LPCWSTR ); extern void ACTION_free_package_structures( MSIPACKAGE* ); extern UINT ACTION_DialogBox( MSIPACKAGE*, LPCWSTR); diff --git a/reactos/lib/msi/package.c b/reactos/lib/msi/package.c index 54a692452eb..d3114df8f10 100644 --- a/reactos/lib/msi/package.c +++ b/reactos/lib/msi/package.c @@ -408,6 +408,8 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage) MSIDATABASE *db = NULL; MSIPACKAGE *package; MSIHANDLE handle; + DWORD size; + static const WCHAR szProductCode[]= {'P','r','o','d','u','c','t','C','o','d','e',0}; TRACE("%s %p\n", debugstr_w(szPackage), pPackage); @@ -445,6 +447,13 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage) MSI_SetPropertyW( package, Database, szPackage ); } + /* this property must exist */ + size = 0; + MSI_GetPropertyW(package,szProductCode,NULL,&size); + size ++; + package->ProductCode = HeapAlloc(GetProcessHeap(),0,size * sizeof(WCHAR)); + MSI_GetPropertyW(package,szProductCode,package->ProductCode, &size); + *pPackage = package; return ERROR_SUCCESS; @@ -454,18 +463,40 @@ UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phP { MSIPACKAGE *package = NULL; UINT ret; + WCHAR path[MAX_PATH]; + WCHAR filename[MAX_PATH]; + static const WCHAR szMSI[] = {'M','S','I',0}; TRACE("%s %08lx %p\n",debugstr_w(szPackage), dwOptions, phPackage); + /* copy the msi file to a temp file to pervent locking a CD + * with a multi disc install + */ + if( szPackage[0] == '#' ) + strcpyW(filename,szPackage); + else + { + GetTempPathW(MAX_PATH, path); + GetTempFileNameW(path, szMSI, 0, filename); + + CopyFileW(szPackage, filename, FALSE); + + TRACE("Opening relocated package %s\n",debugstr_w(filename)); + } + if( dwOptions ) FIXME("dwOptions %08lx not supported\n", dwOptions); - ret = MSI_OpenPackageW( szPackage, &package); + ret = MSI_OpenPackageW( filename, &package); if( ret == ERROR_SUCCESS ) { *phPackage = alloc_msihandle( &package->hdr ); msiobj_release( &package->hdr ); } + + if( szPackage[0] != '#' ) + DeleteFileW(filename); + return ret; } @@ -862,6 +893,10 @@ UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf, if (NULL != szValueBuf && NULL == pchValueBuf) return ERROR_INVALID_PARAMETER; + /* This was tested against native msi */ + if (NULL == szValueBuf && NULL != pchValueBuf) + *pchValueBuf = 0; + package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); if (!package) return ERROR_INVALID_HANDLE; @@ -889,6 +924,10 @@ UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName, if (NULL != szValueBuf && NULL == pchValueBuf) return ERROR_INVALID_PARAMETER; + /* This was tested against native msi */ + if (NULL == szValueBuf && NULL != pchValueBuf) + *pchValueBuf = 0; + package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); if (!package) return ERROR_INVALID_HANDLE; diff --git a/reactos/lib/msi/registry.c b/reactos/lib/msi/registry.c index 012986115c2..c96a766fcfa 100644 --- a/reactos/lib/msi/registry.c +++ b/reactos/lib/msi/registry.c @@ -873,9 +873,18 @@ UINT WINAPI MsiEnumComponentQualifiersW( LPWSTR szComponent, DWORD iIndex, rc = RegEnumValueW(key, iIndex, lpQualifierBuf, pcchQualifierBuf, NULL, NULL, (LPBYTE)full_buffer, &full_buffer_size); + if (rc == ERROR_MORE_DATA) + { + HeapFree(GetProcessHeap(),0,full_buffer); + full_buffer_size+=sizeof(WCHAR); + full_buffer = HeapAlloc(GetProcessHeap(),0,full_buffer_size); + rc = RegEnumValueW(key, iIndex, lpQualifierBuf, pcchQualifierBuf, NULL, + NULL, (LPBYTE)full_buffer, &full_buffer_size); + } + RegCloseKey(key); - if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA) + if (rc == ERROR_SUCCESS) { if (lpApplicationDataBuf && pcchApplicationDataBuf) { @@ -898,6 +907,8 @@ UINT WINAPI MsiEnumComponentQualifiersW( LPWSTR szComponent, DWORD iIndex, debugstr_w(lpApplicationDataBuf)); } + HeapFree(GetProcessHeap(),0,full_buffer); + return rc; } diff --git a/reactos/lib/msi/source.c b/reactos/lib/msi/source.c new file mode 100644 index 00000000000..136d492fa48 --- /dev/null +++ b/reactos/lib/msi/source.c @@ -0,0 +1,560 @@ +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2005 Aric Stewart for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#define COBJMACROS +#define NONAMELESSUNION + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winnls.h" +#include "shlwapi.h" +#include "wine/debug.h" +#include "msi.h" +#include "msiquery.h" +#include "msipriv.h" +#include "wincrypt.h" +#include "winver.h" +#include "winuser.h" +#include "wine/unicode.h" +#include "action.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +/* + * These apis are defined in MSI 3.0 + */ + +typedef struct tagMediaInfo +{ + LPWSTR path; + WCHAR szIndex[10]; + WCHAR type; +} media_info; + +static UINT OpenSourceKey(LPCWSTR szProduct, HKEY* key, BOOL user, BOOL create) +{ + HKEY rootkey = 0; + UINT rc; + static const WCHAR szSourceList[] = {'S','o','u','r','c','e','L','i','s','t',0}; + + if (user) + rc = MSIREG_OpenUserProductsKey(szProduct, &rootkey, create); + else + rc = MSIREG_OpenProductsKey(szProduct, &rootkey, create); + + if (rc) + return rc; + + if (create) + rc = RegCreateKeyW(rootkey, szSourceList, key); + else + rc = RegOpenKeyW(rootkey,szSourceList, key); + + return rc; +} + +static UINT OpenMediaSubkey(HKEY rootkey, HKEY *key, BOOL create) +{ + UINT rc; + static const WCHAR media[] = {'M','e','d','i','a',0}; + + if (create) + rc = RegCreateKeyW(rootkey, media, key); + else + rc = RegOpenKeyW(rootkey,media, key); + + return rc; +} + +static UINT OpenNetworkSubkey(HKEY rootkey, HKEY *key, BOOL create) +{ + UINT rc; + static const WCHAR net[] = {'N','e','t',0}; + + if (create) + rc = RegCreateKeyW(rootkey, net, key); + else + rc = RegOpenKeyW(rootkey, net, key); + + return rc; +} + +static UINT OpenURLSubkey(HKEY rootkey, HKEY *key, BOOL create) +{ + UINT rc; + static const WCHAR URL[] = {'U','R','L',0}; + + if (create) + rc = RegCreateKeyW(rootkey, URL, key); + else + rc = RegOpenKeyW(rootkey, URL, key); + + return rc; +} + + +static UINT find_given_source(HKEY key, LPCWSTR szSource, media_info *ss) +{ + DWORD index = 0; + WCHAR szIndex[10]; + DWORD size; + DWORD val_size; + LPWSTR val; + UINT rc = ERROR_SUCCESS; + + while (rc == ERROR_SUCCESS) + { + val = NULL; + val_size = 0; + rc = RegEnumValueW(key, index, szIndex, &size, NULL, NULL, NULL, &val_size); + if (rc != ERROR_NO_MORE_ITEMS) + { + val = HeapAlloc(GetProcessHeap(),0,val_size); + RegEnumValueW(key, index, szIndex, &size, NULL, NULL, (LPBYTE)val, + &val_size); + if (lstrcmpiW(szSource,val)==0) + { + ss->path = val; + strcpyW(ss->szIndex,szIndex); + break; + } + else + strcpyW(ss->szIndex,szIndex); + + HeapFree(GetProcessHeap(),0,val); + index ++; + } + } + return rc; +} + +/****************************************************************** + * MsiSourceListGetInfoW (MSI.@) + */ +UINT WINAPI MsiSourceListGetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid, + MSIINSTALLCONTEXT dwContext, DWORD dwOptions, + LPCWSTR szProperty, LPWSTR szValue, + LPDWORD pcchValue) +{ + HKEY sourcekey; + UINT rc; + + TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szProperty)); + + if (!szProduct || lstrlenW(szProduct) > 39) + return ERROR_INVALID_PARAMETER; + + if (szValue && !pcchValue) + return ERROR_INVALID_PARAMETER; + + if (dwOptions == MSICODE_PATCH) + { + FIXME("Unhandled options MSICODE_PATCH\n"); + return ERROR_FUNCTION_FAILED; + } + + if (szUserSid) + FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid)); + + if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED) + FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n"); + + if (dwContext == MSIINSTALLCONTEXT_MACHINE) + rc = OpenSourceKey(szProduct, &sourcekey, FALSE, FALSE); + else + rc = OpenSourceKey(szProduct, &sourcekey, TRUE, FALSE); + + if (rc != ERROR_SUCCESS) + return ERROR_UNKNOWN_PRODUCT; + + if (strcmpW(szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW) == 0) + { + HKEY key; + rc = OpenMediaSubkey(sourcekey, &key, FALSE); + if (rc == ERROR_SUCCESS) + rc = RegQueryValueExW(key, INSTALLPROPERTY_MEDIAPACKAGEPATHW, + 0, 0, (LPBYTE)szValue, pcchValue); + if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA) + rc = ERROR_UNKNOWN_PROPERTY; + RegCloseKey(key); + } + else if (strcmpW(szProperty, INSTALLPROPERTY_DISKPROMPTW) ==0) + { + HKEY key; + rc = OpenMediaSubkey(sourcekey, &key, FALSE); + if (rc == ERROR_SUCCESS) + rc = RegQueryValueExW(key, INSTALLPROPERTY_DISKPROMPTW, 0, 0, + (LPBYTE)szValue, pcchValue); + if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA) + rc = ERROR_UNKNOWN_PROPERTY; + RegCloseKey(key); + } + else if (strcmpW(szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW)==0) + { + LPWSTR buffer; + DWORD size = 0; + + RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0, 0, + NULL, &size); + if (size == 0) + rc = ERROR_UNKNOWN_PROPERTY; + else + { + LPWSTR ptr; + buffer = HeapAlloc(GetProcessHeap(),0,size); + rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, + 0, 0, (LPBYTE)buffer,&size); + ptr = strchrW(buffer,';'); + if (ptr) ptr = strchrW(ptr+1,';'); + if (!ptr) + rc = ERROR_UNKNOWN_PROPERTY; + else + { + ptr ++; + lstrcpynW(szValue, ptr, *pcchValue); + if (lstrlenW(ptr) > *pcchValue) + { + *pcchValue = lstrlenW(ptr)+1; + rc = ERROR_MORE_DATA; + } + else + rc = ERROR_SUCCESS; + } + HeapFree(GetProcessHeap(),0,buffer); + } + } + else if (strcmpW(INSTALLPROPERTY_LASTUSEDTYPEW, szProperty)==0) + { + LPWSTR buffer; + DWORD size = 0; + + RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0, 0, + NULL, &size); + if (size == 0) + rc = ERROR_UNKNOWN_PROPERTY; + else + { + buffer = HeapAlloc(GetProcessHeap(),0,size); + rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, + 0, 0, (LPBYTE)buffer,&size); + if (*pcchValue < 1) + { + rc = ERROR_MORE_DATA; + *pcchValue = 1; + } + else + { + szValue[0] = buffer[0]; + rc = ERROR_SUCCESS; + } + HeapFree(GetProcessHeap(),0,buffer); + } + } + else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW, szProperty)==0) + { + rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0, 0, + (LPBYTE)szValue, pcchValue); + if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA) + rc = ERROR_UNKNOWN_PROPERTY; + } + else + { + FIXME("Unknown property %s\n",debugstr_w(szProperty)); + rc = ERROR_UNKNOWN_PROPERTY; + } + + RegCloseKey(sourcekey); + return rc; +} + +/****************************************************************** + * MsiSourceListSetInfoW (MSI.@) + */ +UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid, + MSIINSTALLCONTEXT dwContext, DWORD dwOptions, + LPCWSTR szProperty, LPCWSTR szValue) +{ + HKEY sourcekey; + UINT rc; + + TRACE("%s %s %x %lx %s %s\n", debugstr_w(szProduct), debugstr_w(szUserSid), + dwContext, dwOptions, debugstr_w(szProperty), debugstr_w(szValue)); + + if (!szProduct || lstrlenW(szProduct) > 39) + return ERROR_INVALID_PARAMETER; + + if (dwOptions & MSICODE_PATCH) + { + FIXME("Unhandled options MSICODE_PATCH\n"); + return ERROR_FUNCTION_FAILED; + } + + if (szUserSid) + FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid)); + + if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED) + FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n"); + + if (dwContext == MSIINSTALLCONTEXT_MACHINE) + rc = OpenSourceKey(szProduct, &sourcekey, FALSE, TRUE); + else + rc = OpenSourceKey(szProduct, &sourcekey, TRUE, TRUE); + + if (rc != ERROR_SUCCESS) + return ERROR_UNKNOWN_PRODUCT; + + + if (strcmpW(szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW) == 0) + { + HKEY key; + DWORD size = lstrlenW(szValue)*sizeof(WCHAR); + rc = OpenMediaSubkey(sourcekey, &key, FALSE); + if (rc == ERROR_SUCCESS) + rc = RegSetValueExW(key, INSTALLPROPERTY_MEDIAPACKAGEPATHW, 0, + REG_SZ, (LPBYTE)szValue, size); + if (rc != ERROR_SUCCESS) + rc = ERROR_UNKNOWN_PROPERTY; + RegCloseKey(key); + } + else if (strcmpW(szProperty, INSTALLPROPERTY_DISKPROMPTW) == 0) + { + HKEY key; + DWORD size = lstrlenW(szValue)*sizeof(WCHAR); + rc = OpenMediaSubkey(sourcekey, &key, FALSE); + if (rc == ERROR_SUCCESS) + rc = RegSetValueExW(key, INSTALLPROPERTY_DISKPROMPTW, 0, + REG_SZ, (LPBYTE)szValue, size); + if (rc != ERROR_SUCCESS) + rc = ERROR_UNKNOWN_PROPERTY; + RegCloseKey(key); + } + else if (strcmpW(szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW)==0) + { + LPWSTR buffer = NULL; + DWORD size; + WCHAR typechar = 'n'; + static const WCHAR LastUsedSource_Fmt[] = {'%','c',';','%','i',';','%','s',0}; + + /* make sure the source is registered */ + MsiSourceListAddSourceExW(szProduct, szUserSid, dwContext, + dwOptions, szValue, 0); + + if (dwOptions & MSISOURCETYPE_NETWORK) + typechar = 'n'; + else if (dwOptions & MSISOURCETYPE_URL) + typechar = 'u'; + else if (dwOptions & MSISOURCETYPE_MEDIA) + typechar = 'm'; + else + ERR("Unknown source type! 0x%lx\n",dwOptions); + + size = (lstrlenW(szValue)+5)*sizeof(WCHAR); + buffer = HeapAlloc(GetProcessHeap(),0,size); + sprintfW(buffer, LastUsedSource_Fmt, typechar, 1, szValue); + rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0, + REG_EXPAND_SZ, (LPBYTE)buffer, size); + if (rc != ERROR_SUCCESS) + rc = ERROR_UNKNOWN_PROPERTY; + HeapFree( GetProcessHeap(), 0, buffer ); + } + else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW, szProperty)==0) + { + DWORD size = lstrlenW(szValue)*sizeof(WCHAR); + rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0, + REG_SZ, (LPBYTE)szValue, size); + if (rc != ERROR_SUCCESS) + rc = ERROR_UNKNOWN_PROPERTY; + } + else + { + FIXME("Unknown property %s\n",debugstr_w(szProperty)); + rc = ERROR_UNKNOWN_PROPERTY; + } + + RegCloseKey(sourcekey); + return rc; + +} + +/****************************************************************** + * MsiSourceListAddSourceExW (MSI.@) + */ +UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid, + MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szSource, + DWORD dwIndex) +{ + HKEY sourcekey; + HKEY typekey; + UINT rc; + media_info source_struct; + + TRACE("%s, %s, %x, %lx, %s, %li\n", debugstr_w(szProduct), + debugstr_w(szUserSid), dwContext, dwOptions, debugstr_w(szSource), + dwIndex); + + if (!szProduct) + return ERROR_INVALID_PARAMETER; + + if (!szSource) + return ERROR_INVALID_PARAMETER; + + if (dwOptions & MSICODE_PATCH) + { + FIXME("Unhandled options MSICODE_PATCH\n"); + return ERROR_FUNCTION_FAILED; + } + + if (szUserSid) + FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid)); + + if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED) + FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n"); + + if (dwContext == MSIINSTALLCONTEXT_MACHINE) + rc = OpenSourceKey(szProduct, &sourcekey, FALSE, TRUE); + else + rc = OpenSourceKey(szProduct, &sourcekey, TRUE, TRUE); + + if (rc != ERROR_SUCCESS) + return ERROR_UNKNOWN_PRODUCT; + + if (dwOptions & MSISOURCETYPE_NETWORK) + rc = OpenNetworkSubkey(sourcekey, &typekey, TRUE); + else if (dwOptions & MSISOURCETYPE_URL) + rc = OpenURLSubkey(sourcekey, &typekey, TRUE); + else + { + ERR("Unknown media type!\n"); + RegCloseKey(sourcekey); + return ERROR_FUNCTION_FAILED; + } + + source_struct.szIndex[0] = 0; + if (find_given_source(typekey, szSource, &source_struct)==ERROR_SUCCESS) + { + DWORD current_index = atoiW(source_struct.szIndex); + /* found the source */ + if (dwIndex > 0 && current_index != dwIndex) + FIXME("Need to reorder the souces! UNHANDLED\n"); + } + else + { + DWORD current_index = 0; + static const WCHAR fmt[] = {'%','i',0}; + DWORD size = lstrlenW(szSource)*sizeof(WCHAR); + + if (source_struct.szIndex[0]) + current_index = atoiW(source_struct.szIndex); + /* new source */ + if (dwIndex > 0 && dwIndex < current_index) + FIXME("Need to reorder the souces! UNHANDLED\n"); + + current_index ++; + sprintfW(source_struct.szIndex,fmt,current_index); + rc = RegSetValueExW(typekey, source_struct.szIndex, 0, REG_EXPAND_SZ, + (LPBYTE)szSource, size); + } + + RegCloseKey(typekey); + RegCloseKey(sourcekey); + return rc; +} + +/****************************************************************** + * MsiSourceListAddMediaDisk(MSI.@) + */ +UINT WINAPI MsiSourceListAddMediaDiskW(LPCWSTR szProduct, LPCWSTR szUserSid, + MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId, + LPCWSTR szVolumeLabel, LPCWSTR szDiskPrompt) +{ + HKEY sourcekey; + HKEY mediakey; + UINT rc; + WCHAR szIndex[10]; + static const WCHAR fmt[] = {'%','i',0}; + static const WCHAR disk_fmt[] = {'%','s',';','%','s',0}; + static const WCHAR empty[1] = {0}; + LPCWSTR pt1,pt2; + LPWSTR buffer; + DWORD size; + + TRACE("%s %s %x %lx %li %s %s\n", debugstr_w(szProduct), + debugstr_w(szUserSid), dwContext, dwOptions, dwDiskId, + debugstr_w(szVolumeLabel), debugstr_w(szDiskPrompt)); + + if (!szProduct || lstrlenW(szProduct) > 39) + return ERROR_INVALID_PARAMETER; + + if (dwOptions & MSICODE_PATCH) + { + FIXME("Unhandled options MSICODE_PATCH\n"); + return ERROR_FUNCTION_FAILED; + } + + if (szUserSid) + FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid)); + + if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED) + FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n"); + + if (dwContext == MSIINSTALLCONTEXT_MACHINE) + rc = OpenSourceKey(szProduct, &sourcekey, FALSE, TRUE); + else + rc = OpenSourceKey(szProduct, &sourcekey, TRUE, TRUE); + + if (rc != ERROR_SUCCESS) + return ERROR_UNKNOWN_PRODUCT; + + OpenMediaSubkey(sourcekey,&mediakey,TRUE); + + sprintfW(szIndex,fmt,dwDiskId); + + size = 2; + if (szVolumeLabel) + { + size +=lstrlenW(szVolumeLabel); + pt1 = szVolumeLabel; + } + else + pt1 = empty; + if (szDiskPrompt) + { + size +=lstrlenW(szDiskPrompt); + pt2 = szDiskPrompt; + } + else + pt2 = empty; + + size *=sizeof(WCHAR); + + buffer = HeapAlloc(GetProcessHeap(),0,size); + sprintfW(buffer,disk_fmt,pt1,pt2); + + RegSetValueExW(mediakey, szIndex, 0, REG_SZ, (LPBYTE)buffer, size); + HeapFree( GetProcessHeap(), 0, buffer ); + + RegCloseKey(sourcekey); + RegCloseKey(mediakey); + + return ERROR_SUCCESS; +} diff --git a/reactos/lib/msi/string.c b/reactos/lib/msi/string.c index 4222894c58a..62a73310e07 100644 --- a/reactos/lib/msi/string.c +++ b/reactos/lib/msi/string.c @@ -142,7 +142,7 @@ static void st_mark_entry_used( string_table *st, UINT n ) st->freeslot = n + 1; } -int msi_addstring( string_table *st, int n, const CHAR *data, int len, UINT refcount ) +int msi_addstring( string_table *st, UINT n, const CHAR *data, int len, UINT refcount ) { int sz; @@ -190,7 +190,7 @@ int msi_addstring( string_table *st, int n, const CHAR *data, int len, UINT refc return n; } -int msi_addstringW( string_table *st, int n, const WCHAR *data, int len, UINT refcount ) +int msi_addstringW( string_table *st, UINT n, const WCHAR *data, int len, UINT refcount ) { /* TRACE("[%2d] = %s\n", string_no, debugstr_an(data,len) ); */ diff --git a/reactos/lib/msi/suminfo.c b/reactos/lib/msi/suminfo.c index cd507f2c082..f7692a4c828 100644 --- a/reactos/lib/msi/suminfo.c +++ b/reactos/lib/msi/suminfo.c @@ -333,7 +333,7 @@ static DWORD write_string( LPBYTE data, DWORD ofs, LPCSTR str ) DWORD len = lstrlenA( str ) + 1; write_dword( data, ofs, len ); if( data ) - lstrcpyA( &data[ofs + 4], str ); + memcpy( &data[ofs + 4], str, len ); return (7 + len) & ~3; } diff --git a/reactos/lib/msi/upgrade.c b/reactos/lib/msi/upgrade.c index 7a066ca621a..e96a8e4aadc 100644 --- a/reactos/lib/msi/upgrade.c +++ b/reactos/lib/msi/upgrade.c @@ -136,10 +136,6 @@ static UINT ITERATE_FindRelatedProducts(MSIRECORD *rec, LPVOID param) DWORD sz = 0x100; HKEY hukey; INT r; - static const WCHAR szVersion[] = - {'V','e','r','s','i','o','n',0}; - static const WCHAR szLanguage[] = - {'L','a','n','g','u','a','g','e',0}; unsquash_guid(product,productid); rc = MSIREG_OpenUserProductsKey(productid, &hukey, FALSE); @@ -151,8 +147,8 @@ static UINT ITERATE_FindRelatedProducts(MSIRECORD *rec, LPVOID param) } sz = sizeof(DWORD); - RegQueryValueExW(hukey, szVersion, NULL, NULL, (LPBYTE)&check, - &sz); + RegQueryValueExW(hukey, INSTALLPROPERTY_VERSIONW, NULL, NULL, + (LPBYTE)&check, &sz); /* check min */ ver = MSI_RecordGetString(rec,2); comp_ver = build_version_dword(ver); @@ -179,8 +175,8 @@ static UINT ITERATE_FindRelatedProducts(MSIRECORD *rec, LPVOID param) /* check language*/ sz = sizeof(DWORD); - RegQueryValueExW(hukey, szLanguage, NULL, NULL, (LPBYTE)&check, - &sz); + RegQueryValueExW(hukey, INSTALLPROPERTY_LANGUAGEW, NULL, NULL, + (LPBYTE)&check, &sz); RegCloseKey(hukey); language = MSI_RecordGetString(rec,4); TRACE("Checking languages 0x%lx and %s\n", check, @@ -211,12 +207,14 @@ UINT ACTION_FindRelatedProducts(MSIPACKAGE *package) UINT rc = ERROR_SUCCESS; MSIQUERY *view; - if (package->script && package->script->FindRelatedProductsRun) + if (check_unique_action(package,szFindRelatedProducts)) + { + TRACE("Skipping FindRelatedProducts action: already done on client side\n"); return ERROR_SUCCESS; + } + else + register_unique_action(package,szFindRelatedProducts); - if (package->script) - package->script->FindRelatedProductsRun = TRUE; - rc = MSI_DatabaseOpenViewW(package->db, Query, &view); if (rc != ERROR_SUCCESS) return ERROR_SUCCESS; diff --git a/reactos/w32api/include/msi.h b/reactos/w32api/include/msi.h index 1c1278272c4..38e37251f99 100644 --- a/reactos/w32api/include/msi.h +++ b/reactos/w32api/include/msi.h @@ -148,8 +148,192 @@ typedef enum tagINSTALLTYPE INSTALLTYPE_NETWORK_IMAGE = 1 } INSTALLTYPE; +typedef enum tagMSIINSTALLCONTEXT +{ + MSIINSTALLCONTEXT_FIRSTVISIBLE = 0, + MSIINSTALLCONTEXT_NONE = 0, + MSIINSTALLCONTEXT_USERMANAGED = 1, + MSIINSTALLCONTEXT_USERUNMANAGED = 2, + MSIINSTALLCONTEXT_MACHINE = 4, + MSIINSTALLCONTEXT_ALL = (MSIINSTALLCONTEXT_USERMANAGED | MSIINSTALLCONTEXT_USERUNMANAGED | MSIINSTALLCONTEXT_MACHINE), + MSIINSTALLCONTEXT_ALLUSERMANAGED= 8, +} MSIINSTALLCONTEXT; + +typedef enum tagMSISOURCETYPE +{ + MSISOURCETYPE_UNKNOWN = 0x00000000L, + MSISOURCETYPE_NETWORK = 0x00000001L, + MSISOURCETYPE_URL = 0x00000002L, + MSISOURCETYPE_MEDIA = 0x00000004 +} MSISOURCETYPE; + +typedef enum tagMSICODE +{ + MSICODE_PRODUCT = 0x00000000L, + MSICODE_PATCH = 0x40000000L +} MSICODE; + #define MAX_FEATURE_CHARS 38 +/* Strings defined in msi.h */ +/* Advertised Information */ + +#define INSTALLPROPERTY_PACKAGENAMEA "PackageName" +static const WCHAR INSTALLPROPERTY_PACKAGENAMEW[] = {'P','a','c','k','a','g','e','N','a','m','e',0}; +#define INSTALLPROPERTY_PACKAGENAME WINELIB_NAME_AW(INSTALLPROPERTY_PACKAGENAME) + +#define INSTALLPROPERTY_TRANSFORMSA "Transforms" +static const WCHAR INSTALLPROPERTY_TRANSFORMSW[] = {'T','r','a','n','s','f','o','r','m','s',0}; +#define INSTALLPROPERTY_TRANSFORMS WINELIB_NAME_AW(INSTALLPROPERTY_TRANSFORMS) + +#define INSTALLPROPERTY_LANGUAGEA "Language" +static const WCHAR INSTALLPROPERTY_LANGUAGEW[] = {'L','a','n','g','u','a','g','e',0}; +#define INSTALLPROPERTY_LANGUAGE WINELIB_NAME_AW(INSTALLPROPERTY_LANGUAGE) + +#define INSTALLPROPERTY_PRODUCTNAMEA "ProductName" +static const WCHAR INSTALLPROPERTY_PRODUCTNAMEW[] = {'P','r','o','d','u','c','t','N','a','m','e',0}; +#define INSTALLPROPERTY_PRODUCTNAME WINELIB_NAME_AW(INSTALLPROPERTY_PRODUCTNAME) + +#define INSTALLPROPERTY_ASSIGNMENTTYPEA "AssignmentType" +static const WCHAR INSTALLPROPERTY_ASSIGNMENTTYPEW[] = {'A','s','s','i','g','n','m','e','n','t','T','y','p','e',0}; +#define INSTALLPROPERTY_ASSIGNMENTTYPE WINELIB_NAME_AW(INSTALLPROPERTY_ASSIGNMENTTYPE) + +#define INSTALLPROPERTY_PACKAGECODEA "PackageCode" +static const WCHAR INSTALLPROPERTY_PACKAGECODEW[] = {'P','a','c','k','a','g','e','C','o','d','e',0}; +#define INSTALLPROPERTY_PACKAGECODE WINELIB_NAME_AW(INSTALLPROPERTY_PACKAGECODE) + +#define INSTALLPROPERTY_VERSIONA "Version" +static const WCHAR INSTALLPROPERTY_VERSIONW[]= {'V','e','r','s','i','o','n',0}; +#define INSTALLPROPERTY_VERSION WINELIB_NAME_AW(INSTALLPROPERTY_VERSION) + +/* MSI version 1.1 and above */ + +#define INSTALLPROPERTY_PRODUCTICONA "ProductIcon" +static const WCHAR INSTALLPROPERTY_PRODUCTICONW[] = {'P','r','o','d','u','c','t','I','c','o','n',0}; +#define INSTALLPROPERTY_PRODUCTICON WINELIB_NAME_AW(INSTALLPROPERTY_PRODUCTICON) + +/* MSI version 1.5 and above */ +#define INSTALLPROPERTY_INSTANCETYPEA "InstanceType" +static const WCHAR INSTALLPROPERTY_INSTANCETYPEW[] = {'I','n','s','t','a','n','c','e','T','y','p','e',0}; +#define INSTALLPROPERTY_INSTANCETYPE WINELIB_NAME_AW(INSTALLPROPERTY_INSTANCETYPE) + +/* MSI version 3 and above */ +#define INSTALLPROPERTY_AUTHORIZED_LUA_APPA "AuthorizedLUAApp" +static const WCHAR INSTALLPROPERTY_AUTHORIZED_LUA_APPW[] = {'A','u','t','h','o','r','i','z','e','d','L','U','A','A','p','p',0}; +#define INSTALLPROPERTY_AUTHORIZED_LUA_APP WINELIB_NAME_AW(INSTALLPROPERTY_AUTHORIZED_LUA_APP) + + +/* Installed Information */ +#define INSTALLPROPERTY_INSTALLEDPRODUCTNAMEA "InstalledProductName" +static const WCHAR INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW[] = {'I','n','s','t','a','l','l','e','d','P','r','o','d','u','c','t','N','a','m','e',0}; +#define INSTALLPROPERTY_INSTALLEDPRODUCTNAME WINELIB_NAME_AW(INSTALLPROPERTY_INSTALLEDPRODUCTNAME) + +#define INSTALLPROPERTY_VERSIONSTRINGA "VersionString" +static const WCHAR INSTALLPROPERTY_VERSIONSTRINGW[] = {'V','e','r','s','i','o','n','S','t','r','i','n','g',0}; +#define INSTALLPROPERTY_VERSIONSTRING WINELIB_NAME_AW(INSTALLPROPERTY_VERSIONSTRING) + +#define INSTALLPROPERTY_HELPLINKA "HelpLink" +static const WCHAR INSTALLPROPERTY_HELPLINKW[] = {'H','e','l','p','L','i','n','k',0}; +#define INSTALLPROPERTY_HELPLINK WINELIB_NAME_AW(INSTALLPROPERTY_HELPLINK) + +#define INSTALLPROPERTY_HELPTELEPHONEA "HelpTelephone" +static const WCHAR INSTALLPROPERTY_HELPTELEPHONEW[] = {'H','e','l','p','T','e','l','e','p','h','o','n','e',0}; +#define INSTALLPROPERTY_HELPTELEPHONE WINELIB_NAME_AW(INSTALLPROPERTY_HELPTELEPHONE) + +#define INSTALLPROPERTY_INSTALLLOCATIONA "InstallLocation" +static const WCHAR INSTALLPROPERTY_INSTALLLOCATIONW[] = {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0}; +#define INSTALLPROPERTY_INSTALLLOCATION WINELIB_NAME_AW(INSTALLPROPERTY_INSTALLLOCATION) + +#define INSTALLPROPERTY_INSTALLSOURCEA "InstallSource" +static const WCHAR INSTALLPROPERTY_INSTALLSOURCEW[] = {'I','n','s','t','a','l','l','S','o','u','r','c','e',0}; +#define INSTALLPROPERTY_INSTALLSOURCE WINELIB_NAME_AW(INSTALLPROPERTY_INSTALLSOURCE) + +#define INSTALLPROPERTY_INSTALLDATEA "InstallDate" +static const WCHAR INSTALLPROPERTY_INSTALLDATEW[] = {'I','n','s','t','a','l','l','D','a','t','e',0}; +#define INSTALLPROPERTY_INSTALLDATE WINELIB_NAME_AW(INSTALLPROPERTY_INSTALLDATE) + +#define INSTALLPROPERTY_PUBLISHERA "Publisher" +static const WCHAR INSTALLPROPERTY_PUBLISHERW[] ={'P','u','b','l','i','s','h','e','r',0}; +#define INSTALLPROPERTY_PUBLISHER WINELIB_NAME_AW(INSTALLPROPERTY_PUBLISHER) + +#define INSTALLPROPERTY_LOCALPACKAGEA "LocalPackage" +static const WCHAR INSTALLPROPERTY_LOCALPACKAGEW[] = {'L','o','c','a','l','P','a','c','k','a','g','e',0}; +#define INSTALLPROPERTY_LOCALPACKAGE WINELIB_NAME_AW(INSTALLPROPERTY_LOCALPACKAGE) + +#define INSTALLPROPERTY_URLINFOABOUTA "URLInfoAbout" +static const WCHAR INSTALLPROPERTY_URLINFOABOUTW[] = {'U','R','L','I','n','f','o','A','b','o','u','t',0}; +#define INSTALLPROPERTY_URLINFOABOUT WINELIB_NAME_AW(INSTALLPROPERTY_URLINFOABOUT) + +#define INSTALLPROPERTY_URLUPDATEINFOA "URLUpdateInfo" +static const WCHAR INSTALLPROPERTY_URLUPDATEINFOW[] = {'U','R','L','U','p','d','a','t','e','I','n','f','o',0}; +#define INSTALLPROPERTY_URLUPDATEINFO WINELIB_NAME_AW(INSTALLPROPERTY_URLUPDATEINFO) + +#define INSTALLPROPERTY_VERSIONMINORA "VersionMinor" +static const WCHAR INSTALLPROPERTY_VERSIONMINORW[] = {'V','e','r','s','i','o','n','M','i','n','o','r',0}; +#define INSTALLPROPERTY_VERSIONMINOR WINELIB_NAME_AW(INSTALLPROPERTY_VERSIONMINOR) + +#define INSTALLPROPERTY_VERSIONMAJORA "VersionMajor" +static const WCHAR INSTALLPROPERTY_VERSIONMAJORW[] = {'V','e','r','s','i','o','n','M','a','j','o','r',0}; +#define INSTALLPROPERTY_VERSIONMAJOR WINELIB_NAME_AW(INSTALLPROPERTY_VERSIONMAJOR) + +#define INSTALLPROPERTY_PRODUCTIDA "ProductID" +static const WCHAR INSTALLPROPERTY_PRODUCTIDW[] = {'P','r','o','d','u','c','t','I','D',0}; +#define INSTALLPROPERTY_PRODUCTID WINELIB_NAME_AW(INSTALLPROPERTY_PRODUCTID) + +#define INSTALLPROPERTY_REGCOMPANYA "RegCompany" +static const WCHAR INSTALLPROPERTY_REGCOMPANYW[] = {'R','e','g','C','o','m','p','a','n','y',0}; +#define INSTALLPROPERTY_REGCOMPANY WINELIB_NAME_AW(INSTALLPROPERTY_REGCOMPANY) + +#define INSTALLPROPERTY_REGOWNERA "RegOwner" +static const WCHAR INSTALLPROPERTY_REGOWNERW[] = {'R','e','g','O','w','n','e','r',0}; +#define INSTALLPROPERTY_REGOWNER WINELIB_NAME_AW(INSTALLPROPERTY_REGOWNER) + +/* MSI Version 3.0 and greater */ +#define INSTALLPROPERTY_UNINSTALLABLEA "Uninstallable" +static const WCHAR INSTALLPROPERTY_UNINSTALLABLEW[] = {'U','n','i','n','s','t','a','l','l','a','b','l','e',0}; +#define INSTALLPROPERTY_UNINSTALLABLE WINELIB_NAME_AW(INSTALLPROPERTY_UNINSTALLABLE) + +#define INSTALLPROPERTY_PRODUCTSTATEA "State" +static const WCHAR INSTALLPROPERTY_PRODUCTSTATEW[] = {'S','t','a','t','e',0}; +#define INSTALLPROPERTY_PRODUCTSTATE WINELIB_NAME_AW(INSTALLPROPERTY_PRODUCTSTATE) + +#define INSTALLPROPERTY_PATCHSTATEA "State" +static const WCHAR INSTALLPROPERTY_PATCHSTATEW[] ={'S','t','a','t','e',0}; +#define INSTALLPROPERTY_PATCHSTATE WINELIB_NAME_AW(INSTALLPROPERTY_PATCHSTATE) + +#define INSTALLPROPERTY_PATCHTYPEA "PatchType" +static const WCHAR INSTALLPROPERTY_PATCHTYPEW[] = {'P','a','t','c','h','T','y','p','e',0}; +#define INSTALLPROPERTY_PATCHTYPE WINELIB_NAME_AW(INSTALLPROPERTY_PATCHTYPE) + +#define INSTALLPROPERTY_LUAENABLEDA "LUAEnabled" +static const WCHAR INSTALLPROPERTY_LUAENABLEDW[] = {'L','U','A','E','n','a','b','l','e','d',0}; +#define INSTALLPROPERTY_LUAENABLED WINELIB_NAME_AW(INSTALLPROPERTY_LUAENABLED) + +#define INSTALLPROPERTY_DISPLAYNAMEA "DisplayName" +static const WCHAR INSTALLPROPERTY_DISPLAYNAMEW[] = {'D','i','s','p','l','a','y','N','a','m','e',0}; +#define INSTALLPROPERTY_DISPLAYNAME WINELIB_NAME_AW(INSTALLPROPERTY_DISPLAYNAME) + +#define INSTALLPROPERTY_MOREINFOURLA "MoreInfoURL" +static const WCHAR INSTALLPROPERTY_MOREINFOURLW[] = {'M','o','r','e','I','n','f','o','U','R','L',0}; +#define INSTALLPROPERTY_MOREINFOURL WINELIB_NAME_AW(INSTALLPROPERTY_MOREINFOURL) + +/* Source List Info */ +#define INSTALLPROPERTY_LASTUSEDSOURCEA "LastUsedSource" +static const WCHAR INSTALLPROPERTY_LASTUSEDSOURCEW[] = {'L','a','s','t','U','s','e','d','S','o','u','r','c','e',0}; +#define INSTALLPROPERTY_LASTUSEDSOURCE WINELIB_NAME_AW(INSTALLPROPERTY_LASTUSEDSOURCEW) + +#define INSTALLPROPERTY_LASTUSEDTYPEA "LastUsedType" +static const WCHAR INSTALLPROPERTY_LASTUSEDTYPEW[] = {'L','a','s','t','U','s','e','d','T','y','p','e',0}; +#define INSTALLPROPERTY_LASTUSEDTYPE WINELIB_NAME_AW(INSTALLPROPERTY_LASTUSEDTYPE) + +#define INSTALLPROPERTY_MEDIAPACKAGEPATHA "MediaPackagePath" +static const WCHAR INSTALLPROPERTY_MEDIAPACKAGEPATHW[] = {'M','e','d','i','a','P','a','c','k','a','g','e','P','a','t','h',0}; +#define INSTALLPROPERTY_MEDIAPACKAGEPATH WINELIB_NAME_AW(INSTALLPROPERTY_MEDIAPACKAGEPATH) + +#define INSTALLPROPERTY_DISKPROMPTA "DiskPrompt" +static const WCHAR INSTALLPROPERTY_DISKPROMPTW[] = {'D','i','s','k','P','r','o','m','p','t',0}; +#define INSTALLPROPERTY_DISKPROMPT WINELIB_NAME_AW(INSTALLPROPERTY_DISKPROMPT) + typedef INT (CALLBACK *INSTALLUI_HANDLERA)(LPVOID, UINT, LPCSTR); typedef INT (CALLBACK *INSTALLUI_HANDLERW)(LPVOID, UINT, LPCWSTR); @@ -189,10 +373,6 @@ UINT WINAPI MsiEnumClientsA(LPCSTR, DWORD, LPSTR); UINT WINAPI MsiEnumClientsW(LPCWSTR, DWORD, LPWSTR); #define MsiEnumClients WINELIB_NAME_AW(MsiEnumClients) -UINT WINAPI MsiOpenDatabaseA(LPCSTR, LPCSTR, MSIHANDLE *); -UINT WINAPI MsiOpenDatabaseW(LPCWSTR, LPCWSTR, MSIHANDLE *); -#define MsiOpenDatabase WINELIB_NAME_AW(MsiOpenDatabase) - UINT WINAPI MsiOpenPackageA(LPCSTR, MSIHANDLE*); UINT WINAPI MsiOpenPackageW(LPCWSTR, MSIHANDLE*); #define MsiOpenPackage WINELIB_NAME_AW(MsiOpenPackage) @@ -213,10 +393,6 @@ UINT WINAPI MsiGetProductPropertyA(MSIHANDLE,LPCSTR,LPSTR,DWORD*); UINT WINAPI MsiGetProductPropertyW(MSIHANDLE,LPCWSTR,LPWSTR,DWORD*); #define MsiGetProductProperty WINELIB_NAME_AW(MsiGetProductProperty) -UINT WINAPI MsiGetPropertyA(MSIHANDLE, LPCSTR, LPSTR, DWORD*); -UINT WINAPI MsiGetPropertyW(MSIHANDLE, LPCWSTR, LPWSTR, DWORD*); -#define MsiGetProperty WINELIB_NAME_AW(MsiGetProperty) - UINT WINAPI MsiVerifyPackageA(LPCSTR); UINT WINAPI MsiVerifyPackageW(LPCWSTR); #define MsiVerifyPackage WINELIB_NAME_AW(MsiVerifyPackage) @@ -321,6 +497,22 @@ INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR, LPSTR, DWORD *); INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR, LPWSTR, DWORD *); #define MsiLocateComponent WINELIB_NAME_AW(MsiLocateComponent) +UINT WINAPI MsiSourceListGetInfoA(LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, LPCSTR, LPSTR, LPDWORD); +UINT WINAPI MsiSourceListGetInfoW(LPCWSTR, LPCWSTR, MSIINSTALLCONTEXT, DWORD, LPCWSTR, LPWSTR, LPDWORD); +#define MsiSourceListGetInfo WINELIB_NAME_AW(MsiSourceListGetInfo) + +UINT WINAPI MsiSourceListSetInfoA(LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, LPCSTR, LPCSTR); +UINT WINAPI MsiSourceListSetInfoW(LPCWSTR, LPCWSTR, MSIINSTALLCONTEXT, DWORD, LPCWSTR, LPCWSTR); +#define MsiSourceListSetInfo WINELIB_NAME_AW(MsiSourceListSetInfo) + +UINT WINAPI MsiSourceListAddSourceExA(LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, LPCSTR, DWORD); +UINT WINAPI MsiSourceListAddSourceExW(LPCWSTR, LPCWSTR, MSIINSTALLCONTEXT, DWORD, LPCWSTR, DWORD); +#define MsiSourceListAddSourceEx WINELIB_NAME_AW(MsiSourceListAddSourceEx) + +UINT WINAPI MsiSourceListAddMediaDiskA(LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, DWORD, LPCSTR, LPCSTR); +UINT WINAPI MsiSourceListAddMediaDiskW(LPCWSTR, LPCWSTR, MSIINSTALLCONTEXT, DWORD, DWORD, LPCWSTR, LPCWSTR); +#define MsiSourceListAddMediaDisk WINELIB_NAME_AW(MsiSourceListAddMediaDisk) + /* Non Unicode */ UINT WINAPI MsiCloseHandle(MSIHANDLE); UINT WINAPI MsiCloseAllHandles(void); -- 2.17.1