- Merge from trunk
[reactos.git] / dll / win32 / msi / msi.c
index 4d9da4c..fb90758 100644 (file)
@@ -299,52 +299,66 @@ done:
     return r;
 }
 
-static UINT MSI_ApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szProductCode, LPCWSTR szCommandLine)
+static UINT get_patch_product_codes( LPCWSTR szPatchPackage, WCHAR **product_codes )
 {
-    MSIHANDLE patch = 0, info = 0;
-    UINT r = ERROR_SUCCESS, type;
-    DWORD size = 0;
-    LPCWSTR cmd_ptr = szCommandLine;
-    LPCWSTR product_code = szProductCode;
-    LPWSTR beg, end;
-    LPWSTR cmd = NULL, codes = NULL;
-
-    static const WCHAR patcheq[] = {'P','A','T','C','H','=',0};
+    MSIHANDLE patch, info = 0;
+    UINT r, type;
+    DWORD size;
     static WCHAR empty[] = {0};
+    WCHAR *codes;
 
-    if (!szPatchPackage || !szPatchPackage[0])
-        return ERROR_INVALID_PARAMETER;
+    r = MsiOpenDatabaseW( szPatchPackage, MSIDBOPEN_READONLY, &patch );
+    if (r != ERROR_SUCCESS)
+        return r;
+
+    r = MsiGetSummaryInformationW( patch, NULL, 0, &info );
+    if (r != ERROR_SUCCESS)
+        goto done;
 
-    if (!szProductCode)
+    size = 0;
+    r = MsiSummaryInfoGetPropertyW( info, PID_TEMPLATE, &type, NULL, NULL, empty, &size );
+    if (r != ERROR_MORE_DATA || !size || type != VT_LPSTR)
     {
-        r = MsiOpenDatabaseW(szPatchPackage, MSIDBOPEN_READONLY, &patch);
-        if (r != ERROR_SUCCESS)
-            return r;
+        ERR("Failed to read product codes from patch\n");
+        r = ERROR_FUNCTION_FAILED;
+        goto done;
+    }
 
-        r = MsiGetSummaryInformationW(patch, NULL, 0, &info);
-        if (r != ERROR_SUCCESS)
-            goto done;
+    codes = msi_alloc( ++size * sizeof(WCHAR) );
+    if (!codes)
+    {
+        r = ERROR_OUTOFMEMORY;
+        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, codes, &size );
+    if (r != ERROR_SUCCESS)
+        msi_free( codes );
+    else
+        *product_codes = codes;
 
-        codes = msi_alloc(++size * sizeof(WCHAR));
-        if (!codes)
-        {
-            r = ERROR_OUTOFMEMORY;
-            goto done;
-        }
+done:
+    MsiCloseHandle( info );
+    MsiCloseHandle( patch );
+    return r;
+}
 
-        r = MsiSummaryInfoGetPropertyW(info, PID_TEMPLATE, &type, NULL, NULL, codes, &size);
-        if (r != ERROR_SUCCESS)
-            goto done;
+static UINT MSI_ApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szProductCode, LPCWSTR szCommandLine)
+{
+    UINT r;
+    DWORD size;
+    LPCWSTR cmd_ptr = szCommandLine;
+    LPWSTR beg, end, cmd, codes = NULL;
+    BOOL succeeded = FALSE;
 
-        product_code = codes;
-    }
+    static const WCHAR patcheq[] = {'P','A','T','C','H','=',0};
+    static WCHAR empty[] = {0};
+
+    if (!szPatchPackage || !szPatchPackage[0])
+        return ERROR_INVALID_PARAMETER;
+
+    if (!szProductCode && (r = get_patch_product_codes( szPatchPackage, &codes )))
+        return r;
 
     if (!szCommandLine)
         cmd_ptr = empty;
@@ -353,8 +367,8 @@ static UINT MSI_ApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szProductCode, LPCWS
     cmd = msi_alloc(size * sizeof(WCHAR));
     if (!cmd)
     {
-        r = ERROR_OUTOFMEMORY;
-        goto done;
+        msi_free(codes);
+        return ERROR_OUTOFMEMORY;
     }
 
     lstrcpyW(cmd, cmd_ptr);
@@ -362,25 +376,29 @@ static UINT MSI_ApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szProductCode, LPCWS
     lstrcatW(cmd, patcheq);
     lstrcatW(cmd, szPatchPackage);
 
