msi: Implement MsiApplyMultiplePatchesA/W.
Hans Leidekker
hans at codeweavers.com
Fri May 1 08:06:53 CDT 2009
Adobe_Updater.exe calls this one.
See http://bugs.winehq.org/show_bug.cgi?id=18246
-Hans
diff --git a/dlls/msi/msi.c b/dlls/msi/msi.c
index bee45b0..43436bd 100644
--- a/dlls/msi/msi.c
+++ b/dlls/msi/msi.c
@@ -301,13 +301,13 @@ done:
return r;
}
-UINT WINAPI MsiApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szInstallPackage,
- INSTALLTYPE eInstallType, LPCWSTR szCommandLine)
+static UINT MSI_ApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szProductCode, LPCWSTR szCommandLine)
{
MSIHANDLE patch, info;
UINT r, type;
DWORD size = 0;
LPCWSTR cmd_ptr = szCommandLine;
+ LPCWSTR product_code = szProductCode;
LPWSTR beg, end;
LPWSTR cmd = NULL, codes = NULL;
@@ -315,41 +315,36 @@ UINT WINAPI MsiApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szInstallPackage,
static const WCHAR patcheq[] = {'P','A','T','C','H','=',0};
static WCHAR empty[] = {0};
- TRACE("%s %s %d %s\n", debugstr_w(szPatchPackage), debugstr_w(szInstallPackage),
- eInstallType, debugstr_w(szCommandLine));
-
- if (szInstallPackage || eInstallType == INSTALLTYPE_NETWORK_IMAGE ||
- eInstallType == INSTALLTYPE_SINGLE_INSTANCE)
+ if (!szProductCode)
{
- FIXME("Only reading target products from patch\n");
- return ERROR_CALL_NOT_IMPLEMENTED;
- }
+ r = MsiOpenDatabaseW(szPatchPackage, MSIDBOPEN_READONLY, &patch);
+ if (r != ERROR_SUCCESS)
+ return r;
- r = MsiOpenDatabaseW(szPatchPackage, MSIDBOPEN_READONLY, &patch);
- if (r != ERROR_SUCCESS)
- return r;
+ r = MsiGetSummaryInformationW(patch, NULL, 0, &info);
+ if (r != ERROR_SUCCESS)
+ goto done;
- r = MsiGetSummaryInformationW(patch, NULL, 0, &info);
- if (r != ERROR_SUCCESS)
- goto done;
+ r = MsiSummaryInfoGetPropertyW(info, PID_TEMPLATE, &type, NULL, NULL, empty, &size);
+ if (r != ERROR_MORE_DATA || !size || type != VT_LPSTR)
+ {
+ ERR("Failed to read product codes from patch\n");
+ goto done;
+ }
- r = MsiSummaryInfoGetPropertyW(info, PID_TEMPLATE, &type, NULL, NULL, empty, &size);
- if (r != ERROR_MORE_DATA || !size || type != VT_LPSTR)
- {
- ERR("Failed to read product codes from patch\n");
- goto done;
- }
+ codes = msi_alloc(++size * sizeof(WCHAR));
+ if (!codes)
+ {
+ r = ERROR_OUTOFMEMORY;
+ goto done;
+ }
- codes = msi_alloc(++size * sizeof(WCHAR));
- if (!codes)
- {
- r = ERROR_OUTOFMEMORY;
- goto done;
- }
+ r = MsiSummaryInfoGetPropertyW(info, PID_TEMPLATE, &type, NULL, NULL, codes, &size);
+ if (r != ERROR_SUCCESS)
+ goto done;
- r = MsiSummaryInfoGetPropertyW(info, PID_TEMPLATE, &type, NULL, NULL, codes, &size);
- if (r != ERROR_SUCCESS)
- goto done;
+ product_code = codes;
+ }
if (!szCommandLine)
cmd_ptr = empty;
@@ -389,6 +384,99 @@ done:
return r;
}
+UINT WINAPI MsiApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szInstallPackage,
+ INSTALLTYPE eInstallType, LPCWSTR szCommandLine)
+{
+ TRACE("%s %s %d %s\n", debugstr_w(szPatchPackage), debugstr_w(szInstallPackage),
+ eInstallType, debugstr_w(szCommandLine));
+
+ if (szInstallPackage || eInstallType == INSTALLTYPE_NETWORK_IMAGE ||
+ eInstallType == INSTALLTYPE_SINGLE_INSTANCE)
+ {
+ FIXME("Only reading target products from patch\n");
+ return ERROR_CALL_NOT_IMPLEMENTED;
+ }
+
+ return MSI_ApplyPatchW(szPatchPackage, NULL, szCommandLine);
+}
+
+UINT WINAPI MsiApplyMultiplePatchesA(LPCSTR szPatchPackages,
+ LPCSTR szProductCode, LPCSTR szPropertiesList)
+{
+ LPWSTR patch_packages = NULL;
+ LPWSTR product_code = NULL;
+ LPWSTR properties_list = NULL;
+ UINT r = ERROR_OUTOFMEMORY;
+
+ TRACE("%s %s %s\n", debugstr_a(szPatchPackages), debugstr_a(szProductCode),
+ debugstr_a(szPropertiesList));
+
+ if (!szPatchPackages || !szPatchPackages[0])
+ return ERROR_INVALID_PARAMETER;
+
+ if (!(patch_packages = strdupAtoW(szPatchPackages)))
+ return ERROR_OUTOFMEMORY;
+
+ if (szProductCode && !(product_code = strdupAtoW(szProductCode)))
+ goto done;
+
+ if (szPropertiesList && !(properties_list = strdupAtoW(szPropertiesList)))
+ goto done;
+
+ r = MsiApplyMultiplePatchesW(patch_packages, product_code, properties_list);
+
+done:
+ msi_free(patch_packages);
+ msi_free(product_code);
+ msi_free(properties_list);
+
+ return r;
+}
+
+UINT WINAPI MsiApplyMultiplePatchesW(LPCWSTR szPatchPackages,
+ LPCWSTR szProductCode, LPCWSTR szPropertiesList)
+{
+ UINT r = ERROR_SUCCESS;
+ LPCWSTR beg, end;
+
+ TRACE("%s %s %s\n", debugstr_w(szPatchPackages), debugstr_w(szProductCode),
+ debugstr_w(szPropertiesList));
+
+ if (!szPatchPackages || !szPatchPackages[0])
+ return ERROR_INVALID_PARAMETER;
+
+ beg = end = szPatchPackages;
+ while (*beg)
+ {
+ DWORD len;
+ LPWSTR patch;
+
+ while (*beg == ' ') beg++;
+ while (*end && *end != ';') end++;
+
+ len = end - beg;
+ while (len && beg[len - 1] == ' ') len--;
+
+ if (!len) return ERROR_INVALID_NAME;
+
+ patch = msi_alloc((len + 1) * sizeof(WCHAR));
+ if (!patch)
+ return ERROR_OUTOFMEMORY;
+
+ memcpy(patch, beg, len * sizeof(WCHAR));
+ patch[len] = '\0';
+
+ r = MSI_ApplyPatchW(patch, szProductCode, szPropertiesList);
+ msi_free(patch);
+
+ if (r != ERROR_SUCCESS)
+ break;
+
+ beg = ++end;
+ }
+ return r;
+}
+
UINT WINAPI MsiDetermineApplicablePatchesA(LPCSTR szProductPackagePath,
DWORD cPatchInfo, PMSIPATCHSEQUENCEINFOA pPatchInfo)
{
diff --git a/dlls/msi/msi.spec b/dlls/msi/msi.spec
index 14178e8..1475028 100644
--- a/dlls/msi/msi.spec
+++ b/dlls/msi/msi.spec
@@ -232,8 +232,8 @@
236 stub Migrate10CachedPackagesW
237 stub MsiRemovePatchesA
238 stub MsiRemovePatchesW
-239 stub MsiApplyMultiplePatchesA
-240 stub MsiApplyMultiplePatchesW
+239 stdcall MsiApplyMultiplePatchesA(str str str)
+240 stdcall MsiApplyMultiplePatchesW(wstr wstr wstr)
241 stub MsiExtractPatchXMLDataA
242 stub MsiExtractPatchXMLDataW
243 stdcall MsiGetPatchInfoExA(str str str long str ptr ptr)
diff --git a/dlls/msi/tests/package.c b/dlls/msi/tests/package.c
index ccc9208..35a22de 100644
--- a/dlls/msi/tests/package.c
+++ b/dlls/msi/tests/package.c
@@ -11533,6 +11533,38 @@ static void test_MsiSetProperty(void)
DeleteFileA(msifile);
}
+static void test_MsiApplyMultiplePatches(void)
+{
+ UINT r;
+
+ r = MsiApplyMultiplePatchesA(NULL, NULL, NULL);
+ ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", r);
+
+ r = MsiApplyMultiplePatchesA("", NULL, NULL);
+ ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", r);
+
+ r = MsiApplyMultiplePatchesA(";", NULL, NULL);
+ ok(r == ERROR_INVALID_NAME, "Expected ERROR_INVALID_NAME, got %u\n", r);
+
+ r = MsiApplyMultiplePatchesA(" ;", NULL, NULL);
+ ok(r == ERROR_INVALID_NAME, "Expected ERROR_INVALID_NAME, got %u\n", r);
+
+ r = MsiApplyMultiplePatchesA(";;", NULL, NULL);
+ ok(r == ERROR_INVALID_NAME, "Expected ERROR_INVALID_NAME, got %u\n", r);
+
+ r = MsiApplyMultiplePatchesA("nosuchpatchpackage;", NULL, NULL);
+ todo_wine ok(r == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %u\n", r);
+
+ r = MsiApplyMultiplePatchesA(";nosuchpatchpackage", NULL, NULL);
+ ok(r == ERROR_INVALID_NAME, "Expected ERROR_INVALID_NAME, got %u\n", r);
+
+ r = MsiApplyMultiplePatchesA("nosuchpatchpackage;nosuchpatchpackage", NULL, NULL);
+ todo_wine ok(r == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %u\n", r);
+
+ r = MsiApplyMultiplePatchesA(" nosuchpatchpackage ; nosuchpatchpackage ", NULL, NULL);
+ todo_wine ok(r == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %u\n", r);
+}
+
START_TEST(package)
{
GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
@@ -11566,4 +11598,5 @@ START_TEST(package)
test_emptypackage();
test_MsiGetProductProperty();
test_MsiSetProperty();
+ test_MsiApplyMultiplePatches();
}
diff --git a/include/msi.h b/include/msi.h
index a6a5f3d..6742f2e 100644
--- a/include/msi.h
+++ b/include/msi.h
@@ -649,6 +649,10 @@ UINT WINAPI MsiDetermineApplicablePatchesA(LPCSTR, DWORD, PMSIPATCHSEQUENCEINFOA
UINT WINAPI MsiDetermineApplicablePatchesW(LPCWSTR, DWORD, PMSIPATCHSEQUENCEINFOW);
#define MsiDetermineApplicablePatches WINELIB_NAME_AW(MsiDetermineApplicablePatches)
+UINT WINAPI MsiApplyMultiplePatchesW(LPCWSTR, LPCWSTR, LPCWSTR);
+UINT WINAPI MsiApplyMultiplePatchesA(LPCSTR, LPCSTR, LPCSTR);
+#define MsiApplyMultiplePatches WINELIB_NAME_AW(MsiApplyMultiplePatches)
+
/* Non Unicode */
UINT WINAPI MsiCloseHandle(MSIHANDLE);
UINT WINAPI MsiCloseAllHandles(void);
More information about the wine-patches
mailing list