[MSI] Sync with Wine Staging 1.9.23. CORE-12409
[reactos.git] / reactos / dll / win32 / msi / upgrade.c
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
3 *
4 * Copyright 2005 Aric Stewart for CodeWeavers
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 /*
22 * Actions focused on in this module
23 *
24 * FindRelatedProducts
25 * MigrateFeatureStates (TODO)
26 * RemoveExistingProducts (TODO)
27 */
28
29 #include "msipriv.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(msi);
32
33 static BOOL check_language(DWORD lang1, LPCWSTR lang2, DWORD attributes)
34 {
35 DWORD langdword;
36
37 if (!lang2 || lang2[0]==0)
38 return TRUE;
39
40 langdword = atoiW(lang2);
41
42 if (attributes & msidbUpgradeAttributesLanguagesExclusive)
43 return (lang1 != langdword);
44 else
45 return (lang1 == langdword);
46 }
47
48 static void append_productcode(MSIPACKAGE* package, LPCWSTR action_property,
49 LPCWSTR productid)
50 {
51 LPWSTR prop;
52 LPWSTR newprop;
53 DWORD len;
54 UINT r;
55
56 prop = msi_dup_property(package->db, action_property );
57 if (prop)
58 len = strlenW(prop);
59 else
60 len = 0;
61
62 /*separator*/
63 len ++;
64
65 len += strlenW(productid);
66
67 /*null*/
68 len++;
69
70 newprop = msi_alloc( len*sizeof(WCHAR) );
71
72 if (prop)
73 {
74 strcpyW(newprop,prop);
75 strcatW(newprop,szSemiColon);
76 }
77 else
78 newprop[0] = 0;
79 strcatW(newprop,productid);
80
81 r = msi_set_property( package->db, action_property, newprop, -1 );
82 if (r == ERROR_SUCCESS && !strcmpW( action_property, szSourceDir ))
83 msi_reset_folders( package, TRUE );
84
85 TRACE("Found Related Product... %s now %s\n",
86 debugstr_w(action_property), debugstr_w(newprop));
87
88 msi_free( prop );
89 msi_free( newprop );
90 }
91
92 static UINT ITERATE_FindRelatedProducts(MSIRECORD *rec, LPVOID param)
93 {
94 MSIPACKAGE *package = param;
95 WCHAR product[SQUASHED_GUID_SIZE];
96 DWORD index = 0, attributes = 0, sz = sizeof(product)/sizeof(product[0]);
97 LPCWSTR upgrade_code;
98 HKEY hkey = 0;
99 UINT rc = ERROR_SUCCESS;
100 MSIRECORD *uirow;
101
102 upgrade_code = MSI_RecordGetString(rec,1);
103
104 rc = MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey, FALSE);
105 if (rc != ERROR_SUCCESS)
106 return ERROR_SUCCESS;
107
108 uirow = MSI_CreateRecord(1);
109 attributes = MSI_RecordGetInteger(rec,5);
110
111 while (rc == ERROR_SUCCESS)
112 {
113 rc = RegEnumValueW(hkey, index, product, &sz, NULL, NULL, NULL, NULL);
114 if (rc == ERROR_SUCCESS)
115 {
116 WCHAR productid[GUID_SIZE];
117 LPCWSTR ver, language, action_property;
118 DWORD check = 0, comp_ver, sz = 0x100;
119 HKEY hukey;
120 INT r;
121
122 TRACE("Looking at index %u product %s\n", index, debugstr_w(product));
123
124 unsquash_guid(product, productid);
125 if (MSIREG_OpenProductKey(productid, NULL, MSIINSTALLCONTEXT_USERMANAGED, &hukey, FALSE) &&
126 MSIREG_OpenProductKey(productid, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, &hukey, FALSE) &&
127 MSIREG_OpenProductKey(productid, NULL, MSIINSTALLCONTEXT_MACHINE, &hukey, FALSE))
128 {
129 TRACE("product key not found\n");
130 rc = ERROR_SUCCESS;
131 index ++;
132 continue;
133 }
134
135 sz = sizeof(DWORD);
136 RegQueryValueExW(hukey, INSTALLPROPERTY_VERSIONW, NULL, NULL, (LPBYTE)&check, &sz);
137
138 /* check version minimum */
139 ver = MSI_RecordGetString(rec,2);
140 if (ver)
141 {
142 comp_ver = msi_version_str_to_dword(ver);
143 r = check - comp_ver;
144 if (r < 0 || (r == 0 && !(attributes & msidbUpgradeAttributesVersionMinInclusive)))
145 {
146 TRACE("version below minimum\n");
147 RegCloseKey(hukey);
148 index ++;
149 continue;
150 }
151 }
152
153 /* check version maximum */
154 ver = MSI_RecordGetString(rec,3);
155 if (ver)
156 {
157 comp_ver = msi_version_str_to_dword(ver);
158 r = check - comp_ver;
159 if (r > 0 || (r == 0 && !(attributes & msidbUpgradeAttributesVersionMaxInclusive)))
160 {
161 RegCloseKey(hukey);
162 index ++;
163 continue;
164 }
165 TRACE("version above maximum\n");
166 }
167
168 /* check language */
169 sz = sizeof(DWORD);
170 RegQueryValueExW(hukey, INSTALLPROPERTY_LANGUAGEW, NULL, NULL, (LPBYTE)&check, &sz);
171 RegCloseKey(hukey);
172 language = MSI_RecordGetString(rec,4);
173 if (!check_language(check, language, attributes))
174 {
175 index ++;
176 TRACE("language doesn't match\n");
177 continue;
178 }
179 TRACE("found related product\n");
180
181 action_property = MSI_RecordGetString(rec, 7);
182 append_productcode(package, action_property, productid);
183 MSI_RecordSetStringW(uirow, 1, productid);
184 msi_ui_actiondata(package, szFindRelatedProducts, uirow);
185 }
186 index ++;
187 }
188 RegCloseKey(hkey);
189 msiobj_release( &uirow->hdr);
190
191 return ERROR_SUCCESS;
192 }
193
194 UINT ACTION_FindRelatedProducts(MSIPACKAGE *package)
195 {
196 static const WCHAR query[] = {
197 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
198 '`','U','p','g','r','a','d','e','`',0};
199 MSIQUERY *view;
200 UINT rc;
201
202 if (msi_get_property_int(package->db, szInstalled, 0))
203 {
204 TRACE("Skipping FindRelatedProducts action: product already installed\n");
205 return ERROR_SUCCESS;
206 }
207 if (msi_action_is_unique(package, szFindRelatedProducts))
208 {
209 TRACE("Skipping FindRelatedProducts action: already done in UI sequence\n");
210 return ERROR_SUCCESS;
211 }
212 else
213 msi_register_unique_action(package, szFindRelatedProducts);
214
215 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
216 if (rc != ERROR_SUCCESS)
217 return ERROR_SUCCESS;
218
219 rc = MSI_IterateRecords(view, NULL, ITERATE_FindRelatedProducts, package);
220 msiobj_release(&view->hdr);
221 return rc;
222 }