-    beg = codes;
-    while ((end = strchrW(beg, '}')))
+    if (szProductCode)
+        r = MsiConfigureProductExW(szProductCode, INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, cmd);
+    else
     {
-        *(end + 1) = '\0';
-
-        r = MsiConfigureProductExW(beg, INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, cmd);
-        if (r != ERROR_SUCCESS)
-            goto done;
+        beg = codes;
+        while ((end = strchrW(beg, '}')))
+        {
+            *(end + 1) = '\0';
+            r = MsiConfigureProductExW(beg, INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, cmd);
+            if (r == ERROR_SUCCESS)
+            {
+                TRACE("patch applied\n");
+                succeeded = TRUE;
+            }
+            beg = end + 2;
+        }
 
-        beg = end + 2;
+        if (succeeded)
+            r = ERROR_SUCCESS;
     }
 
-done:
     msi_free(cmd);
     msi_free(codes);
-
-    MsiCloseHandle(info);
-    MsiCloseHandle(patch);
-
     return r;
 }
 
@@ -480,10 +498,43 @@ UINT WINAPI MsiApplyMultiplePatchesW(LPCWSTR szPatchPackages,
 UINT WINAPI MsiDetermineApplicablePatchesA(LPCSTR szProductPackagePath,
         DWORD cPatchInfo, PMSIPATCHSEQUENCEINFOA pPatchInfo)
 {
-    FIXME("(%s, %d, %p): stub!\n", debugstr_a(szProductPackagePath),
-          cPatchInfo, pPatchInfo);
+    UINT i, r;
+    WCHAR *package_path = NULL;
+    MSIPATCHSEQUENCEINFOW *psi;
 
-    return ERROR_CALL_NOT_IMPLEMENTED;
+    TRACE("(%s, %d, %p)\n", debugstr_a(szProductPackagePath), cPatchInfo, pPatchInfo);
+
+    if (szProductPackagePath && !(package_path = strdupAtoW( szProductPackagePath )))
+        return ERROR_OUTOFMEMORY;
+
+    psi = msi_alloc( cPatchInfo * sizeof(*psi) );
+    if (!psi)
+    {
+        msi_free( package_path );
+        return ERROR_OUTOFMEMORY;
+    }
+
+    for (i = 0; i < cPatchInfo; i++)
+    {
+        psi[i].szPatchData = strdupAtoW( pPatchInfo[i].szPatchData );
+        psi[i].ePatchDataType = pPatchInfo[i].ePatchDataType;
+    }
+
+    r = MsiDetermineApplicablePatchesW( package_path, cPatchInfo, psi );
+    if (r == ERROR_SUCCESS)
+    {
+        for (i = 0; i < cPatchInfo; i++)
+        {
+            pPatchInfo[i].dwOrder = psi[i].dwOrder;
+            pPatchInfo[i].uStatus = psi[i].uStatus;
+        }
+    }
+
+    msi_free( package_path );
+    for (i = 0; i < cPatchInfo; i++)
+        msi_free( (WCHAR *)psi[i].szPatchData );
+    msi_free( psi );
+    return r;
 }
 
 static UINT MSI_ApplicablePatchW( MSIPACKAGE *package, LPCWSTR patch )
@@ -502,15 +553,14 @@ static UINT MSI_ApplicablePatchW( MSIPACKAGE *package, LPCWSTR patch )
     si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
     if (!si)
     {
-        r = ERROR_FUNCTION_FAILED;
-        goto done;
+        msiobj_release( &patch_db->hdr );
+        return ERROR_FUNCTION_FAILED;
     }
 
     r = msi_check_patch_applicable( package, si );
     if (r != ERROR_SUCCESS)
         TRACE("patch not applicable\n");
 
-done:
     msiobj_release( &patch_db->hdr );
     msiobj_release( &si->hdr );
     return r;
@@ -596,10 +646,6 @@ static UINT msi_open_package(LPCWSTR product, MSIINSTALLCONTEXT context,
     WCHAR sourcepath[MAX_PATH];
     WCHAR filename[MAX_PATH];
 
-    static const WCHAR szLocalPackage[] = {
-        'L','o','c','a','l','P','a','c','k','a','g','e',0};
-
-
     r = MSIREG_OpenInstallProps(product, context, NULL, &props, FALSE);
     if (r != ERROR_SUCCESS)
         return ERROR_BAD_CONFIGURATION;
@@ -779,7 +825,7 @@ UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer)
     UINT r;
     WCHAR szwBuffer[GUID_SIZE];
 
-    TRACE("%s %s\n",debugstr_a(szComponent), debugstr_a(szBuffer));
+    TRACE("%s %p\n", debugstr_a(szComponent), szBuffer);
 
     if( szComponent )
     {
@@ -1181,7 +1227,7 @@ done:
 
 static UINT msi_copy_outval(LPWSTR val, LPWSTR out, LPDWORD size)
 {
-    UINT r;
+    UINT r = ERROR_SUCCESS;
 
     if (!val)
         return ERROR_UNKNOWN_PROPERTY;
@@ -1201,7 +1247,7 @@ static UINT msi_copy_outval(LPWSTR val, LPWSTR out, LPDWORD size)
     if (size)
         *size = lstrlenW(val);
 
-    return ERROR_SUCCESS;
+    return r;
 }
 
 UINT WINAPI MsiGetProductInfoExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
@@ -1613,6 +1659,93 @@ done:
     return r;
 }
 
+UINT WINAPI MsiGetPatchInfoA( LPCSTR patch, LPCSTR attr, LPSTR buffer, LPDWORD buflen )
+{
+    UINT r = ERROR_OUTOFMEMORY;
+    DWORD size;
+    LPWSTR patchW = NULL, attrW = NULL, bufferW = NULL;
+
+    TRACE("%s %s %p %p\n", debugstr_a(patch), debugstr_a(attr), buffer, buflen);
+
+    if (!patch || !attr)
+        return ERROR_INVALID_PARAMETER;
+
+    if (!(patchW = strdupAtoW( patch )))
+        goto done;
+
+    if (!(attrW = strdupAtoW( attr )))
+        goto done;
+
+    size = 0;
+    r = MsiGetPatchInfoW( patchW, attrW, NULL, &size );
+    if (r != ERROR_SUCCESS)
+        goto done;
+
+    size++;
+    if (!(bufferW = msi_alloc( size * sizeof(WCHAR) )))
+    {
+        r = ERROR_OUTOFMEMORY;
+        goto done;
+    }
+
+    r = MsiGetPatchInfoW( patchW, attrW, bufferW, &size );
+    if (r == ERROR_SUCCESS)
+    {
+        int len = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL );
+        if (len > *buflen)
+            r = ERROR_MORE_DATA;
+        else if (buffer)
+            WideCharToMultiByte( CP_ACP, 0, bufferW, -1, buffer, *buflen, NULL, NULL );
+
+        *buflen = len - 1;
+    }
+
+done:
+    msi_free( patchW );
+    msi_free( attrW );
+    msi_free( bufferW );
+    return r;
+}
+
+UINT WINAPI MsiGetPatchInfoW( LPCWSTR patch, LPCWSTR attr, LPWSTR buffer, LPDWORD buflen )
+{
+    UINT r;
+    WCHAR product[GUID_SIZE];
+    DWORD index;
+
+    TRACE("%s %s %p %p\n", debugstr_w(patch), debugstr_w(attr), buffer, buflen);
+
+    if (!patch || !attr)
+        return ERROR_INVALID_PARAMETER;
+
+    if (strcmpW( INSTALLPROPERTY_LOCALPACKAGEW, attr ))
+        return ERROR_UNKNOWN_PROPERTY;
+
+    index = 0;
+    while (1)
+    {
+        r = MsiEnumProductsW( index, product );
+        if (r != ERROR_SUCCESS)
+            break;
+
+        r = MsiGetPatchInfoExW( patch, product, NULL, MSIINSTALLCONTEXT_USERMANAGED, attr, buffer, buflen );
+        if (r == ERROR_SUCCESS || r == ERROR_MORE_DATA)
+            return r;
+
+        r = MsiGetPatchInfoExW( patch, product, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, attr, buffer, buflen );
+        if (r == ERROR_SUCCESS || r == ERROR_MORE_DATA)
+            return r;
+
+        r = MsiGetPatchInfoExW( patch, product, NULL, MSIINSTALLCONTEXT_MACHINE, attr, buffer, buflen );
+        if (r == ERROR_SUCCESS || r == ERROR_MORE_DATA)
+            return r;
+
+        index++;
+    }
+
+    return ERROR_UNKNOWN_PRODUCT;
+}
+
 UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes)
 {
     LPWSTR szwLogFile = NULL;
@@ -2027,6 +2160,9 @@ INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf,
 
     TRACE("%s %p %p\n", debugstr_a(szComponent), lpPathBuf, pcchBuf);
 
+    if (!szComponent || !pcchBuf)
+        return INSTALLSTATE_INVALIDARG;
+
     if (MsiGetProductCodeA( szComponent, szProduct ) != ERROR_SUCCESS)
         return INSTALLSTATE_UNKNOWN;
 
@@ -2040,6 +2176,9 @@ INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf,
 
     TRACE("%s %p %p\n", debugstr_w(szComponent), lpPathBuf, pcchBuf);
 
+    if (!szComponent || !pcchBuf)
+        return INSTALLSTATE_INVALIDARG;
+
     if (MsiGetProductCodeW( szComponent, szProduct ) != ERROR_SUCCESS)
         return INSTALLSTATE_UNKNOWN;
 
@@ -2062,6 +2201,22 @@ UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uT
     return MessageBoxExW(hWnd,lpText,lpCaption,uType,wLanguageId); 
 }
 
