- implement encoding and decoding of enumerated types, unsigned
[wine] / dlls / 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 /*
22  * Actions focused on in this module
23  *
24  * FindRelatedProducts
25  * MigrateFeatureStates (TODO)
26  * RemoveExistingProducts (TODO)
27  */
28
29 #include <stdarg.h>
30 #include <stdio.h>
31
32 #define COBJMACROS
33
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "winreg.h"
38 #include "wine/debug.h"
39 #include "msi.h"
40 #include "msiquery.h"
41 #include "msidefs.h"
42 #include "msipriv.h"
43 #include "winnls.h"
44 #include "winuser.h"
45 #include "winver.h"
46 #include "action.h"
47 #include "wine/unicode.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(msi);
50
51 static BOOL check_language(DWORD lang1, LPCWSTR lang2, DWORD attributes)
52 {
53     DWORD langdword;
54
55     if (!lang2 || lang2[0]==0)
56         return TRUE;
57
58     langdword = atoiW(lang2);
59
60     if (attributes & msidbUpgradeAttributesLanguagesExclusive)
61         return (lang1 != langdword);
62     else
63         return (lang1 == langdword);
64 }
65
66 static void append_productcode(MSIPACKAGE* package, LPCWSTR action_property,
67                                LPCWSTR productid)
68 {
69     LPWSTR prop;
70     LPWSTR newprop;
71     DWORD len;
72     static const WCHAR separator[] = {';',0};
73
74     prop = load_dynamic_property(package, action_property, NULL);
75     if (prop)
76         len = strlenW(prop);
77     else
78         len = 0;
79
80     /*separator*/
81     len ++;
82
83     len += strlenW(productid);
84
85     /*null*/
86     len++;
87
88     newprop = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
89
90     if (prop)
91     {
92         strcpyW(newprop,prop);
93         strcatW(newprop,separator);
94     }
95     else
96         newprop[0] = 0;
97     strcatW(newprop,productid);
98
99     MSI_SetPropertyW(package, action_property, newprop);
100     TRACE("Found Related Product... %s now %s\n",debugstr_w(action_property),
101                     debugstr_w(newprop));
102     HeapFree(GetProcessHeap(),0,prop);
103     HeapFree(GetProcessHeap(),0,newprop);
104 }
105
106 static UINT ITERATE_FindRelatedProducts(MSIRECORD *rec, LPVOID param)
107 {
108     MSIPACKAGE *package = (MSIPACKAGE*)param;
109     WCHAR product[GUID_SIZE];
110     DWORD index = 0;
111     DWORD attributes = 0;
112     DWORD sz = GUID_SIZE;
113     LPCWSTR upgrade_code;
114     HKEY hkey = 0;
115     UINT rc = ERROR_SUCCESS;
116
117     upgrade_code = MSI_RecordGetString(rec,1);
118
119     rc = MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey, FALSE);
120     if (rc != ERROR_SUCCESS)
121         return ERROR_SUCCESS;
122
123     attributes = MSI_RecordGetInteger(rec,5);
124     
125     while (rc == ERROR_SUCCESS)
126     {
127         rc = RegEnumValueW(hkey, index, product, &sz, NULL, NULL, NULL, NULL);
128         TRACE("Looking at (%li) %s\n",index,debugstr_w(product));
129         if (rc == ERROR_SUCCESS)
130         {
131             WCHAR productid[GUID_SIZE];
132             LPCWSTR ver;
133             LPCWSTR language;
134             LPCWSTR action_property;
135             DWORD check = 0x00000000;
136             DWORD comp_ver = 0x00000000;
137             DWORD sz = 0x100;
138             HKEY hukey;
139             INT r;
140             static const WCHAR szVersion[] =
141                 {'V','e','r','s','i','o','n',0};
142             static const WCHAR szLanguage[] =
143                 {'L','a','n','g','u','a','g','e',0};
144
145             unsquash_guid(product,productid);
146             rc = MSIREG_OpenUserProductsKey(productid, &hukey, FALSE);
147             if (rc != ERROR_SUCCESS)
148             {
149                 rc = ERROR_SUCCESS;
150                 index ++;
151                 continue;
152             }
153           
154             sz = sizeof(DWORD);
155             RegQueryValueExW(hukey, szVersion, NULL, NULL, (LPBYTE)&check, 
156                             &sz);
157             /* check min */
158             ver = MSI_RecordGetString(rec,2);
159             comp_ver = build_version_dword(ver);
160             r = check - comp_ver; 
161             if (r < 0 || (r == 0 && !(attributes &
162                                     msidbUpgradeAttributesVersionMinInclusive)))
163             {
164                 RegCloseKey(hukey);
165                 index ++;
166                 continue;
167             }
168
169             /* check max */
170             ver = MSI_RecordGetString(rec,3);
171             comp_ver = build_version_dword(ver);
172             r = check - comp_ver;
173             if (r > 0 || (r == 0 && !(attributes & 
174                                     msidbUpgradeAttributesVersionMaxInclusive)))
175             {
176                 RegCloseKey(hukey);
177                 index ++;
178                 continue;
179             }
180
181             /* check language*/
182             sz = sizeof(DWORD);
183             RegQueryValueExW(hukey, szLanguage, NULL, NULL, (LPBYTE)&check, 
184                             &sz);
185             RegCloseKey(hukey);
186             language = MSI_RecordGetString(rec,4);
187             TRACE("Checking languages 0x%lx and %s\n", check, 
188                             debugstr_w(language));
189             if (!check_language(check, language, attributes))
190             {
191                 index ++;
192                 continue;
193             }
194
195             action_property = MSI_RecordGetString(rec,7);
196             append_productcode(package,action_property,productid);
197         }
198         index ++;
199     }
200     RegCloseKey(hkey);
201     
202     return ERROR_SUCCESS;
203 }
204
205 UINT ACTION_FindRelatedProducts(MSIPACKAGE *package)
206 {
207     static const WCHAR Query[] = 
208         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',
209          ' ','`','U','p','g','r','a','d','e','`',0};
210     UINT rc = ERROR_SUCCESS;
211     MSIQUERY *view;
212
213     if (package->script && package->script->FindRelatedProductsRun)
214         return ERROR_SUCCESS;
215
216     if (package->script)
217         package->script->FindRelatedProductsRun = TRUE;
218     
219     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
220     if (rc != ERROR_SUCCESS)
221         return ERROR_SUCCESS;
222     
223     rc = MSI_IterateRecords(view, NULL, ITERATE_FindRelatedProducts, package);
224     msiobj_release(&view->hdr);
225     
226     return rc;
227 }