+UINT WINAPI MsiMessageBoxExA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType,
+                DWORD unknown, WORD wLanguageId, DWORD f)
+{
+    FIXME("(%p, %s, %s, %u, 0x%08x, 0x%08x, 0x%08x): semi-stub\n", hWnd, debugstr_a(lpText),
+            debugstr_a(lpCaption), uType, unknown, wLanguageId, f);
+    return MessageBoxExA(hWnd, lpText, lpCaption, uType, wLanguageId);
+}
+
+UINT WINAPI MsiMessageBoxExW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,
+                DWORD unknown, WORD wLanguageId, DWORD f)
+{
+    FIXME("(%p, %s, %s, %u, 0x%08x, 0x%08x, 0x%08x): semi-stub\n", hWnd, debugstr_w(lpText),
+            debugstr_w(lpCaption), uType, unknown, wLanguageId, f);
+    return MessageBoxExW(hWnd, lpText, lpCaption, uType, wLanguageId);
+}
+
 UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext,
                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf,
                 LPDWORD pcchPathBuf )
@@ -2250,6 +2405,7 @@ done:
         r = ERROR_SUCCESS;
     }
 
+    msiobj_release(&package->hdr);
     return r;
 }
 
@@ -3432,10 +3588,10 @@ UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
     if (r != ERROR_SUCCESS)
         return r;
 
-    MSI_SetPropertyW( package, szReinstallMode, reinstallmode );
-    MSI_SetPropertyW( package, szInstalled, szOne );
-    MSI_SetPropertyW( package, szLogVerbose, szOne );
-    MSI_SetPropertyW( package, szReinstall, szFeature );
+    msi_set_property( package->db, szReinstallMode, reinstallmode );
+    msi_set_property( package->db, szInstalled, szOne );
+    msi_set_property( package->db, szLogVerbose, szOne );
+    msi_set_property( package->db, szReinstall, szFeature );
 
     r = MSI_InstallPackage( package, sourcepath, NULL );
 
@@ -3623,3 +3779,45 @@ UINT WINAPI MsiInstallMissingComponentW(LPCWSTR szProduct, LPCWSTR szComponent,
     FIXME("(%s %s %d\n", debugstr_w(szProduct), debugstr_w(szComponent), eInstallState);
     return ERROR_SUCCESS;
 }
+
+UINT WINAPI MsiBeginTransactionW( LPCWSTR name, DWORD attrs, MSIHANDLE *id, HANDLE *event );
+/***********************************************************************
+ * MsiBeginTransactionA     [MSI.@]
+ */
+UINT WINAPI MsiBeginTransactionA( LPCSTR name, DWORD attrs, MSIHANDLE *id, HANDLE *event )
+{
+    WCHAR *nameW;
+    UINT r;
+
+    FIXME("%s %u %p %p\n", debugstr_a(name), attrs, id, event);
+
+    nameW = strdupAtoW( name );
+    if (name && !nameW)
+        return ERROR_OUTOFMEMORY;
+
+    r = MsiBeginTransactionW( nameW, attrs, id, event );
+    msi_free( nameW );
+    return r;
+}
+
+/***********************************************************************
+ * MsiBeginTransactionW     [MSI.@]
+ */
+UINT WINAPI MsiBeginTransactionW( LPCWSTR name, DWORD attrs, MSIHANDLE *id, HANDLE *event )
+{
+    FIXME("%s %u %p %p\n", debugstr_w(name), attrs, id, event);
+
+    *id = (MSIHANDLE)0xdeadbeef;
+    *event = (HANDLE)0xdeadbeef;
+
+    return ERROR_SUCCESS;
+}
+
+/***********************************************************************
+ * MsiEndTransaction     [MSI.@]
+ */
+UINT WINAPI MsiEndTransaction( DWORD state )
+{
+    FIXME("%u\n", state);
+    return ERROR_SUCCESS;
+}