Commit | Line | Data |
---|---|---|
401bd3f7 AS |
1 | /* |
2 | * Implementation of the Microsoft Installer (msi.dll) | |
3 | * | |
c6689520 | 4 | * Copyright 2004,2005 Aric Stewart for CodeWeavers |
401bd3f7 AS |
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 | |
360a3f91 | 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
401bd3f7 AS |
19 | */ |
20 | ||
401bd3f7 | 21 | #include <stdarg.h> |
401bd3f7 | 22 | |
486d020c FG |
23 | #define COBJMACROS |
24 | ||
401bd3f7 AS |
25 | #include "windef.h" |
26 | #include "winbase.h" | |
27 | #include "winerror.h" | |
28 | #include "winreg.h" | |
9bc12ade | 29 | #include "winsvc.h" |
d3bec325 | 30 | #include "odbcinst.h" |
401bd3f7 | 31 | #include "wine/debug.h" |
b6bc6aa6 | 32 | #include "msidefs.h" |
401bd3f7 | 33 | #include "msipriv.h" |
401bd3f7 AS |
34 | #include "winuser.h" |
35 | #include "shlobj.h" | |
bfe07d1d JH |
36 | #include "objbase.h" |
37 | #include "mscoree.h" | |
38 | #include "fusion.h" | |
39 | #include "shlwapi.h" | |
401bd3f7 | 40 | #include "wine/unicode.h" |
98efef18 | 41 | #include "winver.h" |
401bd3f7 | 42 | |
bd1bbc17 AS |
43 | #define REG_PROGRESS_VALUE 13200 |
44 | #define COMPONENT_PROGRESS_VALUE 24000 | |
401bd3f7 | 45 | |
401bd3f7 AS |
46 | WINE_DEFAULT_DEBUG_CHANNEL(msi); |
47 | ||
48 | /* | |
49 | * Prototypes | |
50 | */ | |
a7a6f5f3 AJ |
51 | static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran); |
52 | static UINT ACTION_ProcessUISequence(MSIPACKAGE *package); | |
f8f64406 | 53 | static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI); |
9e85ec3b | 54 | static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, UINT* rc, BOOL force); |
90c57396 | 55 | |
401bd3f7 AS |
56 | /* |
57 | * consts and values used | |
58 | */ | |
014ad3ba | 59 | static const WCHAR c_colon[] = {'C',':','\\',0}; |
c6689520 | 60 | |
9ba8ba30 | 61 | static const WCHAR szCreateFolders[] = |
8e233e9b | 62 | {'C','r','e','a','t','e','F','o','l','d','e','r','s',0}; |
9ba8ba30 | 63 | static const WCHAR szCostFinalize[] = |
8e233e9b | 64 | {'C','o','s','t','F','i','n','a','l','i','z','e',0}; |
c6689520 | 65 | const WCHAR szInstallFiles[] = |
8e233e9b | 66 | {'I','n','s','t','a','l','l','F','i','l','e','s',0}; |
c6689520 | 67 | const WCHAR szDuplicateFiles[] = |
8e233e9b | 68 | {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0}; |
9ba8ba30 | 69 | static const WCHAR szWriteRegistryValues[] = |
8e233e9b AS |
70 | {'W','r','i','t','e','R','e','g','i','s','t','r','y', |
71 | 'V','a','l','u','e','s',0}; | |
9ba8ba30 | 72 | static const WCHAR szCostInitialize[] = |
8e233e9b | 73 | {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0}; |
9ba8ba30 | 74 | static const WCHAR szFileCost[] = |
8e233e9b | 75 | {'F','i','l','e','C','o','s','t',0}; |
9ba8ba30 | 76 | static const WCHAR szInstallInitialize[] = |
8e233e9b | 77 | {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0}; |
9ba8ba30 | 78 | static const WCHAR szInstallValidate[] = |
8e233e9b | 79 | {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0}; |
9ba8ba30 | 80 | static const WCHAR szLaunchConditions[] = |
8e233e9b | 81 | {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0}; |
9ba8ba30 | 82 | static const WCHAR szProcessComponents[] = |
8e233e9b | 83 | {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0}; |
9ba8ba30 | 84 | static const WCHAR szRegisterTypeLibraries[] = |
8e233e9b AS |
85 | {'R','e','g','i','s','t','e','r','T','y','p','e', |
86 | 'L','i','b','r','a','r','i','e','s',0}; | |
db982e25 | 87 | const WCHAR szRegisterClassInfo[] = |
8e233e9b | 88 | {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0}; |
db982e25 | 89 | const WCHAR szRegisterProgIdInfo[] = |
8e233e9b | 90 | {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0}; |
9ba8ba30 | 91 | static const WCHAR szCreateShortcuts[] = |
8e233e9b | 92 | {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0}; |
9ba8ba30 | 93 | static const WCHAR szPublishProduct[] = |
8e233e9b | 94 | {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0}; |
9ba8ba30 | 95 | static const WCHAR szWriteIniValues[] = |
8e233e9b | 96 | {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0}; |
9ba8ba30 | 97 | static const WCHAR szSelfRegModules[] = |
8e233e9b | 98 | {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0}; |
9ba8ba30 | 99 | static const WCHAR szPublishFeatures[] = |
8e233e9b | 100 | {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0}; |
9ba8ba30 | 101 | static const WCHAR szRegisterProduct[] = |
8e233e9b | 102 | {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0}; |
9ba8ba30 | 103 | static const WCHAR szInstallExecute[] = |
8e233e9b | 104 | {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0}; |
9ba8ba30 | 105 | static const WCHAR szInstallExecuteAgain[] = |
8e233e9b AS |
106 | {'I','n','s','t','a','l','l','E','x','e','c','u','t','e', |
107 | 'A','g','a','i','n',0}; | |
9ba8ba30 | 108 | static const WCHAR szInstallFinalize[] = |
8e233e9b | 109 | {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0}; |
9ba8ba30 | 110 | static const WCHAR szForceReboot[] = |
8e233e9b | 111 | {'F','o','r','c','e','R','e','b','o','o','t',0}; |
9ba8ba30 | 112 | static const WCHAR szResolveSource[] = |
8e233e9b | 113 | {'R','e','s','o','l','v','e','S','o','u','r','c','e',0}; |
b79a53e9 | 114 | static const WCHAR szAppSearch[] = |
8e233e9b | 115 | {'A','p','p','S','e','a','r','c','h',0}; |
9ba8ba30 | 116 | static const WCHAR szAllocateRegistrySpace[] = |
8e233e9b AS |
117 | {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y', |
118 | 'S','p','a','c','e',0}; | |
9ba8ba30 | 119 | static const WCHAR szBindImage[] = |
8e233e9b | 120 | {'B','i','n','d','I','m','a','g','e',0}; |
9ba8ba30 | 121 | static const WCHAR szCCPSearch[] = |
8e233e9b | 122 | {'C','C','P','S','e','a','r','c','h',0}; |
9ba8ba30 | 123 | static const WCHAR szDeleteServices[] = |
8e233e9b | 124 | {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0}; |
9ba8ba30 | 125 | static const WCHAR szDisableRollback[] = |
8e233e9b | 126 | {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0}; |
9ba8ba30 | 127 | static const WCHAR szExecuteAction[] = |
8e233e9b | 128 | {'E','x','e','c','u','t','e','A','c','t','i','o','n',0}; |
db982e25 | 129 | const WCHAR szFindRelatedProducts[] = |
8e233e9b AS |
130 | {'F','i','n','d','R','e','l','a','t','e','d', |
131 | 'P','r','o','d','u','c','t','s',0}; | |
9ba8ba30 | 132 | static const WCHAR szInstallAdminPackage[] = |
8e233e9b AS |
133 | {'I','n','s','t','a','l','l','A','d','m','i','n', |
134 | 'P','a','c','k','a','g','e',0}; | |
9ba8ba30 | 135 | static const WCHAR szInstallSFPCatalogFile[] = |
8e233e9b AS |
136 | {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g', |
137 | 'F','i','l','e',0}; | |
9ba8ba30 | 138 | static const WCHAR szIsolateComponents[] = |
8e233e9b | 139 | {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0}; |
c6689520 | 140 | const WCHAR szMigrateFeatureStates[] = |
8e233e9b AS |
141 | {'M','i','g','r','a','t','e','F','e','a','t','u','r','e', |
142 | 'S','t','a','t','e','s',0}; | |
c6689520 | 143 | const WCHAR szMoveFiles[] = |
8e233e9b | 144 | {'M','o','v','e','F','i','l','e','s',0}; |
9ba8ba30 | 145 | static const WCHAR szMsiPublishAssemblies[] = |
8e233e9b AS |
146 | {'M','s','i','P','u','b','l','i','s','h', |
147 | 'A','s','s','e','m','b','l','i','e','s',0}; | |
9ba8ba30 | 148 | static const WCHAR szMsiUnpublishAssemblies[] = |
8e233e9b AS |
149 | {'M','s','i','U','n','p','u','b','l','i','s','h', |
150 | 'A','s','s','e','m','b','l','i','e','s',0}; | |
9ba8ba30 | 151 | static const WCHAR szInstallODBC[] = |
8e233e9b | 152 | {'I','n','s','t','a','l','l','O','D','B','C',0}; |
9ba8ba30 | 153 | static const WCHAR szInstallServices[] = |
8e233e9b | 154 | {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0}; |
c6689520 | 155 | const WCHAR szPatchFiles[] = |
8e233e9b | 156 | {'P','a','t','c','h','F','i','l','e','s',0}; |
9ba8ba30 | 157 | static const WCHAR szPublishComponents[] = |
8e233e9b | 158 | {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0}; |
9ba8ba30 | 159 | static const WCHAR szRegisterComPlus[] = |
8e233e9b | 160 | {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0}; |
db982e25 | 161 | const WCHAR szRegisterExtensionInfo[] = |
8e233e9b AS |
162 | {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n', |
163 | 'I','n','f','o',0}; | |
9ba8ba30 | 164 | static const WCHAR szRegisterFonts[] = |
8e233e9b | 165 | {'R','e','g','i','s','t','e','r','F','o','n','t','s',0}; |
db982e25 | 166 | const WCHAR szRegisterMIMEInfo[] = |
8e233e9b | 167 | {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0}; |
9ba8ba30 | 168 | static const WCHAR szRegisterUser[] = |
8e233e9b | 169 | {'R','e','g','i','s','t','e','r','U','s','e','r',0}; |
c6689520 | 170 | const WCHAR szRemoveDuplicateFiles[] = |
8e233e9b AS |
171 | {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e', |
172 | 'F','i','l','e','s',0}; | |
9ba8ba30 | 173 | static const WCHAR szRemoveEnvironmentStrings[] = |
8e233e9b AS |
174 | {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t', |
175 | 'S','t','r','i','n','g','s',0}; | |
c6689520 | 176 | const WCHAR szRemoveExistingProducts[] = |
8e233e9b AS |
177 | {'R','e','m','o','v','e','E','x','i','s','t','i','n','g', |
178 | 'P','r','o','d','u','c','t','s',0}; | |
c6689520 | 179 | const WCHAR szRemoveFiles[] = |
8e233e9b | 180 | {'R','e','m','o','v','e','F','i','l','e','s',0}; |
9ba8ba30 | 181 | static const WCHAR szRemoveFolders[] = |
8e233e9b | 182 | {'R','e','m','o','v','e','F','o','l','d','e','r','s',0}; |
9ba8ba30 | 183 | static const WCHAR szRemoveIniValues[] = |
8e233e9b | 184 | {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0}; |
9ba8ba30 | 185 | static const WCHAR szRemoveODBC[] = |
8e233e9b | 186 | {'R','e','m','o','v','e','O','D','B','C',0}; |
9ba8ba30 | 187 | static const WCHAR szRemoveRegistryValues[] = |
8e233e9b AS |
188 | {'R','e','m','o','v','e','R','e','g','i','s','t','r','y', |
189 | 'V','a','l','u','e','s',0}; | |
9ba8ba30 | 190 | static const WCHAR szRemoveShortcuts[] = |
8e233e9b | 191 | {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0}; |
9ba8ba30 | 192 | static const WCHAR szRMCCPSearch[] = |
8e233e9b | 193 | {'R','M','C','C','P','S','e','a','r','c','h',0}; |
9ba8ba30 | 194 | static const WCHAR szScheduleReboot[] = |
8e233e9b | 195 | {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0}; |
9ba8ba30 | 196 | static const WCHAR szSelfUnregModules[] = |
8e233e9b | 197 | {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0}; |
9ba8ba30 | 198 | static const WCHAR szSetODBCFolders[] = |
8e233e9b | 199 | {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0}; |
9ba8ba30 | 200 | static const WCHAR szStartServices[] = |
8e233e9b | 201 | {'S','t','a','r','t','S','e','r','v','i','c','e','s',0}; |
9ba8ba30 | 202 | static const WCHAR szStopServices[] = |
8e233e9b | 203 | {'S','t','o','p','S','e','r','v','i','c','e','s',0}; |
9ba8ba30 | 204 | static const WCHAR szUnpublishComponents[] = |
8e233e9b AS |
205 | {'U','n','p','u','b','l','i','s','h', |
206 | 'C','o','m','p','o','n','e','n','t','s',0}; | |
9ba8ba30 | 207 | static const WCHAR szUnpublishFeatures[] = |
8e233e9b | 208 | {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0}; |
c6689520 | 209 | const WCHAR szUnregisterClassInfo[] = |
8e233e9b AS |
210 | {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s', |
211 | 'I','n','f','o',0}; | |
9ba8ba30 | 212 | static const WCHAR szUnregisterComPlus[] = |
8e233e9b | 213 | {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0}; |
c6689520 | 214 | const WCHAR szUnregisterExtensionInfo[] = |
8e233e9b AS |
215 | {'U','n','r','e','g','i','s','t','e','r', |
216 | 'E','x','t','e','n','s','i','o','n','I','n','f','o',0}; | |
9ba8ba30 | 217 | static const WCHAR szUnregisterFonts[] = |
8e233e9b | 218 | {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0}; |
c6689520 | 219 | const WCHAR szUnregisterMIMEInfo[] = |
8e233e9b | 220 | {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0}; |
c6689520 | 221 | const WCHAR szUnregisterProgIdInfo[] = |
8e233e9b AS |
222 | {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d', |
223 | 'I','n','f','o',0}; | |
9ba8ba30 | 224 | static const WCHAR szUnregisterTypeLibraries[] = |
8e233e9b AS |
225 | {'U','n','r','e','g','i','s','t','e','r','T','y','p','e', |
226 | 'L','i','b','r','a','r','i','e','s',0}; | |
9ba8ba30 | 227 | static const WCHAR szValidateProductID[] = |
8e233e9b | 228 | {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0}; |
9ba8ba30 | 229 | static const WCHAR szWriteEnvironmentStrings[] = |
8e233e9b AS |
230 | {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t', |
231 | 'S','t','r','i','n','g','s',0}; | |
90c57396 | 232 | |
3b955150 MM |
233 | /* action handlers */ |
234 | typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*); | |
235 | ||
90c57396 AS |
236 | struct _actions { |
237 | LPCWSTR action; | |
238 | STANDARDACTIONHANDLER handler; | |
239 | }; | |
240 | ||
2703d717 AS |
241 | |
242 | /******************************************************** | |
243 | * helper functions | |
244 | ********************************************************/ | |
245 | ||
a7a6f5f3 | 246 | static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action) |
d2c395ad | 247 | { |
d2c395ad | 248 | static const WCHAR Query_t[] = |
8e233e9b | 249 | {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', |
98e38082 AS |
250 | '`','A','c','t','i','o', 'n','T','e','x','t','`',' ', |
251 | 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=', | |
252 | ' ','\'','%','s','\'',0}; | |
d679bc5a | 253 | MSIRECORD * row; |
d2c395ad | 254 | |
0b352c7f MM |
255 | row = MSI_QueryGetRecord( package->db, Query_t, action ); |
256 | if (!row) | |
d2c395ad | 257 | return; |
a7a6f5f3 AJ |
258 | MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row); |
259 | msiobj_release(&row->hdr); | |
d2c395ad AS |
260 | } |
261 | ||
a7a6f5f3 | 262 | static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start, |
d2c395ad AS |
263 | UINT rc) |
264 | { | |
a7a6f5f3 | 265 | MSIRECORD * row; |
d2c395ad | 266 | static const WCHAR template_s[]= |
8e233e9b AS |
267 | {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ', |
268 | '%','s', '.',0}; | |
d2c395ad | 269 | static const WCHAR template_e[]= |
8e233e9b AS |
270 | {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ', |
271 | '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ', | |
272 | '%','i','.',0}; | |
d2c395ad | 273 | static const WCHAR format[] = |
8e233e9b | 274 | {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0}; |
d2c395ad AS |
275 | WCHAR message[1024]; |
276 | WCHAR timet[0x100]; | |
277 | ||
278 | GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100); | |
279 | if (start) | |
280 | sprintfW(message,template_s,timet,action); | |
281 | else | |
282 | sprintfW(message,template_e,timet,action,rc); | |
283 | ||
a7a6f5f3 AJ |
284 | row = MSI_CreateRecord(1); |
285 | MSI_RecordSetStringW(row,1,message); | |
d2c395ad | 286 | |
a7a6f5f3 AJ |
287 | MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row); |
288 | msiobj_release(&row->hdr); | |
d2c395ad AS |
289 | } |
290 | ||
ca71e5af JH |
291 | UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine, |
292 | BOOL preserve_case ) | |
e3452228 MM |
293 | { |
294 | LPCWSTR ptr,ptr2; | |
295 | BOOL quote; | |
296 | DWORD len; | |
297 | LPWSTR prop = NULL, val = NULL; | |
298 | ||
299 | if (!szCommandLine) | |
300 | return ERROR_SUCCESS; | |
301 | ||
302 | ptr = szCommandLine; | |
303 | ||
304 | while (*ptr) | |
305 | { | |
306 | if (*ptr==' ') | |
307 | { | |
308 | ptr++; | |
309 | continue; | |
310 | } | |
311 | ||
312 | TRACE("Looking at %s\n",debugstr_w(ptr)); | |
313 | ||
314 | ptr2 = strchrW(ptr,'='); | |
315 | if (!ptr2) | |
316 | { | |
317 | ERR("command line contains unknown string : %s\n", debugstr_w(ptr)); | |
318 | break; | |
319 | } | |
320 | ||
321 | quote = FALSE; | |
322 | ||
323 | len = ptr2-ptr; | |
324 | prop = msi_alloc((len+1)*sizeof(WCHAR)); | |
325 | memcpy(prop,ptr,len*sizeof(WCHAR)); | |
326 | prop[len]=0; | |
ca71e5af JH |
327 | |
328 | if (!preserve_case) | |
329 | struprW(prop); | |
330 | ||
e3452228 MM |
331 | ptr2++; |
332 | ||
333 | len = 0; | |
334 | ptr = ptr2; | |
335 | while (*ptr && (quote || (!quote && *ptr!=' '))) | |
336 | { | |
337 | if (*ptr == '"') | |
338 | quote = !quote; | |
339 | ptr++; | |
340 | len++; | |
341 | } | |
342 | ||
343 | if (*ptr2=='"') | |
344 | { | |
345 | ptr2++; | |
346 | len -= 2; | |
347 | } | |
348 | val = msi_alloc((len+1)*sizeof(WCHAR)); | |
349 | memcpy(val,ptr2,len*sizeof(WCHAR)); | |
350 | val[len] = 0; | |
351 | ||
352 | if (lstrlenW(prop) > 0) | |
353 | { | |
354 | TRACE("Found commandline property (%s) = (%s)\n", | |
355 | debugstr_w(prop), debugstr_w(val)); | |
356 | MSI_SetPropertyW(package,prop,val); | |
357 | } | |
358 | msi_free(val); | |
359 | msi_free(prop); | |
360 | } | |
361 | ||
362 | return ERROR_SUCCESS; | |
363 | } | |
364 | ||
965a72ad MM |
365 | |
366 | static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep ) | |
367 | { | |
2e372c08 | 368 | LPCWSTR pc; |
965a72ad MM |
369 | LPWSTR p, *ret = NULL; |
370 | UINT count = 0; | |
371 | ||
372 | if (!str) | |
373 | return ret; | |
374 | ||
375 | /* count the number of substrings */ | |
2e372c08 | 376 | for ( pc = str, count = 0; pc; count++ ) |
965a72ad | 377 | { |
2e372c08 AT |
378 | pc = strchrW( pc, sep ); |
379 | if (pc) | |
380 | pc++; | |
965a72ad MM |
381 | } |
382 | ||
383 | /* allocate space for an array of substring pointers and the substrings */ | |
384 | ret = msi_alloc( (count+1) * sizeof (LPWSTR) + | |
385 | (lstrlenW(str)+1) * sizeof(WCHAR) ); | |
386 | if (!ret) | |
387 | return ret; | |
388 | ||
389 | /* copy the string and set the pointers */ | |
390 | p = (LPWSTR) &ret[count+1]; | |
391 | lstrcpyW( p, str ); | |
392 | for( count = 0; (ret[count] = p); count++ ) | |
393 | { | |
394 | p = strchrW( p, sep ); | |
395 | if (p) | |
396 | *p++ = 0; | |
397 | } | |
398 | ||
399 | return ret; | |
400 | } | |
401 | ||
0d7dc8f9 MM |
402 | static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch ) |
403 | { | |
86af8769 HL |
404 | static const WCHAR szProductCode[] = |
405 | { 'P','r','o','d','u','c','t','C','o','d','e',0 }; | |
406 | static const WCHAR szSystemLanguageID[] = | |
407 | { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 }; | |
408 | ||
409 | LPWSTR prod_code, patch_product, langid = NULL, template = NULL; | |
410 | UINT ret = ERROR_FUNCTION_FAILED; | |
0d7dc8f9 MM |
411 | |
412 | prod_code = msi_dup_property( package, szProductCode ); | |
413 | patch_product = msi_get_suminfo_product( patch ); | |
414 | ||
415 | TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product)); | |
416 | ||
417 | if ( strstrW( patch_product, prod_code ) ) | |
86af8769 HL |
418 | { |
419 | static const WCHAR zero[] = {'0',0}; | |
420 | MSISUMMARYINFO *si; | |
421 | const WCHAR *p; | |
422 | ||
423 | si = MSI_GetSummaryInformationW( patch, 0 ); | |
424 | if (!si) | |
425 | { | |
426 | ERR("no summary information!\n"); | |
427 | goto end; | |
428 | } | |
429 | ||
430 | template = msi_suminfo_dup_string( si, PID_TEMPLATE ); | |
431 | if (!template) | |
432 | { | |
433 | ERR("no template property!\n"); | |
434 | msiobj_release( &si->hdr ); | |
435 | goto end; | |
436 | } | |
437 | ||
438 | if (!template[0]) | |
439 | { | |
440 | ret = ERROR_SUCCESS; | |
441 | msiobj_release( &si->hdr ); | |
442 | goto end; | |
443 | } | |
444 | ||
445 | langid = msi_dup_property( package, szSystemLanguageID ); | |
446 | if (!langid) | |
447 | { | |
448 | msiobj_release( &si->hdr ); | |
449 | goto end; | |
450 | } | |
451 | ||
452 | p = strchrW( template, ';' ); | |
453 | if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, zero ))) | |
454 | { | |
455 | TRACE("applicable transform\n"); | |
456 | ret = ERROR_SUCCESS; | |
457 | } | |
458 | ||
459 | /* FIXME: check platform */ | |
460 | ||
461 | msiobj_release( &si->hdr ); | |
462 | } | |
0d7dc8f9 | 463 | |
86af8769 | 464 | end: |
0d7dc8f9 MM |
465 | msi_free( patch_product ); |
466 | msi_free( prod_code ); | |
86af8769 HL |
467 | msi_free( template ); |
468 | msi_free( langid ); | |
0d7dc8f9 MM |
469 | |
470 | return ret; | |
471 | } | |
472 | ||
965a72ad MM |
473 | static UINT msi_apply_substorage_transform( MSIPACKAGE *package, |
474 | MSIDATABASE *patch_db, LPCWSTR name ) | |
475 | { | |
476 | UINT ret = ERROR_FUNCTION_FAILED; | |
477 | IStorage *stg = NULL; | |
478 | HRESULT r; | |
479 | ||
480 | TRACE("%p %s\n", package, debugstr_w(name) ); | |
481 | ||
482 | if (*name++ != ':') | |
483 | { | |
484 | ERR("expected a colon in %s\n", debugstr_w(name)); | |
485 | return ERROR_FUNCTION_FAILED; | |
486 | } | |
487 | ||
488 | r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg ); | |
489 | if (SUCCEEDED(r)) | |
490 | { | |
0d7dc8f9 MM |
491 | ret = msi_check_transform_applicable( package, stg ); |
492 | if (ret == ERROR_SUCCESS) | |
493 | msi_table_apply_transform( package->db, stg ); | |
494 | else | |
495 | TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name)); | |
965a72ad | 496 | IStorage_Release( stg ); |
965a72ad MM |
497 | } |
498 | else | |
499 | ERR("failed to open substorage %s\n", debugstr_w(name)); | |
500 | ||
0d7dc8f9 | 501 | return ERROR_SUCCESS; |
965a72ad MM |
502 | } |
503 | ||
05e9a1fc | 504 | UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si ) |
965a72ad | 505 | { |
261e1179 JH |
506 | static const WCHAR szProdCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 }; |
507 | LPWSTR guid_list, *guids, product_code; | |
965a72ad MM |
508 | UINT i, ret = ERROR_FUNCTION_FAILED; |
509 | ||
261e1179 JH |
510 | product_code = msi_dup_property( package, szProdCode ); |
511 | if (!product_code) | |
965a72ad | 512 | { |
261e1179 JH |
513 | /* FIXME: the property ProductCode should be written into the DB somewhere */ |
514 | ERR("no product code to check\n"); | |
965a72ad MM |
515 | return ERROR_SUCCESS; |
516 | } | |
517 | ||
518 | guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE ); | |
519 | guids = msi_split_string( guid_list, ';' ); | |
520 | for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ ) | |
521 | { | |
261e1179 | 522 | if (!lstrcmpW( guids[i], product_code )) |
965a72ad MM |
523 | ret = ERROR_SUCCESS; |
524 | } | |
525 | msi_free( guids ); | |
526 | msi_free( guid_list ); | |
261e1179 | 527 | msi_free( product_code ); |
965a72ad MM |
528 | |
529 | return ret; | |
530 | } | |
531 | ||
c059ceb5 JH |
532 | static UINT msi_set_media_source_prop(MSIPACKAGE *package) |
533 | { | |
534 | MSIQUERY *view; | |
535 | MSIRECORD *rec = NULL; | |
536 | LPWSTR patch; | |
537 | LPCWSTR prop; | |
538 | UINT r; | |
539 | ||
540 | static const WCHAR szPatch[] = {'P','A','T','C','H',0}; | |
541 | static const WCHAR query[] = {'S','E','L','E','C','T',' ', | |
542 | '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ', | |
543 | '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ', | |
544 | '`','S','o','u','r','c','e','`',' ','I','S',' ', | |
545 | 'N','O','T',' ','N','U','L','L',0}; | |
546 | ||
547 | r = MSI_DatabaseOpenViewW(package->db, query, &view); | |
548 | if (r != ERROR_SUCCESS) | |
549 | return r; | |
550 | ||
551 | r = MSI_ViewExecute(view, 0); | |
552 | if (r != ERROR_SUCCESS) | |
553 | goto done; | |
554 | ||
555 | if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS) | |
556 | { | |
557 | prop = MSI_RecordGetString(rec, 1); | |
558 | patch = msi_dup_property(package, szPatch); | |
559 | MSI_SetPropertyW(package, prop, patch); | |
560 | msi_free(patch); | |
561 | } | |
562 | ||
563 | done: | |
564 | if (rec) msiobj_release(&rec->hdr); | |
565 | msiobj_release(&view->hdr); | |
566 | ||
567 | return r; | |
568 | } | |
569 | ||
965a72ad MM |
570 | static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db ) |
571 | { | |
572 | MSISUMMARYINFO *si; | |
573 | LPWSTR str, *substorage; | |
574 | UINT i, r = ERROR_SUCCESS; | |
575 | ||
7f98f1d0 | 576 | si = MSI_GetSummaryInformationW( patch_db->storage, 0 ); |
965a72ad MM |
577 | if (!si) |
578 | return ERROR_FUNCTION_FAILED; | |
579 | ||
01eb9300 JH |
580 | if (msi_check_patch_applicable( package, si ) != ERROR_SUCCESS) |
581 | { | |
582 | TRACE("Patch not applicable\n"); | |
583 | return ERROR_SUCCESS; | |
584 | } | |
585 | ||
586 | package->patch = msi_alloc(sizeof(MSIPATCHINFO)); | |
587 | if (!package->patch) | |
588 | return ERROR_OUTOFMEMORY; | |
589 | ||
590 | package->patch->patchcode = msi_suminfo_dup_string(si, PID_REVNUMBER); | |
591 | if (!package->patch->patchcode) | |
592 | return ERROR_OUTOFMEMORY; | |
965a72ad MM |
593 | |
594 | /* enumerate the substorage */ | |
595 | str = msi_suminfo_dup_string( si, PID_LASTAUTHOR ); | |
01eb9300 JH |
596 | package->patch->transforms = str; |
597 | ||
965a72ad MM |
598 | substorage = msi_split_string( str, ';' ); |
599 | for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ ) | |
600 | r = msi_apply_substorage_transform( package, patch_db, substorage[i] ); | |
965a72ad | 601 | |
01eb9300 | 602 | msi_free( substorage ); |
965a72ad MM |
603 | msiobj_release( &si->hdr ); |
604 | ||
c059ceb5 JH |
605 | msi_set_media_source_prop(package); |
606 | ||
965a72ad MM |
607 | return r; |
608 | } | |
609 | ||
610 | static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file ) | |
611 | { | |
612 | MSIDATABASE *patch_db = NULL; | |
613 | UINT r; | |
614 | ||
615 | TRACE("%p %s\n", package, debugstr_w( file ) ); | |
616 | ||
617 | /* FIXME: | |
618 | * We probably want to make sure we only open a patch collection here. | |
619 | * Patch collections (.msp) and databases (.msi) have different GUIDs | |
620 | * but currently MSI_OpenDatabaseW will accept both. | |
621 | */ | |
622 | r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db ); | |
623 | if ( r != ERROR_SUCCESS ) | |
624 | { | |
625 | ERR("failed to open patch collection %s\n", debugstr_w( file ) ); | |
626 | return r; | |
627 | } | |
628 | ||
629 | msi_parse_patch_summary( package, patch_db ); | |
9a4ba8c1 MM |
630 | |
631 | /* | |
632 | * There might be a CAB file in the patch package, | |
633 | * so append it to the list of storage to search for streams. | |
634 | */ | |
635 | append_storage_to_db( package->db, patch_db->storage ); | |
636 | ||
965a72ad MM |
637 | msiobj_release( &patch_db->hdr ); |
638 | ||
639 | return ERROR_SUCCESS; | |
640 | } | |
641 | ||
642 | /* get the PATCH property, and apply all the patches it specifies */ | |
643 | static UINT msi_apply_patches( MSIPACKAGE *package ) | |
644 | { | |
645 | static const WCHAR szPatch[] = { 'P','A','T','C','H',0 }; | |
646 | LPWSTR patch_list, *patches; | |
647 | UINT i, r = ERROR_SUCCESS; | |
648 | ||
649 | patch_list = msi_dup_property( package, szPatch ); | |
650 | ||
651 | TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) ); | |
652 | ||
653 | patches = msi_split_string( patch_list, ';' ); | |
654 | for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ ) | |
655 | r = msi_apply_patch_package( package, patches[i] ); | |
656 | ||
657 | msi_free( patches ); | |
658 | msi_free( patch_list ); | |
659 | ||
660 | return r; | |
661 | } | |
662 | ||
e534e772 MM |
663 | static UINT msi_apply_transforms( MSIPACKAGE *package ) |
664 | { | |
665 | static const WCHAR szTransforms[] = { | |
666 | 'T','R','A','N','S','F','O','R','M','S',0 }; | |
667 | LPWSTR xform_list, *xforms; | |
668 | UINT i, r = ERROR_SUCCESS; | |
669 | ||
670 | xform_list = msi_dup_property( package, szTransforms ); | |
671 | xforms = msi_split_string( xform_list, ';' ); | |
672 | ||
673 | for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ ) | |
674 | { | |
675 | if (xforms[i][0] == ':') | |
776a7d70 | 676 | r = msi_apply_substorage_transform( package, package->db, xforms[i] ); |
e534e772 MM |
677 | else |
678 | r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 ); | |
679 | } | |
680 | ||
681 | msi_free( xforms ); | |
682 | msi_free( xform_list ); | |
683 | ||
684 | return r; | |
685 | } | |
686 | ||
4439e0b5 | 687 | static BOOL ui_sequence_exists( MSIPACKAGE *package ) |
6da8041d JH |
688 | { |
689 | MSIQUERY *view; | |
690 | UINT rc; | |
691 | ||
692 | static const WCHAR ExecSeqQuery [] = | |
693 | {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', | |
694 | '`','I','n','s','t','a','l','l', | |
695 | 'U','I','S','e','q','u','e','n','c','e','`', | |
696 | ' ','W','H','E','R','E',' ', | |
697 | '`','S','e','q','u','e','n','c','e','`',' ', | |
698 | '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ', | |
699 | '`','S','e','q','u','e','n','c','e','`',0}; | |
700 | ||
701 | rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); | |
702 | if (rc == ERROR_SUCCESS) | |
703 | { | |
704 | msiobj_release(&view->hdr); | |
705 | return TRUE; | |
706 | } | |
707 | ||
708 | return FALSE; | |
709 | } | |
710 | ||
c777d309 JH |
711 | static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace) |
712 | { | |
062070bf | 713 | LPWSTR p, db; |
c777d309 JH |
714 | LPWSTR source, check; |
715 | DWORD len; | |
716 | ||
c37849ad JH |
717 | static const WCHAR szOriginalDatabase[] = |
718 | {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0}; | |
719 | ||
062070bf JH |
720 | db = msi_dup_property( package, szOriginalDatabase ); |
721 | if (!db) | |
722 | return ERROR_OUTOFMEMORY; | |
723 | ||
724 | p = strrchrW( db, '\\' ); | |
c777d309 | 725 | if (!p) |
062070bf | 726 | { |
18648766 JH |
727 | p = strrchrW( db, '/' ); |
728 | if (!p) | |
729 | { | |
730 | msi_free(db); | |
731 | return ERROR_SUCCESS; | |
732 | } | |
062070bf | 733 | } |
c777d309 | 734 | |
062070bf | 735 | len = p - db + 2; |
c777d309 | 736 | source = msi_alloc( len * sizeof(WCHAR) ); |
062070bf | 737 | lstrcpynW( source, db, len ); |
c777d309 JH |
738 | |
739 | check = msi_dup_property( package, cszSourceDir ); | |
740 | if (!check || replace) | |
741 | MSI_SetPropertyW( package, cszSourceDir, source ); | |
742 | ||
743 | msi_free( check ); | |
744 | ||
745 | check = msi_dup_property( package, cszSOURCEDIR ); | |
746 | if (!check || replace) | |
747 | MSI_SetPropertyW( package, cszSOURCEDIR, source ); | |
748 | ||
749 | msi_free( check ); | |
750 | msi_free( source ); | |
062070bf | 751 | msi_free( db ); |
c777d309 JH |
752 | |
753 | return ERROR_SUCCESS; | |
754 | } | |
755 | ||
5f11262d JH |
756 | static UINT msi_set_context(MSIPACKAGE *package) |
757 | { | |
758 | WCHAR val[10]; | |
759 | DWORD sz = 10; | |
760 | DWORD num; | |
761 | UINT r; | |
762 | ||
763 | static const WCHAR szOne[] = {'1',0}; | |
764 | static const WCHAR szAllUsers[] = {'A','L','L','U','S','E','R','S',0}; | |
765 | ||
766 | package->Context = MSIINSTALLCONTEXT_USERUNMANAGED; | |
767 | ||
768 | r = MSI_GetPropertyW(package, szAllUsers, val, &sz); | |
769 | if (r == ERROR_SUCCESS) | |
770 | { | |
771 | num = atolW(val); | |
772 | if (num == 1 || num == 2) | |
773 | package->Context = MSIINSTALLCONTEXT_MACHINE; | |
774 | } | |
775 | ||
776 | MSI_SetPropertyW(package, szAllUsers, szOne); | |
777 | return ERROR_SUCCESS; | |
778 | } | |
779 | ||
401bd3f7 AS |
780 | /**************************************************** |
781 | * TOP level entry points | |
782 | *****************************************************/ | |
783 | ||
61f24a4c MM |
784 | UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath, |
785 | LPCWSTR szCommandLine ) | |
401bd3f7 | 786 | { |
401bd3f7 | 787 | UINT rc; |
6da8041d | 788 | BOOL ui = FALSE, ui_exists; |
a7a6f5f3 | 789 | static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0}; |
6269f00c AS |
790 | static const WCHAR szAction[] = {'A','C','T','I','O','N',0}; |
791 | static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0}; | |
1169aa9a HL |
792 | static const WCHAR szReinstall[] = {'R','E','I','N','S','T','A','L','L',0}; |
793 | static const WCHAR szInstalled[] = {'I','n','s','t','a','l','l','e','d',0}; | |
794 | static const WCHAR szAll[] = {'A','L','L',0}; | |
6269f00c AS |
795 | |
796 | MSI_SetPropertyW(package, szAction, szInstall); | |
9cd707da | 797 | |
3a94011a | 798 | package->script = msi_alloc_zero(sizeof(MSISCRIPT)); |
401bd3f7 | 799 | |
c9802931 AS |
800 | package->script->InWhatSequence = SEQUENCE_INSTALL; |
801 | ||
e95136b7 AS |
802 | if (szPackagePath) |
803 | { | |
c777d309 | 804 | LPWSTR p, dir; |
0e14c29d | 805 | LPCWSTR file; |
08443b3b JH |
806 | |
807 | dir = strdupW(szPackagePath); | |
808 | p = strrchrW(dir, '\\'); | |
e95136b7 | 809 | if (p) |
0e14c29d | 810 | { |
08443b3b | 811 | *(++p) = 0; |
0e14c29d AT |
812 | file = szPackagePath + (p - dir); |
813 | } | |
08443b3b | 814 | else |
e95136b7 | 815 | { |
08443b3b JH |
816 | msi_free(dir); |
817 | dir = msi_alloc(MAX_PATH*sizeof(WCHAR)); | |
818 | GetCurrentDirectoryW(MAX_PATH, dir); | |
819 | lstrcatW(dir, cszbs); | |
0e14c29d | 820 | file = szPackagePath; |
e95136b7 | 821 | } |
08443b3b JH |
822 | |
823 | msi_free( package->PackagePath ); | |
0e14c29d | 824 | package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR)); |
08443b3b | 825 | if (!package->PackagePath) |
c1e5c4a9 | 826 | { |
08443b3b JH |
827 | msi_free(dir); |
828 | return ERROR_OUTOFMEMORY; | |
c1e5c4a9 | 829 | } |
e95136b7 | 830 | |
08443b3b | 831 | lstrcpyW(package->PackagePath, dir); |
0e14c29d | 832 | lstrcatW(package->PackagePath, file); |
08443b3b | 833 | msi_free(dir); |
c777d309 JH |
834 | |
835 | msi_set_sourcedir_props(package, FALSE); | |
e95136b7 | 836 | } |
401bd3f7 | 837 | |
ca71e5af | 838 | msi_parse_command_line( package, szCommandLine, FALSE ); |
74f0de96 | 839 | |
e534e772 | 840 | msi_apply_transforms( package ); |
965a72ad MM |
841 | msi_apply_patches( package ); |
842 | ||
1169aa9a HL |
843 | if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 )) |
844 | { | |
845 | TRACE("setting reinstall property\n"); | |
846 | MSI_SetPropertyW( package, szReinstall, szAll ); | |
847 | } | |
848 | ||
30fc5602 JH |
849 | /* properties may have been added by a transform */ |
850 | msi_clone_properties( package ); | |
5f11262d | 851 | msi_set_context( package ); |
30fc5602 | 852 | |
d8b00a07 | 853 | if ( (msi_get_property_int(package, szUILevel, 0) & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED ) |
ed7c4bc8 | 854 | { |
74f0de96 MM |
855 | package->script->InWhatSequence |= SEQUENCE_UI; |
856 | rc = ACTION_ProcessUISequence(package); | |
857 | ui = TRUE; | |
6da8041d JH |
858 | ui_exists = ui_sequence_exists(package); |
859 | if (rc == ERROR_SUCCESS || !ui_exists) | |
ed7c4bc8 | 860 | { |
74f0de96 | 861 | package->script->InWhatSequence |= SEQUENCE_EXEC; |
6da8041d | 862 | rc = ACTION_ProcessExecSequence(package,ui_exists); |
ed7c4bc8 | 863 | } |
ed7c4bc8 AS |
864 | } |
865 | else | |
a7a6f5f3 | 866 | rc = ACTION_ProcessExecSequence(package,FALSE); |
ed7c4bc8 | 867 | |
9cd707da AS |
868 | package->script->CurrentlyScripting= FALSE; |
869 | ||
09d35c3c AS |
870 | /* process the ending type action */ |
871 | if (rc == ERROR_SUCCESS) | |
f8f64406 | 872 | ACTION_PerformActionSequence(package,-1,ui); |
6b16f29f | 873 | else if (rc == ERROR_INSTALL_USEREXIT) |
f8f64406 | 874 | ACTION_PerformActionSequence(package,-2,ui); |
6b16f29f | 875 | else if (rc == ERROR_INSTALL_SUSPEND) |
f8f64406 | 876 | ACTION_PerformActionSequence(package,-4,ui); |
9cd707da AS |
877 | else /* failed */ |
878 | ACTION_PerformActionSequence(package,-3,ui); | |
54c67dd1 AS |
879 | |
880 | /* finish up running custom actions */ | |
881 | ACTION_FinishCustomActions(package); | |
09d35c3c | 882 | |
9c8b83ce HL |
883 | if (rc == ERROR_SUCCESS && package->need_reboot) |
884 | return ERROR_SUCCESS_REBOOT_REQUIRED; | |
885 | ||
ed7c4bc8 AS |
886 | return rc; |
887 | } | |
888 | ||
f8f64406 | 889 | static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI) |
09d35c3c | 890 | { |
0b352c7f | 891 | UINT rc = ERROR_SUCCESS; |
09d35c3c | 892 | MSIRECORD * row = 0; |
8e233e9b AS |
893 | static const WCHAR ExecSeqQuery[] = |
894 | {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', | |
98e38082 AS |
895 | '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e', |
896 | 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ', | |
897 | '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0}; | |
09d35c3c | 898 | |
f8f64406 AS |
899 | static const WCHAR UISeqQuery[] = |
900 | {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', | |
98e38082 AS |
901 | '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e', |
902 | '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`', | |
f8f64406 AS |
903 | ' ', '=',' ','%','i',0}; |
904 | ||
905 | if (UI) | |
0b352c7f | 906 | row = MSI_QueryGetRecord(package->db, UISeqQuery, seq); |
f8f64406 | 907 | else |
0b352c7f | 908 | row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq); |
09d35c3c | 909 | |
0b352c7f | 910 | if (row) |
09d35c3c | 911 | { |
20806c73 MM |
912 | LPCWSTR action, cond; |
913 | ||
09d35c3c AS |
914 | TRACE("Running the actions\n"); |
915 | ||
09d35c3c | 916 | /* check conditions */ |
20806c73 | 917 | cond = MSI_RecordGetString(row,2); |
9375fd9f MM |
918 | |
919 | /* this is a hack to skip errors in the condition code */ | |
920 | if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE) | |
921 | goto end; | |
09d35c3c | 922 | |
20806c73 MM |
923 | action = MSI_RecordGetString(row,1); |
924 | if (!action) | |
09d35c3c | 925 | { |
20806c73 MM |
926 | ERR("failed to fetch action\n"); |
927 | rc = ERROR_FUNCTION_FAILED; | |
09d35c3c AS |
928 | goto end; |
929 | } | |
930 | ||
f8f64406 | 931 | if (UI) |
8a94f7aa | 932 | rc = ACTION_PerformUIAction(package,action,-1); |
f8f64406 | 933 | else |
8a94f7aa | 934 | rc = ACTION_PerformAction(package,action,-1,FALSE); |
09d35c3c | 935 | end: |
0b352c7f | 936 | msiobj_release(&row->hdr); |
09d35c3c AS |
937 | } |
938 | else | |
939 | rc = ERROR_SUCCESS; | |
940 | ||
941 | return rc; | |
942 | } | |
ed7c4bc8 | 943 | |
2703d717 AS |
944 | typedef struct { |
945 | MSIPACKAGE* package; | |
946 | BOOL UI; | |
947 | } iterate_action_param; | |
948 | ||
949 | static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param) | |
950 | { | |
5f3ac30b | 951 | iterate_action_param *iap = param; |
2703d717 AS |
952 | UINT rc; |
953 | LPCWSTR cond, action; | |
954 | ||
955 | action = MSI_RecordGetString(row,1); | |
956 | if (!action) | |
957 | { | |
958 | ERR("Error is retrieving action name\n"); | |
9375fd9f | 959 | return ERROR_FUNCTION_FAILED; |
2703d717 AS |
960 | } |
961 | ||
962 | /* check conditions */ | |
963 | cond = MSI_RecordGetString(row,2); | |
9375fd9f MM |
964 | |
965 | /* this is a hack to skip errors in the condition code */ | |
966 | if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE) | |
2703d717 | 967 | { |
9375fd9f MM |
968 | TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action)); |
969 | return ERROR_SUCCESS; | |
2703d717 AS |
970 | } |
971 | ||
972 | if (iap->UI) | |
8a94f7aa | 973 | rc = ACTION_PerformUIAction(iap->package,action,-1); |
2703d717 | 974 | else |
8a94f7aa | 975 | rc = ACTION_PerformAction(iap->package,action,-1,FALSE); |
2703d717 | 976 | |
4f634a3b MM |
977 | msi_dialog_check_messages( NULL ); |
978 | ||
979 | if (iap->package->CurrentInstallState != ERROR_SUCCESS ) | |
980 | rc = iap->package->CurrentInstallState; | |
981 | ||
2703d717 AS |
982 | if (rc == ERROR_FUNCTION_NOT_CALLED) |
983 | rc = ERROR_SUCCESS; | |
984 | ||
985 | if (rc != ERROR_SUCCESS) | |
558abec8 | 986 | ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc); |
2703d717 AS |
987 | |
988 | return rc; | |
989 | } | |
990 | ||
d34b1c23 MM |
991 | UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode ) |
992 | { | |
993 | MSIQUERY * view; | |
994 | UINT r; | |
995 | static const WCHAR query[] = | |
996 | {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', | |
997 | '`','%','s','`', | |
998 | ' ','W','H','E','R','E',' ', | |
999 | '`','S','e','q','u','e','n','c','e','`',' ', | |
1000 | '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ', | |
1001 | '`','S','e','q','u','e','n','c','e','`',0}; | |
1002 | iterate_action_param iap; | |
1003 | ||
1004 | /* | |
1005 | * FIXME: probably should be checking UILevel in the | |
1006 | * ACTION_PerformUIAction/ACTION_PerformAction | |
1007 | * rather than saving the UI level here. Those | |
1008 | * two functions can be merged too. | |
1009 | */ | |
1010 | iap.package = package; | |
1011 | iap.UI = TRUE; | |
1012 | ||
1013 | TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode ); | |
1014 | ||
1015 | r = MSI_OpenQuery( package->db, &view, query, szTable ); | |
1016 | if (r == ERROR_SUCCESS) | |
1017 | { | |
1018 | r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap ); | |
1019 | msiobj_release(&view->hdr); | |
1020 | } | |
1021 | ||
1022 | return r; | |
1023 | } | |
1024 | ||
a7a6f5f3 | 1025 | static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran) |
ed7c4bc8 | 1026 | { |
a7a6f5f3 | 1027 | MSIQUERY * view; |
ed7c4bc8 | 1028 | UINT rc; |
8e233e9b AS |
1029 | static const WCHAR ExecSeqQuery[] = |
1030 | {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', | |
98e38082 AS |
1031 | '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e', |
1032 | 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ', | |
1033 | '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ', | |
8e233e9b | 1034 | 'O','R','D','E','R',' ', 'B','Y',' ', |
98e38082 | 1035 | '`','S','e','q','u','e','n','c','e','`',0 }; |
a7a6f5f3 | 1036 | MSIRECORD * row = 0; |
8e233e9b | 1037 | static const WCHAR IVQuery[] = |
98e38082 AS |
1038 | {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`', |
1039 | ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l', | |
1040 | 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ', | |
1041 | 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=', | |
1042 | ' ','\'', 'I','n','s','t','a','l','l', | |
1043 | 'V','a','l','i','d','a','t','e','\'', 0}; | |
9db0e072 | 1044 | INT seq = 0; |
2703d717 | 1045 | iterate_action_param iap; |
ed7c4bc8 | 1046 | |
2703d717 AS |
1047 | iap.package = package; |
1048 | iap.UI = FALSE; | |
b6bc6aa6 | 1049 | |
9cd707da | 1050 | if (package->script->ExecuteSequenceRun) |
b6bc6aa6 AS |
1051 | { |
1052 | TRACE("Execute Sequence already Run\n"); | |
1053 | return ERROR_SUCCESS; | |
1054 | } | |
1055 | ||
9cd707da | 1056 | package->script->ExecuteSequenceRun = TRUE; |
2703d717 | 1057 | |
9db0e072 | 1058 | /* get the sequence number */ |
ed7c4bc8 AS |
1059 | if (UIran) |
1060 | { | |
0b352c7f MM |
1061 | row = MSI_QueryGetRecord(package->db, IVQuery); |
1062 | if( !row ) | |
1063 | return ERROR_FUNCTION_FAILED; | |
a7a6f5f3 AJ |
1064 | seq = MSI_RecordGetInteger(row,1); |
1065 | msiobj_release(&row->hdr); | |
ed7c4bc8 | 1066 | } |
9db0e072 | 1067 | |
0c238856 | 1068 | rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq); |
401bd3f7 AS |
1069 | if (rc == ERROR_SUCCESS) |
1070 | { | |
2703d717 | 1071 | TRACE("Running the actions\n"); |
401bd3f7 | 1072 | |
2703d717 | 1073 | rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap); |
a7a6f5f3 | 1074 | msiobj_release(&view->hdr); |
401bd3f7 AS |
1075 | } |
1076 | ||
401bd3f7 AS |
1077 | return rc; |
1078 | } | |
1079 | ||
a7a6f5f3 | 1080 | static UINT ACTION_ProcessUISequence(MSIPACKAGE *package) |
ed7c4bc8 | 1081 | { |
a7a6f5f3 | 1082 | MSIQUERY * view; |
ed7c4bc8 | 1083 | UINT rc; |
8e233e9b AS |
1084 | static const WCHAR ExecSeqQuery [] = |
1085 | {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', | |
98e38082 AS |
1086 | '`','I','n','s','t','a','l','l', |
1087 | 'U','I','S','e','q','u','e','n','c','e','`', | |
1088 | ' ','W','H','E','R','E',' ', | |
1089 | '`','S','e','q','u','e','n','c','e','`',' ', | |
8e233e9b | 1090 | '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ', |
98e38082 | 1091 | '`','S','e','q','u','e','n','c','e','`',0}; |
2703d717 AS |
1092 | iterate_action_param iap; |
1093 | ||
1094 | iap.package = package; | |
1095 | iap.UI = TRUE; | |
1096 | ||
a7a6f5f3 | 1097 | rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); |
ed7c4bc8 AS |
1098 | |
1099 | if (rc == ERROR_SUCCESS) | |
1100 | { | |
0edbaf7e | 1101 | TRACE("Running the actions\n"); |
ed7c4bc8 | 1102 | |
2703d717 | 1103 | rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap); |
a7a6f5f3 | 1104 | msiobj_release(&view->hdr); |
ed7c4bc8 AS |
1105 | } |
1106 | ||
ed7c4bc8 AS |
1107 | return rc; |
1108 | } | |
1109 | ||
401bd3f7 AS |
1110 | /******************************************************** |
1111 | * ACTION helper functions and functions that perform the actions | |
1112 | *******************************************************/ | |
f9acfe63 | 1113 | static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action, |
8a94f7aa | 1114 | UINT* rc, UINT script, BOOL force ) |
3f318609 AS |
1115 | { |
1116 | BOOL ret=FALSE; | |
1117 | UINT arc; | |
1118 | ||
8a94f7aa | 1119 | arc = ACTION_CustomAction(package, action, script, force); |
3f318609 AS |
1120 | |
1121 | if (arc != ERROR_CALL_NOT_IMPLEMENTED) | |
1122 | { | |
1123 | *rc = arc; | |
1124 | ret = TRUE; | |
1125 | } | |
1126 | return ret; | |
1127 | } | |
401bd3f7 AS |
1128 | |
1129 | /* | |
da8b3dd7 FG |
1130 | * A lot of actions are really important even if they don't do anything |
1131 | * explicit... Lots of properties are set at the beginning of the installation | |
1132 | * CostFinalize does a bunch of work to translate the directories and such | |
401bd3f7 | 1133 | * |
6e2bca34 | 1134 | * But until I get write access to the database that is hard, so I am going to |
401bd3f7 AS |
1135 | * hack it to see if I can get something to run. |
1136 | */ | |
8a94f7aa | 1137 | UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force) |
401bd3f7 | 1138 | { |
d2c395ad | 1139 | UINT rc = ERROR_SUCCESS; |
3f318609 | 1140 | BOOL handled; |
401bd3f7 AS |
1141 | |
1142 | TRACE("Performing action (%s)\n",debugstr_w(action)); | |
7d3e5973 | 1143 | |
9cd707da | 1144 | handled = ACTION_HandleStandardAction(package, action, &rc, force); |
3f318609 AS |
1145 | |
1146 | if (!handled) | |
8a94f7aa | 1147 | handled = ACTION_HandleCustomAction(package, action, &rc, script, force); |
3f318609 AS |
1148 | |
1149 | if (!handled) | |
90c57396 | 1150 | { |
c48daf93 | 1151 | WARN("unhandled msi action %s\n",debugstr_w(action)); |
3f318609 | 1152 | rc = ERROR_FUNCTION_NOT_CALLED; |
90c57396 | 1153 | } |
c75201f4 | 1154 | |
3f318609 AS |
1155 | return rc; |
1156 | } | |
1157 | ||
8a94f7aa | 1158 | UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script) |
3f318609 AS |
1159 | { |
1160 | UINT rc = ERROR_SUCCESS; | |
1161 | BOOL handled = FALSE; | |
1162 | ||
1163 | TRACE("Performing action (%s)\n",debugstr_w(action)); | |
1164 | ||
9cd707da | 1165 | handled = ACTION_HandleStandardAction(package, action, &rc,TRUE); |
3f318609 | 1166 | |
90c57396 | 1167 | if (!handled) |
8a94f7aa | 1168 | handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE); |
90c57396 | 1169 | |
4f634a3b MM |
1170 | if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS ) |
1171 | handled = TRUE; | |
34d4a02b | 1172 | |
3f318609 AS |
1173 | if (!handled) |
1174 | { | |
c48daf93 | 1175 | WARN("unhandled msi action %s\n",debugstr_w(action)); |
3f318609 | 1176 | rc = ERROR_FUNCTION_NOT_CALLED; |
90c57396 | 1177 | } |
401bd3f7 | 1178 | |
d2c395ad | 1179 | return rc; |
401bd3f7 AS |
1180 | } |
1181 | ||
2274ff19 AS |
1182 | |
1183 | /* | |
1184 | * Actual Action Handlers | |
1185 | */ | |
1186 | ||
1187 | static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param) | |
1188 | { | |
5f3ac30b | 1189 | MSIPACKAGE *package = param; |
2274ff19 AS |
1190 | LPCWSTR dir; |
1191 | LPWSTR full_path; | |
1192 | MSIRECORD *uirow; | |
1193 | MSIFOLDER *folder; | |
1194 | ||
1195 | dir = MSI_RecordGetString(row,1); | |
1196 | if (!dir) | |
1197 | { | |
0edbaf7e | 1198 | ERR("Unable to get folder id\n"); |
2274ff19 AS |
1199 | return ERROR_SUCCESS; |
1200 | } | |
1201 | ||
8cedb218 | 1202 | full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder); |
2274ff19 AS |
1203 | if (!full_path) |
1204 | { | |
1205 | ERR("Unable to resolve folder id %s\n",debugstr_w(dir)); | |
1206 | return ERROR_SUCCESS; | |
1207 | } | |
1208 | ||
1209 | TRACE("Folder is %s\n",debugstr_w(full_path)); | |
1210 | ||
1211 | /* UI stuff */ | |
1212 | uirow = MSI_CreateRecord(1); | |
1213 | MSI_RecordSetStringW(uirow,1,full_path); | |
1214 | ui_actiondata(package,szCreateFolders,uirow); | |
1215 | msiobj_release( &uirow->hdr ); | |
1216 | ||
1217 | if (folder->State == 0) | |
1218 | create_full_pathW(full_path); | |
1219 | ||
1220 | folder->State = 3; | |
1221 | ||
ee034ba4 | 1222 | msi_free(full_path); |
2274ff19 AS |
1223 | return ERROR_SUCCESS; |
1224 | } | |
1225 | ||
03b4dbbd MM |
1226 | /* FIXME: probably should merge this with the above function */ |
1227 | static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir ) | |
1228 | { | |
1229 | UINT rc = ERROR_SUCCESS; | |
1230 | MSIFOLDER *folder; | |
1231 | LPWSTR install_path; | |
1232 | ||
8cedb218 | 1233 | install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder); |
03b4dbbd MM |
1234 | if (!install_path) |
1235 | return ERROR_FUNCTION_FAILED; | |
1236 | ||
1237 | /* create the path */ | |
1238 | if (folder->State == 0) | |
1239 | { | |
1240 | create_full_pathW(install_path); | |
1241 | folder->State = 2; | |
1242 | } | |
1243 | msi_free(install_path); | |
1244 | ||
1245 | return rc; | |
1246 | } | |
2274ff19 | 1247 | |
9c845851 MM |
1248 | UINT msi_create_component_directories( MSIPACKAGE *package ) |
1249 | { | |
1250 | MSICOMPONENT *comp; | |
1251 | ||
1252 | /* create all the folders required by the components are going to install */ | |
1253 | LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) | |
1254 | { | |
d693f461 | 1255 | if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL)) |
9c845851 MM |
1256 | continue; |
1257 | msi_create_directory( package, comp->Directory ); | |
1258 | } | |
1259 | ||
1260 | return ERROR_SUCCESS; | |
1261 | } | |
1262 | ||
401bd3f7 AS |
1263 | /* |
1264 | * Also we cannot enable/disable components either, so for now I am just going | |
6e2bca34 | 1265 | * to do all the directories for all the components. |
401bd3f7 | 1266 | */ |
a7a6f5f3 | 1267 | static UINT ACTION_CreateFolders(MSIPACKAGE *package) |
401bd3f7 | 1268 | { |
8e233e9b | 1269 | static const WCHAR ExecSeqQuery[] = |
98e38082 AS |
1270 | {'S','E','L','E','C','T',' ', |
1271 | '`','D','i','r','e','c','t','o','r','y','_','`', | |
8e233e9b | 1272 | ' ','F','R','O','M',' ', |
98e38082 | 1273 | '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 }; |
401bd3f7 | 1274 | UINT rc; |
a7a6f5f3 | 1275 | MSIQUERY *view; |
eb0e0df9 | 1276 | |
03b4dbbd | 1277 | /* create all the empty folders specified in the CreateFolder table */ |
a7a6f5f3 | 1278 | rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view ); |
401bd3f7 | 1279 | if (rc != ERROR_SUCCESS) |
84837d96 | 1280 | return ERROR_SUCCESS; |
401bd3f7 | 1281 | |
2274ff19 | 1282 | rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package); |
a7a6f5f3 | 1283 | msiobj_release(&view->hdr); |
03b4dbbd | 1284 | |
9c845851 | 1285 | msi_create_component_directories( package ); |
03b4dbbd | 1286 | |
401bd3f7 AS |
1287 | return rc; |
1288 | } | |
1289 | ||
1d46cdf1 | 1290 | static UINT load_component( MSIRECORD *row, LPVOID param ) |
bdb29552 | 1291 | { |
1d46cdf1 | 1292 | MSIPACKAGE *package = param; |
38d67a45 | 1293 | MSICOMPONENT *comp; |
bdb29552 | 1294 | |
ee034ba4 | 1295 | comp = msi_alloc_zero( sizeof(MSICOMPONENT) ); |
38d67a45 | 1296 | if (!comp) |
1d46cdf1 MM |
1297 | return ERROR_FUNCTION_FAILED; |
1298 | ||
1299 | list_add_tail( &package->components, &comp->entry ); | |
bdb29552 | 1300 | |
38d67a45 | 1301 | /* fill in the data */ |
51c6618d | 1302 | comp->Component = msi_dup_record_field( row, 1 ); |
bdb29552 | 1303 | |
efcc1ec5 | 1304 | TRACE("Loading Component %s\n", debugstr_w(comp->Component)); |
bdb29552 | 1305 | |
51c6618d MM |
1306 | comp->ComponentId = msi_dup_record_field( row, 2 ); |
1307 | comp->Directory = msi_dup_record_field( row, 3 ); | |
38d67a45 | 1308 | comp->Attributes = MSI_RecordGetInteger(row,4); |
51c6618d MM |
1309 | comp->Condition = msi_dup_record_field( row, 5 ); |
1310 | comp->KeyPath = msi_dup_record_field( row, 6 ); | |
bdb29552 | 1311 | |
d893cb7d | 1312 | comp->Installed = INSTALLSTATE_UNKNOWN; |
3bec162d | 1313 | msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN); |
fbdd7096 | 1314 | |
1d46cdf1 MM |
1315 | return ERROR_SUCCESS; |
1316 | } | |
1317 | ||
1318 | static UINT load_all_components( MSIPACKAGE *package ) | |
1319 | { | |
1320 | static const WCHAR query[] = { | |
1321 | 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ', | |
1322 | '`','C','o','m','p','o','n','e','n','t','`',0 }; | |
1323 | MSIQUERY *view; | |
1324 | UINT r; | |
1325 | ||
1326 | if (!list_empty(&package->components)) | |
1327 | return ERROR_SUCCESS; | |
bdb29552 | 1328 | |
1d46cdf1 MM |
1329 | r = MSI_DatabaseOpenViewW( package->db, query, &view ); |
1330 | if (r != ERROR_SUCCESS) | |
1331 | return r; | |
1332 | ||
1333 | r = MSI_IterateRecords(view, NULL, load_component, package); | |
1334 | msiobj_release(&view->hdr); | |
1335 | return r; | |
bdb29552 AS |
1336 | } |
1337 | ||
04598248 AS |
1338 | typedef struct { |
1339 | MSIPACKAGE *package; | |
1da2858c | 1340 | MSIFEATURE *feature; |
04598248 AS |
1341 | } _ilfs; |
1342 | ||
38d67a45 | 1343 | static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp ) |
3f2d5d7f MM |
1344 | { |
1345 | ComponentList *cl; | |
1346 | ||
ee034ba4 | 1347 | cl = msi_alloc( sizeof (*cl) ); |
3f2d5d7f MM |
1348 | if ( !cl ) |
1349 | return ERROR_NOT_ENOUGH_MEMORY; | |
38d67a45 | 1350 | cl->component = comp; |
1da2858c | 1351 | list_add_tail( &feature->Components, &cl->entry ); |
3f2d5d7f MM |
1352 | |
1353 | return ERROR_SUCCESS; | |
1354 | } | |
1355 | ||
545d0e70 JH |
1356 | static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child ) |
1357 | { | |
1358 | FeatureList *fl; | |
1359 | ||
1360 | fl = msi_alloc( sizeof(*fl) ); | |
1361 | if ( !fl ) | |
1362 | return ERROR_NOT_ENOUGH_MEMORY; | |
1363 | fl->feature = child; | |
1364 | list_add_tail( &parent->Children, &fl->entry ); | |
1365 | ||
1366 | return ERROR_SUCCESS; | |
1367 | } | |
1368 | ||
04598248 | 1369 | static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param) |
bdb29552 | 1370 | { |
5f3ac30b | 1371 | _ilfs* ilfs = param; |
04598248 | 1372 | LPCWSTR component; |
38d67a45 | 1373 | MSICOMPONENT *comp; |
04598248 AS |
1374 | |
1375 | component = MSI_RecordGetString(row,1); | |
1376 | ||
1377 | /* check to see if the component is already loaded */ | |
38d67a45 | 1378 | comp = get_loaded_component( ilfs->package, component ); |
1d46cdf1 | 1379 | if (!comp) |
04598248 | 1380 | { |
1d46cdf1 MM |
1381 | ERR("unknown component %s\n", debugstr_w(component)); |
1382 | return ERROR_FUNCTION_FAILED; | |
04598248 AS |
1383 | } |
1384 | ||
1d46cdf1 MM |
1385 | add_feature_component( ilfs->feature, comp ); |
1386 | comp->Enabled = TRUE; | |
04598248 AS |
1387 | |
1388 | return ERROR_SUCCESS; | |
1389 | } | |
1390 | ||
545d0e70 JH |
1391 | static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name ) |
1392 | { | |
1393 | MSIFEATURE *feature; | |
1394 | ||
bfe07d1d JH |
1395 | if ( !name ) |
1396 | return NULL; | |
1397 | ||
545d0e70 JH |
1398 | LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) |
1399 | { | |
1400 | if ( !lstrcmpW( feature->Feature, name ) ) | |
1401 | return feature; | |
1402 | } | |
1403 | ||
1404 | return NULL; | |
1405 | } | |
1406 | ||
04598248 AS |
1407 | static UINT load_feature(MSIRECORD * row, LPVOID param) |
1408 | { | |
5f3ac30b | 1409 | MSIPACKAGE* package = param; |
1da2858c | 1410 | MSIFEATURE* feature; |
8e233e9b | 1411 | static const WCHAR Query1[] = |
98e38082 AS |
1412 | {'S','E','L','E','C','T',' ', |
1413 | '`','C','o','m','p','o','n','e','n','t','_','`', | |
1414 | ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e', | |
1415 | 'C','o','m','p','o','n','e','n','t','s','`',' ', | |
1416 | 'W','H','E','R','E',' ', | |
1417 | '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0}; | |
a7a6f5f3 | 1418 | MSIQUERY * view; |
a7a6f5f3 | 1419 | UINT rc; |
04598248 AS |
1420 | _ilfs ilfs; |
1421 | ||
bdb29552 AS |
1422 | /* fill in the data */ |
1423 | ||
ee034ba4 | 1424 | feature = msi_alloc_zero( sizeof (MSIFEATURE) ); |
1da2858c MM |
1425 | if (!feature) |
1426 | return ERROR_NOT_ENOUGH_MEMORY; | |
3f2d5d7f | 1427 | |
545d0e70 | 1428 | list_init( &feature->Children ); |
1da2858c | 1429 | list_init( &feature->Components ); |
bdb29552 | 1430 | |
51c6618d | 1431 | feature->Feature = msi_dup_record_field( row, 1 ); |
bdb29552 | 1432 | |
1da2858c | 1433 | TRACE("Loading feature %s\n",debugstr_w(feature->Feature)); |
bdb29552 | 1434 | |
51c6618d MM |
1435 | feature->Feature_Parent = msi_dup_record_field( row, 2 ); |
1436 | feature->Title = msi_dup_record_field( row, 3 ); | |
1437 | feature->Description = msi_dup_record_field( row, 4 ); | |
bdb29552 | 1438 | |
a7a6f5f3 | 1439 | if (!MSI_RecordIsNull(row,5)) |
1da2858c | 1440 | feature->Display = MSI_RecordGetInteger(row,5); |
bdb29552 | 1441 | |
1da2858c | 1442 | feature->Level= MSI_RecordGetInteger(row,6); |
51c6618d | 1443 | feature->Directory = msi_dup_record_field( row, 7 ); |
1da2858c | 1444 | feature->Attributes = MSI_RecordGetInteger(row,8); |
bdb29552 | 1445 | |
ca5c1100 | 1446 | feature->Installed = INSTALLSTATE_UNKNOWN; |
d596ae29 | 1447 | msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN); |
fbdd7096 | 1448 | |
1da2858c | 1449 | list_add_tail( &package->features, &feature->entry ); |
bdb29552 AS |
1450 | |
1451 | /* load feature components */ | |
1452 | ||
1da2858c | 1453 | rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature ); |
a7a6f5f3 | 1454 | if (rc != ERROR_SUCCESS) |
04598248 | 1455 | return ERROR_SUCCESS; |
bdb29552 | 1456 | |
1da2858c MM |
1457 | ilfs.package = package; |
1458 | ilfs.feature = feature; | |
1459 | ||
04598248 | 1460 | MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs); |
a7a6f5f3 | 1461 | msiobj_release(&view->hdr); |
04598248 AS |
1462 | |
1463 | return ERROR_SUCCESS; | |
bdb29552 AS |
1464 | } |
1465 | ||
545d0e70 JH |
1466 | static UINT find_feature_children(MSIRECORD * row, LPVOID param) |
1467 | { | |
5f3ac30b | 1468 | MSIPACKAGE* package = param; |
545d0e70 JH |
1469 | MSIFEATURE *parent, *child; |
1470 | ||
1471 | child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) ); | |
1472 | if (!child) | |
1473 | return ERROR_FUNCTION_FAILED; | |
1474 | ||
1475 | if (!child->Feature_Parent) | |
1476 | return ERROR_SUCCESS; | |
1477 | ||
1478 | parent = find_feature_by_name( package, child->Feature_Parent ); | |
1479 | if (!parent) | |
1480 | return ERROR_FUNCTION_FAILED; | |
1481 | ||
1482 | add_feature_child( parent, child ); | |
1483 | return ERROR_SUCCESS; | |
1484 | } | |
1485 | ||
1d46cdf1 MM |
1486 | static UINT load_all_features( MSIPACKAGE *package ) |
1487 | { | |
1488 | static const WCHAR query[] = { | |
1489 | 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', | |
1490 | '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R', | |
1491 | ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0}; | |
1492 | MSIQUERY *view; | |
1493 | UINT r; | |
1494 | ||
1495 | if (!list_empty(&package->features)) | |
1496 | return ERROR_SUCCESS; | |
1497 | ||
1498 | r = MSI_DatabaseOpenViewW( package->db, query, &view ); | |
1499 | if (r != ERROR_SUCCESS) | |
1500 | return r; | |
1501 | ||
1502 | r = MSI_IterateRecords( view, NULL, load_feature, package ); | |
545d0e70 JH |
1503 | if (r != ERROR_SUCCESS) |
1504 | return r; | |
1505 | ||
1506 | r = MSI_IterateRecords( view, NULL, find_feature_children, package ); | |
1d46cdf1 | 1507 | msiobj_release( &view->hdr ); |
545d0e70 | 1508 | |
1d46cdf1 MM |
1509 | return r; |
1510 | } | |
1511 | ||
c1513be4 MM |
1512 | static LPWSTR folder_split_path(LPWSTR p, WCHAR ch) |
1513 | { | |
1514 | if (!p) | |
1515 | return p; | |
1516 | p = strchrW(p, ch); | |
1517 | if (!p) | |
1518 | return p; | |
1519 | *p = 0; | |
1520 | return p+1; | |
1521 | } | |
1522 | ||
4160722b JH |
1523 | static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file) |
1524 | { | |
1525 | static const WCHAR query[] = { | |
1526 | 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', | |
1527 | '`','M','s','i','F','i','l','e','H','a','s','h','`',' ', | |
1528 | 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0}; | |
1529 | MSIQUERY *view = NULL; | |
1277e1b5 | 1530 | MSIRECORD *row = NULL; |
4160722b JH |
1531 | UINT r; |
1532 | ||
1533 | TRACE("%s\n", debugstr_w(file->File)); | |
1534 | ||
1535 | r = MSI_OpenQuery(package->db, &view, query, file->File); | |
1536 | if (r != ERROR_SUCCESS) | |
1537 | goto done; | |
1538 | ||
1539 | r = MSI_ViewExecute(view, NULL); | |
1540 | if (r != ERROR_SUCCESS) | |
1541 | goto done; | |
1542 | ||
1543 | r = MSI_ViewFetch(view, &row); | |
1544 | if (r != ERROR_SUCCESS) | |
1545 | goto done; | |
1546 | ||
1547 | file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO); | |
1548 | file->hash.dwData[0] = MSI_RecordGetInteger(row, 3); | |
1549 | file->hash.dwData[1] = MSI_RecordGetInteger(row, 4); | |
1550 | file->hash.dwData[2] = MSI_RecordGetInteger(row, 5); | |
1551 | file->hash.dwData[3] = MSI_RecordGetInteger(row, 6); | |
1552 | ||
1553 | done: | |
1554 | if (view) msiobj_release(&view->hdr); | |
1277e1b5 | 1555 | if (row) msiobj_release(&row->hdr); |
4160722b JH |
1556 | return r; |
1557 | } | |
1558 | ||
04598248 | 1559 | static UINT load_file(MSIRECORD *row, LPVOID param) |
ec688fb4 | 1560 | { |
5f3ac30b | 1561 | MSIPACKAGE* package = param; |
09b0abaa | 1562 | LPCWSTR component; |
e18f8abe | 1563 | MSIFILE *file; |
ec688fb4 AS |
1564 | |
1565 | /* fill in the data */ | |
1566 | ||
ee034ba4 | 1567 | file = msi_alloc_zero( sizeof (MSIFILE) ); |
e18f8abe MM |
1568 | if (!file) |
1569 | return ERROR_NOT_ENOUGH_MEMORY; | |
9db0e072 | 1570 | |
51c6618d | 1571 | file->File = msi_dup_record_field( row, 1 ); |
ec688fb4 | 1572 | |
e18f8abe MM |
1573 | component = MSI_RecordGetString( row, 2 ); |
1574 | file->Component = get_loaded_component( package, component ); | |
09b0abaa | 1575 | |
e18f8abe | 1576 | if (!file->Component) |
9a8d2f3f JH |
1577 | { |
1578 | WARN("Component not found: %s\n", debugstr_w(component)); | |
1579 | msi_free(file->File); | |
1580 | msi_free(file); | |
1581 | return ERROR_SUCCESS; | |
1582 | } | |
bdb29552 | 1583 | |
51c6618d | 1584 | file->FileName = msi_dup_record_field( row, 3 ); |
e18f8abe | 1585 | reduce_to_longfilename( file->FileName ); |
98d9cec7 | 1586 | |
51c6618d | 1587 | file->ShortName = msi_dup_record_field( row, 3 ); |
c1513be4 | 1588 | file->LongName = strdupW( folder_split_path(file->ShortName, '|')); |
ec688fb4 | 1589 | |
e18f8abe | 1590 | file->FileSize = MSI_RecordGetInteger( row, 4 ); |
51c6618d MM |
1591 | file->Version = msi_dup_record_field( row, 5 ); |
1592 | file->Language = msi_dup_record_field( row, 6 ); | |
e18f8abe MM |
1593 | file->Attributes = MSI_RecordGetInteger( row, 7 ); |
1594 | file->Sequence = MSI_RecordGetInteger( row, 8 ); | |
1595 | ||
dded8fb7 | 1596 | file->state = msifs_invalid; |
ec688fb4 | 1597 | |
f84fa0ce JH |
1598 | /* if the compressed bits are not set in the file attributes, |
1599 | * then read the information from the package word count property | |
1600 | */ | |
f80b5f6e JH |
1601 | if (package->WordCount & msidbSumInfoSourceTypeAdminImage) |
1602 | { | |
1603 | file->IsCompressed = FALSE; | |
1604 | } | |
1605 | else if (file->Attributes & | |
1606 | (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded)) | |
f84fa0ce JH |
1607 | { |
1608 | file->IsCompressed = TRUE; | |
1609 | } | |
1610 | else if (file->Attributes & msidbFileAttributesNoncompressed) | |
1611 | { | |
1612 | file->IsCompressed = FALSE; | |
1613 | } | |
1614 | else | |
1615 | { | |
7538f9ac | 1616 | file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed; |
f84fa0ce JH |
1617 | } |
1618 | ||
4160722b JH |
1619 | load_file_hash(package, file); |
1620 | ||
e18f8abe | 1621 | TRACE("File Loaded (%s)\n",debugstr_w(file->File)); |
ec688fb4 | 1622 | |
e18f8abe | 1623 | list_add_tail( &package->files, &file->entry ); |
ec688fb4 AS |
1624 | |
1625 | return ERROR_SUCCESS; | |
1626 | } | |
1627 | ||
c5a1443f | 1628 | static UINT load_all_files(MSIPACKAGE *package) |
ec688fb4 | 1629 | { |
a7a6f5f3 | 1630 | MSIQUERY * view; |
ec688fb4 | 1631 | UINT rc; |
8e233e9b AS |
1632 | static const WCHAR Query[] = |
1633 | {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', | |
98e38082 AS |
1634 | '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ', |
1635 | '`','S','e','q','u','e','n','c','e','`', 0}; | |
ec688fb4 | 1636 | |
9a9195d6 MM |
1637 | if (!list_empty(&package->files)) |
1638 | return ERROR_SUCCESS; | |
1639 | ||
a7a6f5f3 | 1640 | rc = MSI_DatabaseOpenViewW(package->db, Query, &view); |
ec688fb4 | 1641 | if (rc != ERROR_SUCCESS) |
84837d96 | 1642 | return ERROR_SUCCESS; |
ec688fb4 | 1643 | |
04598248 | 1644 | rc = MSI_IterateRecords(view, NULL, load_file, package); |
a7a6f5f3 | 1645 | msiobj_release(&view->hdr); |
bdb29552 AS |
1646 | |
1647 | return ERROR_SUCCESS; | |
1648 | } | |
1649 | ||
7eb27026 MM |
1650 | static UINT load_folder( MSIRECORD *row, LPVOID param ) |
1651 | { | |
1652 | MSIPACKAGE *package = param; | |
1653 | static const WCHAR szDot[] = { '.',0 }; | |
1654 | static WCHAR szEmpty[] = { 0 }; | |
1655 | LPWSTR p, tgt_short, tgt_long, src_short, src_long; | |
1656 | MSIFOLDER *folder; | |
1657 | ||
1658 | folder = msi_alloc_zero( sizeof (MSIFOLDER) ); | |
1659 | if (!folder) | |
1660 | return ERROR_NOT_ENOUGH_MEMORY; | |
1661 | ||
1662 | folder->Directory = msi_dup_record_field( row, 1 ); | |
1663 | ||
1664 | TRACE("%s\n", debugstr_w(folder->Directory)); | |
1665 | ||
1666 | p = msi_dup_record_field(row, 3); | |
1667 | ||
1668 | /* split src and target dir */ | |
1669 | tgt_short = p; | |
1670 | src_short = folder_split_path( p, ':' ); | |
1671 | ||
1672 | /* split the long and short paths */ | |
1673 | tgt_long = folder_split_path( tgt_short, '|' ); | |
1674 | src_long = folder_split_path( src_short, '|' ); | |
1675 | ||
1676 | /* check for no-op dirs */ | |
1677 | if (!lstrcmpW(szDot, tgt_short)) | |
1678 | tgt_short = szEmpty; | |
1679 | if (!lstrcmpW(szDot, src_short)) | |
1680 | src_short = szEmpty; | |
1681 | ||
1682 | if (!tgt_long) | |
1683 | tgt_long = tgt_short; | |
1684 | ||
1685 | if (!src_short) { | |
1686 | src_short = tgt_short; | |
1687 | src_long = tgt_long; | |
1688 | } | |
1689 | ||
1690 | if (!src_long) | |
1691 | src_long = src_short; | |
1692 | ||
1693 | /* FIXME: use the target short path too */ | |
1694 | folder->TargetDefault = strdupW(tgt_long); | |
1695 | folder->SourceShortPath = strdupW(src_short); | |
1696 | folder->SourceLongPath = strdupW(src_long); | |
1697 | msi_free(p); | |
1698 | ||
1699 | TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault )); | |
1700 | TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath )); | |
1701 | TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath )); | |
1702 | ||
1703 | folder->Parent = msi_dup_record_field( row, 2 ); | |
1704 | ||
1705 | folder->Property = msi_dup_property( package, folder->Directory ); | |
1706 | ||
1707 | list_add_tail( &package->folders, &folder->entry ); | |
1708 | ||
1709 | TRACE("returning %p\n", folder); | |
1710 | ||
1711 | return ERROR_SUCCESS; | |
1712 | } | |
1713 | ||
1714 | static UINT load_all_folders( MSIPACKAGE *package ) | |
1715 | { | |
1716 | static const WCHAR query[] = { | |
1717 | 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ', | |
1718 | '`','D','i','r','e','c','t','o','r','y','`',0 }; | |
1719 | MSIQUERY *view; | |
1720 | UINT r; | |
1721 | ||
1722 | if (!list_empty(&package->folders)) | |
1723 | return ERROR_SUCCESS; | |
1724 | ||
1725 | r = MSI_DatabaseOpenViewW( package->db, query, &view ); | |
1726 | if (r != ERROR_SUCCESS) | |
1727 | return r; | |
1728 | ||
1729 | r = MSI_IterateRecords(view, NULL, load_folder, package); | |
1730 | msiobj_release(&view->hdr); | |
1731 | return r; | |
1732 | } | |
c5a1443f AS |
1733 | |
1734 | /* | |
9a9195d6 | 1735 | * I am not doing any of the costing functionality yet. |
c5a1443f AS |
1736 | * Mostly looking at doing the Component and Feature loading |
1737 | * | |
1738 | * The native MSI does A LOT of modification to tables here. Mostly adding | |
9a9195d6 | 1739 | * a lot of temporary columns to the Feature and Component tables. |
c5a1443f AS |
1740 | * |
1741 | * note: Native msi also tracks the short filename. But I am only going to | |
1742 | * track the long ones. Also looking at this directory table | |
1743 | * it appears that the directory table does not get the parents | |
9a9195d6 | 1744 | * resolved base on property only based on their entries in the |
c5a1443f AS |
1745 | * directory table. |
1746 | */ | |
1747 | static UINT ACTION_CostInitialize(MSIPACKAGE *package) | |
1748 | { | |
c5a1443f AS |
1749 | static const WCHAR szCosting[] = |
1750 | {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 }; | |
1751 | static const WCHAR szZero[] = { '0', 0 }; | |
c5a1443f | 1752 | |
c5a1443f | 1753 | MSI_SetPropertyW(package, szCosting, szZero); |
1d46cdf1 | 1754 | MSI_SetPropertyW(package, cszRootDrive, c_colon); |
c5a1443f | 1755 | |
dbbd5ca7 | 1756 | load_all_folders( package ); |
1d46cdf1 MM |
1757 | load_all_components( package ); |
1758 | load_all_features( package ); | |
1759 | load_all_files( package ); | |
c5a1443f AS |
1760 | |
1761 | return ERROR_SUCCESS; | |
1762 | } | |
1763 | ||
f9acfe63 | 1764 | static UINT execute_script(MSIPACKAGE *package, UINT script ) |
9cd707da | 1765 | { |
bb54ed13 | 1766 | UINT i; |
9cd707da AS |
1767 | UINT rc = ERROR_SUCCESS; |
1768 | ||
1769 | TRACE("Executing Script %i\n",script); | |
1770 | ||
aa81e4fa MM |
1771 | if (!package->script) |
1772 | { | |
1773 | ERR("no script!\n"); | |
1774 | return ERROR_FUNCTION_FAILED; | |
1775 | } | |
1776 | ||
9cd707da AS |
1777 | for (i = 0; i < package->script->ActionCount[script]; i++) |
1778 | { | |
1779 | LPWSTR action; | |
1780 | action = package->script->Actions[script][i]; | |
1781 | ui_actionstart(package, action); | |
1782 | TRACE("Executing Action (%s)\n",debugstr_w(action)); | |
8a94f7aa | 1783 | rc = ACTION_PerformAction(package, action, script, TRUE); |
9cd707da AS |
1784 | if (rc != ERROR_SUCCESS) |
1785 | break; | |
1786 | } | |
f86cfd40 | 1787 | msi_free_action_script(package, script); |
9cd707da AS |
1788 | return rc; |
1789 | } | |
1790 | ||
c5a1443f AS |
1791 | static UINT ACTION_FileCost(MSIPACKAGE *package) |
1792 | { | |
1793 | return ERROR_SUCCESS; | |
1794 | } | |
1795 | ||
b7669153 | 1796 | static void ACTION_GetComponentInstallStates(MSIPACKAGE *package) |
78a04e39 | 1797 | { |
38d67a45 | 1798 | MSICOMPONENT *comp; |
42115638 JH |
1799 | INSTALLSTATE state; |
1800 | UINT r; | |
78a04e39 | 1801 | |
42115638 | 1802 | state = MsiQueryProductStateW(package->ProductCode); |
32f57022 | 1803 | |
42115638 JH |
1804 | LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry) |
1805 | { | |
32f57022 JH |
1806 | if (!comp->ComponentId) |
1807 | continue; | |
1808 | ||
42115638 JH |
1809 | if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT) |
1810 | comp->Installed = INSTALLSTATE_ABSENT; | |
1811 | else | |
1812 | { | |
1813 | r = MsiQueryComponentStateW(package->ProductCode, NULL, | |
1814 | package->Context, comp->ComponentId, | |
1815 | &comp->Installed); | |
1816 | if (r != ERROR_SUCCESS) | |
1817 | comp->Installed = INSTALLSTATE_ABSENT; | |
1818 | } | |
78a04e39 | 1819 | } |
b7669153 MM |
1820 | } |
1821 | ||
5a3c3b6a | 1822 | static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package) |
b7669153 | 1823 | { |
b7669153 | 1824 | MSIFEATURE *feature; |
5a3c3b6a JH |
1825 | INSTALLSTATE state; |
1826 | ||
1827 | state = MsiQueryProductStateW(package->ProductCode); | |
78a04e39 | 1828 | |
1da2858c | 1829 | LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) |
78a04e39 | 1830 | { |
5a3c3b6a JH |
1831 | if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT) |
1832 | feature->Installed = INSTALLSTATE_ABSENT; | |
1833 | else | |
78a04e39 | 1834 | { |
5a3c3b6a JH |
1835 | feature->Installed = MsiQueryFeatureStateW(package->ProductCode, |
1836 | feature->Feature); | |
78a04e39 AS |
1837 | } |
1838 | } | |
1839 | } | |
1840 | ||
c855fbfc JH |
1841 | static BOOL process_state_property(MSIPACKAGE* package, int level, |
1842 | LPCWSTR property, INSTALLSTATE state) | |
ae1aa32c | 1843 | { |
ae1aa32c | 1844 | static const WCHAR all[]={'A','L','L',0}; |
c855fbfc | 1845 | static const WCHAR remove[] = {'R','E','M','O','V','E',0}; |
40cfbaf0 | 1846 | static const WCHAR reinstall[] = {'R','E','I','N','S','T','A','L','L',0}; |
72faac0d | 1847 | LPWSTR override; |
1da2858c | 1848 | MSIFEATURE *feature; |
ae1aa32c | 1849 | |
062ad505 | 1850 | override = msi_dup_property( package, property ); |
72faac0d MM |
1851 | if (!override) |
1852 | return FALSE; | |
575cc67d | 1853 | |
72faac0d | 1854 | LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) |
ae1aa32c | 1855 | { |
c855fbfc JH |
1856 | if (lstrcmpW(property, remove) && |
1857 | (feature->Level <= 0 || feature->Level > level)) | |
1858 | continue; | |
1859 | ||
40cfbaf0 HL |
1860 | if (!strcmpW(property, reinstall)) state = feature->Installed; |
1861 | ||
72faac0d | 1862 | if (strcmpiW(override,all)==0) |
d596ae29 | 1863 | msi_feature_set_state(package, feature, state); |
72faac0d MM |
1864 | else |
1865 | { | |
1866 | LPWSTR ptr = override; | |
1867 | LPWSTR ptr2 = strchrW(override,','); | |
d900b539 | 1868 | |
72faac0d MM |
1869 | while (ptr) |
1870 | { | |
1871 | if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0) | |
1872 | || (!ptr2 && strcmpW(ptr,feature->Feature)==0)) | |
d900b539 | 1873 | { |
d596ae29 | 1874 | msi_feature_set_state(package, feature, state); |
72faac0d | 1875 | break; |
d900b539 | 1876 | } |
72faac0d MM |
1877 | if (ptr2) |
1878 | { | |
1879 | ptr=ptr2+1; | |
1880 | ptr2 = strchrW(ptr,','); | |
1881 | } | |
1882 | else | |
1883 | break; | |
d900b539 | 1884 | } |
fbdd7096 | 1885 | } |
6395ff6a | 1886 | } |
ee034ba4 | 1887 | msi_free(override); |
78a04e39 | 1888 | |
72faac0d | 1889 | return TRUE; |
78a04e39 AS |
1890 | } |
1891 | ||
7bcac31d | 1892 | UINT MSI_SetFeatureStates(MSIPACKAGE *package) |
78a04e39 | 1893 | { |
c855fbfc | 1894 | int level; |
8e233e9b AS |
1895 | static const WCHAR szlevel[] = |
1896 | {'I','N','S','T','A','L','L','L','E','V','E','L',0}; | |
1897 | static const WCHAR szAddLocal[] = | |
1898 | {'A','D','D','L','O','C','A','L',0}; | |
c31fd437 JH |
1899 | static const WCHAR szAddSource[] = |
1900 | {'A','D','D','S','O','U','R','C','E',0}; | |
8e233e9b AS |
1901 | static const WCHAR szRemove[] = |
1902 | {'R','E','M','O','V','E',0}; | |
d5655f90 AS |
1903 | static const WCHAR szReinstall[] = |
1904 | {'R','E','I','N','S','T','A','L','L',0}; | |
4da865f3 HL |
1905 | static const WCHAR szAdvertise[] = |
1906 | {'A','D','V','E','R','T','I','S','E',0}; | |
78a04e39 | 1907 | BOOL override = FALSE; |
38d67a45 | 1908 | MSICOMPONENT* component; |
1da2858c MM |
1909 | MSIFEATURE *feature; |
1910 | ||
78a04e39 AS |
1911 | |
1912 | /* I do not know if this is where it should happen.. but */ | |
1913 | ||
1914 | TRACE("Checking Install Level\n"); | |
1915 | ||
c855fbfc | 1916 | level = msi_get_property_int(package, szlevel, 1); |
78a04e39 | 1917 | |
58162f87 | 1918 | /* ok here is the _real_ rub |
fbb33435 FG |
1919 | * all these activation/deactivation things happen in order and things |
1920 | * later on the list override things earlier on the list. | |
4da865f3 HL |
1921 | * 0) INSTALLLEVEL processing |
1922 | * 1) ADDLOCAL | |
1923 | * 2) REMOVE | |
1924 | * 3) ADDSOURCE | |
1925 | * 4) ADDDEFAULT | |
1926 | * 5) REINSTALL | |
1927 | * 6) ADVERTISE | |
78a04e39 AS |
1928 | * 7) COMPADDLOCAL |
1929 | * 8) COMPADDSOURCE | |
1930 | * 9) FILEADDLOCAL | |
1931 | * 10) FILEADDSOURCE | |
1932 | * 11) FILEADDDEFAULT | |
78a04e39 | 1933 | * |
fbb33435 FG |
1934 | * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and |
1935 | * REMOVE are the big ones, since we don't handle administrative installs | |
1936 | * yet anyway. | |
78a04e39 | 1937 | */ |
c855fbfc JH |
1938 | override |= process_state_property(package, level, szAddLocal, INSTALLSTATE_LOCAL); |
1939 | override |= process_state_property(package, level, szRemove, INSTALLSTATE_ABSENT); | |
1940 | override |= process_state_property(package, level, szAddSource, INSTALLSTATE_SOURCE); | |
40cfbaf0 | 1941 | override |= process_state_property(package, level, szReinstall, INSTALLSTATE_UNKNOWN); |
4da865f3 | 1942 | override |= process_state_property(package, level, szAdvertise, INSTALLSTATE_ADVERTISED); |
78a04e39 AS |
1943 | |
1944 | if (!override) | |
fbdd7096 | 1945 | { |
1da2858c | 1946 | LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) |
fbdd7096 | 1947 | { |
1da2858c | 1948 | BOOL feature_state = ((feature->Level > 0) && |
c855fbfc | 1949 | (feature->Level <= level)); |
ae1aa32c | 1950 | |
1da2858c | 1951 | if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN)) |
fbdd7096 | 1952 | { |
1da2858c | 1953 | if (feature->Attributes & msidbFeatureAttributesFavorSource) |
d596ae29 | 1954 | msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE); |
1da2858c | 1955 | else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise) |
d596ae29 | 1956 | msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED); |
b39d8fc2 | 1957 | else |
d596ae29 | 1958 | msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL); |
fbdd7096 | 1959 | } |
ae1aa32c | 1960 | } |
545d0e70 JH |
1961 | |
1962 | /* disable child features of unselected parent features */ | |
1963 | LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) | |
1964 | { | |
1965 | FeatureList *fl; | |
1966 | ||
c855fbfc | 1967 | if (feature->Level > 0 && feature->Level <= level) |
545d0e70 JH |
1968 | continue; |
1969 | ||
1970 | LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry ) | |
d596ae29 | 1971 | msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN); |
545d0e70 | 1972 | } |
fbdd7096 | 1973 | } |
6999a042 AS |
1974 | else |
1975 | { | |
1976 | /* set the Preselected Property */ | |
1977 | static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0}; | |
1978 | static const WCHAR szOne[] = { '1', 0 }; | |
1979 | ||
1980 | MSI_SetPropertyW(package,szPreselected,szOne); | |
1981 | } | |
fbdd7096 AS |
1982 | |
1983 | /* | |
6395ff6a MM |
1984 | * now we want to enable or disable components base on feature |
1985 | */ | |
fbdd7096 | 1986 | |
1da2858c | 1987 | LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) |
fbdd7096 | 1988 | { |
3f2d5d7f MM |
1989 | ComponentList *cl; |
1990 | ||
62219754 JH |
1991 | TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n", |
1992 | debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action); | |
1993 | ||
1994 | if (!feature->Level) | |
1995 | continue; | |
97419aea MM |
1996 | |
1997 | /* features with components that have compressed files are made local */ | |
1998 | LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) | |
1999 | { | |
2000 | if (cl->component->Enabled && | |
2001 | cl->component->ForceLocalState && | |
2002 | feature->Action == INSTALLSTATE_SOURCE) | |
2003 | { | |
d596ae29 | 2004 | msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL); |
97419aea MM |
2005 | break; |
2006 | } | |
2007 | } | |
ae1aa32c | 2008 | |
1da2858c | 2009 | LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) |
ae1aa32c | 2010 | { |
38d67a45 | 2011 | component = cl->component; |
fbdd7096 | 2012 | |
87fa854d MM |
2013 | if (!component->Enabled) |
2014 | continue; | |
2015 | ||
97419aea | 2016 | switch (feature->Action) |
ad80eceb | 2017 | { |
fc6b9dd4 JH |
2018 | case INSTALLSTATE_ABSENT: |
2019 | component->anyAbsent = 1; | |
2020 | break; | |
97419aea MM |
2021 | case INSTALLSTATE_ADVERTISED: |
2022 | component->hasAdvertiseFeature = 1; | |
2023 | break; | |
2024 | case INSTALLSTATE_SOURCE: | |
2025 | component->hasSourceFeature = 1; | |
2026 | break; | |
2027 | case INSTALLSTATE_LOCAL: | |
2028 | component->hasLocalFeature = 1; | |
2029 | break; | |
2030 | case INSTALLSTATE_DEFAULT: | |
2031 | if (feature->Attributes & msidbFeatureAttributesFavorAdvertise) | |
2032 | component->hasAdvertiseFeature = 1; | |
2033 | else if (feature->Attributes & msidbFeatureAttributesFavorSource) | |
2034 | component->hasSourceFeature = 1; | |
ad80eceb | 2035 | else |
97419aea MM |
2036 | component->hasLocalFeature = 1; |
2037 | break; | |
2038 | default: | |
2039 | break; | |
929395c0 | 2040 | } |
97419aea MM |
2041 | } |
2042 | } | |
929395c0 | 2043 | |
97419aea MM |
2044 | LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry ) |
2045 | { | |
2046 | /* if the component isn't enabled, leave it alone */ | |
2047 | if (!component->Enabled) | |
2048 | continue; | |
2049 | ||
2050 | /* check if it's local or source */ | |
2051 | if (!(component->Attributes & msidbComponentAttributesOptional) && | |
2052 | (component->hasLocalFeature || component->hasSourceFeature)) | |
2053 | { | |
2054 | if ((component->Attributes & msidbComponentAttributesSourceOnly) && | |
2055 | !component->ForceLocalState) | |
3bec162d | 2056 | msi_component_set_state(package, component, INSTALLSTATE_SOURCE); |
97419aea | 2057 | else |
3bec162d | 2058 | msi_component_set_state(package, component, INSTALLSTATE_LOCAL); |
97419aea MM |
2059 | continue; |
2060 | } | |
929395c0 | 2061 | |
97419aea MM |
2062 | /* if any feature is local, the component must be local too */ |
2063 | if (component->hasLocalFeature) | |
2064 | { | |
3bec162d | 2065 | msi_component_set_state(package, component, INSTALLSTATE_LOCAL); |
97419aea MM |
2066 | continue; |
2067 | } | |
6395ff6a | 2068 | |
97419aea MM |
2069 | if (component->hasSourceFeature) |
2070 | { | |
3bec162d | 2071 | msi_component_set_state(package, component, INSTALLSTATE_SOURCE); |
97419aea | 2072 | continue; |
ae1aa32c | 2073 | } |
97419aea MM |
2074 | |
2075 | if (component->hasAdvertiseFeature) | |
2076 | { | |
3bec162d | 2077 | msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED); |
97419aea MM |
2078 | continue; |
2079 | } | |
2080 | ||
2081 | TRACE("nobody wants component %s\n", debugstr_w(component->Component)); | |
fc6b9dd4 | 2082 | if (component->anyAbsent) |
3bec162d | 2083 | msi_component_set_state(package, component, INSTALLSTATE_ABSENT); |
6395ff6a | 2084 | } |
fbdd7096 | 2085 | |
38d67a45 | 2086 | LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry ) |
fbdd7096 | 2087 | { |
9efb7b71 MM |
2088 | if (component->Action == INSTALLSTATE_DEFAULT) |
2089 | { | |
2090 | TRACE("%s was default, setting to local\n", debugstr_w(component->Component)); | |
3bec162d | 2091 | msi_component_set_state(package, component, INSTALLSTATE_LOCAL); |
9efb7b71 MM |
2092 | } |
2093 | ||
3fe6a5d0 MM |
2094 | TRACE("Result: Component %s (Installed %i, Action %i)\n", |
2095 | debugstr_w(component->Component), component->Installed, component->Action); | |
fbdd7096 AS |
2096 | } |
2097 | ||
2098 | ||
ae1aa32c AS |
2099 | return ERROR_SUCCESS; |
2100 | } | |
2101 | ||
443ad4d3 AS |
2102 | static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param) |
2103 | { | |
5f3ac30b | 2104 | MSIPACKAGE *package = param; |
443ad4d3 AS |
2105 | LPCWSTR name; |
2106 | LPWSTR path; | |
baad8887 | 2107 | MSIFOLDER *f; |
443ad4d3 AS |
2108 | |
2109 | name = MSI_RecordGetString(row,1); | |
2110 | ||
baad8887 JH |
2111 | f = get_loaded_folder(package, name); |
2112 | if (!f) return ERROR_SUCCESS; | |
2113 | ||
2114 | /* reset the ResolvedTarget */ | |
2115 | msi_free(f->ResolvedTarget); | |
2116 | f->ResolvedTarget = NULL; | |
2117 | ||
443ad4d3 AS |
2118 | /* This helper function now does ALL the work */ |
2119 | TRACE("Dir %s ...\n",debugstr_w(name)); | |
8cedb218 | 2120 | path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL); |
443ad4d3 | 2121 | TRACE("resolves to %s\n",debugstr_w(path)); |
ee034ba4 | 2122 | msi_free(path); |
443ad4d3 AS |
2123 | |
2124 | return ERROR_SUCCESS; | |
2125 | } | |
2126 | ||
2127 | static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param) | |
2128 | { | |
5f3ac30b | 2129 | MSIPACKAGE *package = param; |
1da2858c MM |
2130 | LPCWSTR name; |
2131 | MSIFEATURE *feature; | |
443ad4d3 | 2132 | |
1da2858c | 2133 | name = MSI_RecordGetString( row, 1 ); |
443ad4d3 | 2134 | |
1da2858c MM |
2135 | feature = get_loaded_feature( package, name ); |
2136 | if (!feature) | |
2137 | ERR("FAILED to find loaded feature %s\n",debugstr_w(name)); | |
443ad4d3 AS |
2138 | else |
2139 | { | |
2140 | LPCWSTR Condition; | |
2141 | Condition = MSI_RecordGetString(row,3); | |
2142 | ||
0713f098 | 2143 | if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE) |
443ad4d3 AS |
2144 | { |
2145 | int level = MSI_RecordGetInteger(row,2); | |
633ee950 | 2146 | TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level); |
1da2858c | 2147 | feature->Level = level; |
443ad4d3 AS |
2148 | } |
2149 | } | |
2150 | return ERROR_SUCCESS; | |
2151 | } | |
2152 | ||
020bda7e | 2153 | static LPWSTR msi_get_disk_file_version( LPCWSTR filename ) |
d1723de5 MM |
2154 | { |
2155 | static const WCHAR name_fmt[] = | |
2156 | {'%','u','.','%','u','.','%','u','.','%','u',0}; | |
76d6b767 | 2157 | static const WCHAR name[] = {'\\',0}; |
d1723de5 MM |
2158 | VS_FIXEDFILEINFO *lpVer; |
2159 | WCHAR filever[0x100]; | |
2160 | LPVOID version; | |
2161 | DWORD versize; | |
2162 | DWORD handle; | |
2163 | UINT sz; | |
2164 | ||
2165 | TRACE("%s\n", debugstr_w(filename)); | |
2166 | ||
2167 | versize = GetFileVersionInfoSizeW( filename, &handle ); | |
2168 | if (!versize) | |
2169 | return NULL; | |
2170 | ||
2171 | version = msi_alloc( versize ); | |
2172 | GetFileVersionInfoW( filename, 0, versize, version ); | |
2173 | ||
9c6fac65 RS |
2174 | if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz )) |
2175 | { | |
2176 | msi_free( version ); | |
2177 | return NULL; | |
2178 | } | |
d1723de5 MM |
2179 | |
2180 | sprintfW( filever, name_fmt, | |
2181 | HIWORD(lpVer->dwFileVersionMS), | |
2182 | LOWORD(lpVer->dwFileVersionMS), | |
2183 | HIWORD(lpVer->dwFileVersionLS), | |
2184 | LOWORD(lpVer->dwFileVersionLS)); | |
2185 | ||
023383af RS |
2186 | msi_free( version ); |
2187 | ||
d1723de5 MM |
2188 | return strdupW( filever ); |
2189 | } | |
2190 | ||
c5c55210 | 2191 | static UINT msi_check_file_install_states( MSIPACKAGE *package ) |
401bd3f7 | 2192 | { |
c5c55210 | 2193 | LPWSTR file_version; |
e18f8abe | 2194 | MSIFILE *file; |
ec688fb4 | 2195 | |
e18f8abe | 2196 | LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) |
ec688fb4 | 2197 | { |
f11c8b00 MM |
2198 | MSICOMPONENT* comp = file->Component; |
2199 | LPWSTR p; | |
ec688fb4 | 2200 | |
f11c8b00 MM |
2201 | if (!comp) |
2202 | continue; | |
ec688fb4 | 2203 | |
d893cb7d | 2204 | if (file->IsCompressed) |
d893cb7d | 2205 | comp->ForceLocalState = TRUE; |
d893cb7d | 2206 | |
f11c8b00 | 2207 | /* calculate target */ |
8cedb218 | 2208 | p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL); |
ba8200bf | 2209 | |
ee034ba4 | 2210 | msi_free(file->TargetPath); |
fa384f6b | 2211 | |
f11c8b00 | 2212 | TRACE("file %s is named %s\n", |
d1723de5 | 2213 | debugstr_w(file->File), debugstr_w(file->FileName)); |
fa384f6b | 2214 | |
f11c8b00 | 2215 | file->TargetPath = build_directory_name(2, p, file->FileName); |
fa384f6b | 2216 | |
ee034ba4 | 2217 | msi_free(p); |
ec688fb4 | 2218 | |
f11c8b00 | 2219 | TRACE("file %s resolves to %s\n", |
d1723de5 | 2220 | debugstr_w(file->File), debugstr_w(file->TargetPath)); |
fa384f6b | 2221 | |
ddf0b593 MM |
2222 | /* don't check files of components that aren't installed */ |
2223 | if (comp->Installed == INSTALLSTATE_UNKNOWN || | |
2224 | comp->Installed == INSTALLSTATE_ABSENT) | |
2225 | { | |
2226 | file->state = msifs_missing; /* assume files are missing */ | |
2227 | continue; | |
2228 | } | |
2229 | ||
f11c8b00 MM |
2230 | if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES) |
2231 | { | |
dded8fb7 | 2232 | file->state = msifs_missing; |
f11c8b00 MM |
2233 | comp->Cost += file->FileSize; |
2234 | continue; | |
2235 | } | |
fa384f6b | 2236 | |
d1723de5 MM |
2237 | if (file->Version && |
2238 | (file_version = msi_get_disk_file_version( file->TargetPath ))) | |
f11c8b00 | 2239 | { |
f11c8b00 | 2240 | TRACE("new %s old %s\n", debugstr_w(file->Version), |
d1723de5 MM |
2241 | debugstr_w(file_version)); |
2242 | /* FIXME: seems like a bad way to compare version numbers */ | |
2243 | if (lstrcmpiW(file_version, file->Version)<0) | |
ec688fb4 | 2244 | { |
dded8fb7 | 2245 | file->state = msifs_overwrite; |
ec688fb4 AS |
2246 | comp->Cost += file->FileSize; |
2247 | } | |
2248 | else | |
dded8fb7 | 2249 | file->state = msifs_present; |
d1723de5 | 2250 | msi_free( file_version ); |
f11c8b00 MM |
2251 | } |
2252 | else | |
dded8fb7 | 2253 | file->state = msifs_present; |
ec688fb4 AS |
2254 | } |
2255 | ||
c5c55210 MM |
2256 | return ERROR_SUCCESS; |
2257 | } | |
2258 | ||
2259 | /* | |
2260 | * A lot is done in this function aside from just the costing. | |
2261 | * The costing needs to be implemented at some point but for now I am going | |
2262 | * to focus on the directory building | |
2263 | * | |
2264 | */ | |
2265 | static UINT ACTION_CostFinalize(MSIPACKAGE *package) | |
2266 | { | |
2267 | static const WCHAR ExecSeqQuery[] = | |
2268 | {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', | |
2269 | '`','D','i','r','e','c','t','o','r','y','`',0}; | |
2270 | static const WCHAR ConditionQuery[] = | |
2271 | {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', | |
2272 | '`','C','o','n','d','i','t','i','o','n','`',0}; | |
2273 | static const WCHAR szCosting[] = | |
2274 | {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 }; | |
2275 | static const WCHAR szlevel[] = | |
2276 | {'I','N','S','T','A','L','L','L','E','V','E','L',0}; | |
ece5a047 JH |
2277 | static const WCHAR szOutOfDiskSpace[] = |
2278 | {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0}; | |
c5c55210 | 2279 | static const WCHAR szOne[] = { '1', 0 }; |
ece5a047 | 2280 | static const WCHAR szZero[] = { '0', 0 }; |
c5c55210 MM |
2281 | MSICOMPONENT *comp; |
2282 | UINT rc; | |
2283 | MSIQUERY * view; | |
2284 | LPWSTR level; | |
2285 | ||
c5c55210 MM |
2286 | TRACE("Building Directory properties\n"); |
2287 | ||
2288 | rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); | |
2289 | if (rc == ERROR_SUCCESS) | |
2290 | { | |
2291 | rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories, | |
2292 | package); | |
2293 | msiobj_release(&view->hdr); | |
2294 | } | |
2295 | ||
2296 | /* read components states from the registry */ | |
2297 | ACTION_GetComponentInstallStates(package); | |
5a3c3b6a | 2298 | ACTION_GetFeatureInstallStates(package); |
c5c55210 MM |
2299 | |
2300 | TRACE("File calculations\n"); | |
2301 | msi_check_file_install_states( package ); | |
2302 | ||
7d3e5973 AS |
2303 | TRACE("Evaluating Condition Table\n"); |
2304 | ||
a7a6f5f3 | 2305 | rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view); |
84837d96 AS |
2306 | if (rc == ERROR_SUCCESS) |
2307 | { | |
443ad4d3 AS |
2308 | rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions, |
2309 | package); | |
ac6a413b | 2310 | msiobj_release(&view->hdr); |
84837d96 | 2311 | } |
7d3e5973 AS |
2312 | |
2313 | TRACE("Enabling or Disabling Components\n"); | |
38d67a45 | 2314 | LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) |
7d3e5973 | 2315 | { |
9375fd9f | 2316 | if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE) |
7d3e5973 | 2317 | { |
9375fd9f MM |
2318 | TRACE("Disabling component %s\n", debugstr_w(comp->Component)); |
2319 | comp->Enabled = FALSE; | |
7d3e5973 | 2320 | } |
bf515184 JH |
2321 | else |
2322 | comp->Enabled = TRUE; | |
7d3e5973 AS |
2323 | } |
2324 | ||
a7a6f5f3 | 2325 | MSI_SetPropertyW(package,szCosting,szOne); |
8cc14a93 | 2326 | /* set default run level if not set */ |
062ad505 | 2327 | level = msi_dup_property( package, szlevel ); |
8cc14a93 AS |
2328 | if (!level) |
2329 | MSI_SetPropertyW(package,szlevel, szOne); | |
ee034ba4 | 2330 | msi_free(level); |
ae1aa32c | 2331 | |
ece5a047 JH |
2332 | /* FIXME: check volume disk space */ |
2333 | MSI_SetPropertyW(package, szOutOfDiskSpace, szZero); | |
2334 | ||
7c7f0bb2 | 2335 | return MSI_SetFeatureStates(package); |
401bd3f7 AS |
2336 | } |
2337 | ||
da8b3dd7 | 2338 | /* OK this value is "interpreted" and then formatted based on the |
6e160f14 | 2339 | first few characters */ |
09b0abaa | 2340 | static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type, |
401bd3f7 AS |
2341 | DWORD *size) |
2342 | { | |
2343 | LPSTR data = NULL; | |
2f658cb3 | 2344 | |
6e160f14 | 2345 | if (value[0]=='#' && value[1]!='#' && value[1]!='%') |
401bd3f7 | 2346 | { |
6e160f14 AS |
2347 | if (value[1]=='x') |
2348 | { | |
2349 | LPWSTR ptr; | |
2350 | CHAR byte[5]; | |
6186b2be | 2351 | LPWSTR deformated = NULL; |
6e160f14 AS |
2352 | int count; |
2353 | ||
a7a6f5f3 | 2354 | deformat_string(package, &value[2], &deformated); |
6e160f14 AS |
2355 | |
2356 | /* binary value type */ | |
6186b2be AS |
2357 | ptr = deformated; |
2358 | *type = REG_BINARY; | |
2359 | if (strlenW(ptr)%2) | |
2360 | *size = (strlenW(ptr)/2)+1; | |
2361 | else | |
2362 | *size = strlenW(ptr)/2; | |
2363 | ||
ee034ba4 | 2364 | data = msi_alloc(*size); |
6186b2be | 2365 | |
6e160f14 AS |
2366 | byte[0] = '0'; |
2367 | byte[1] = 'x'; | |
2368 | byte[4] = 0; | |
2369 | count = 0; | |
6186b2be AS |
2370 | /* if uneven pad with a zero in front */ |
2371 | if (strlenW(ptr)%2) | |
2372 | { | |
2373 | byte[2]= '0'; | |
2374 | byte[3]= *ptr; | |
2375 | ptr++; | |
2376 | data[count] = (BYTE)strtol(byte,NULL,0); | |
2377 | count ++; | |
2378 | TRACE("Uneven byte count\n"); | |
2379 | } | |
6e160f14 AS |
2380 | while (*ptr) |
2381 | { | |
2382 | byte[2]= *ptr; | |
2383 | ptr++; | |
2384 | byte[3]= *ptr; | |
2385 | ptr++; | |
2386 | data[count] = (BYTE)strtol(byte,NULL,0); | |
2387 | count ++; | |
2388 | } | |
ee034ba4 | 2389 | msi_free(deformated); |
6e160f14 | 2390 | |
f1d4646a | 2391 | TRACE("Data %i bytes(%i)\n",*size,count); |
6e160f14 AS |
2392 | } |
2393 | else | |
2394 | { | |
2395 | LPWSTR deformated; | |
b6bc6aa6 AS |
2396 | LPWSTR p; |
2397 | DWORD d = 0; | |
a7a6f5f3 | 2398 | deformat_string(package, &value[1], &deformated); |
6e160f14 AS |
2399 | |
2400 | *type=REG_DWORD; | |
2401 | *size = sizeof(DWORD); | |
ee034ba4 | 2402 | data = msi_alloc(*size); |
b6bc6aa6 AS |
2403 | p = deformated; |
2404 | if (*p == '-') | |
2405 | p++; | |
2406 | while (*p) | |
2407 | { | |
2408 | if ( (*p < '0') || (*p > '9') ) | |
2409 | break; | |
2410 | d *= 10; | |
2411 | d += (*p - '0'); | |
2412 | p++; | |
2413 | } | |
2414 | if (deformated[0] == '-') | |
2415 | d = -d; | |
2416 | *(LPDWORD)data = d; | |
f1d4646a | 2417 | TRACE("DWORD %i\n",*(LPDWORD)data); |
6e160f14 | 2418 | |
ee034ba4 | 2419 | msi_free(deformated); |
6e160f14 | 2420 | } |
401bd3f7 AS |
2421 | } |
2422 | else | |
2423 | { | |
54c67dd1 | 2424 | static const WCHAR szMulti[] = {'[','~',']',0}; |
09b0abaa | 2425 | LPCWSTR ptr; |
6e160f14 AS |
2426 | *type=REG_SZ; |
2427 | ||
401bd3f7 | 2428 | if (value[0]=='#') |
6e160f14 AS |
2429 | { |
2430 | if (value[1]=='%') | |
2431 | { | |
2432 | ptr = &value[2]; | |
2433 | *type=REG_EXPAND_SZ; | |
2434 | } | |
2435 | else | |
2436 | ptr = &value[1]; | |
2437 | } | |
2438 | else | |
401bd3f7 AS |
2439 | ptr=value; |
2440 | ||
54c67dd1 AS |
2441 | if (strstrW(value,szMulti)) |
2442 | *type = REG_MULTI_SZ; | |
2443 | ||
2f658cb3 JH |
2444 | /* remove initial delimiter */ |
2445 | if (!strncmpW(value, szMulti, 3)) | |
2446 | ptr = value + 3; | |
2447 | ||
a7a6f5f3 | 2448 | *size = deformat_string(package, ptr,(LPWSTR*)&data); |
2f658cb3 JH |
2449 | |
2450 | /* add double NULL terminator */ | |
2451 | if (*type == REG_MULTI_SZ) | |
2452 | { | |
21b4af1b JH |
2453 | *size += 2 * sizeof(WCHAR); /* two NULL terminators */ |
2454 | data = msi_realloc_zero(data, *size); | |
2f658cb3 | 2455 | } |
401bd3f7 AS |
2456 | } |
2457 | return data; | |
2458 | } | |
2459 | ||
92ef78ee | 2460 | static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param) |
401bd3f7 | 2461 | { |
5f3ac30b | 2462 | MSIPACKAGE *package = param; |
92ef78ee AS |
2463 | static const WCHAR szHCR[] = |
2464 | {'H','K','E','Y','_','C','L','A','S','S','E','S','_', | |
2465 | 'R','O','O','T','\\',0}; | |
2466 | static const WCHAR szHCU[] = | |
2467 | {'H','K','E','Y','_','C','U','R','R','E','N','T','_', | |
2468 | 'U','S','E','R','\\',0}; | |
2469 | static const WCHAR szHLM[] = | |
2470 | {'H','K','E','Y','_','L','O','C','A','L','_', | |
2471 | 'M','A','C','H','I','N','E','\\',0}; | |
2472 | static const WCHAR szHU[] = | |
2473 | {'H','K','E','Y','_','U','S','E','R','S','\\',0}; | |
2474 | ||
2475 | LPSTR value_data = NULL; | |
2476 | HKEY root_key, hkey; | |
2477 | DWORD type,size; | |
2478 | LPWSTR deformated; | |
2479 | LPCWSTR szRoot, component, name, key, value; | |
38d67a45 | 2480 | MSICOMPONENT *comp; |
92ef78ee AS |
2481 | MSIRECORD * uirow; |
2482 | LPWSTR uikey; | |
2483 | INT root; | |
2484 | BOOL check_first = FALSE; | |
401bd3f7 | 2485 | UINT rc; |
401bd3f7 | 2486 | |
92ef78ee | 2487 | ui_progress(package,2,0,0,0); |
7d3e5973 | 2488 | |
92ef78ee AS |
2489 | value = NULL; |
2490 | key = NULL; | |
2491 | uikey = NULL; | |
2492 | name = NULL; | |
401bd3f7 | 2493 | |
92ef78ee | 2494 | component = MSI_RecordGetString(row, 6); |
38d67a45 | 2495 | comp = get_loaded_component(package,component); |
0946c42d JD |
2496 | if (!comp) |
2497 | return ERROR_SUCCESS; | |
d2c395ad | 2498 | |
d693f461 | 2499 | if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL)) |
401bd3f7 | 2500 | { |
92ef78ee AS |
2501 | TRACE("Skipping write due to disabled component %s\n", |
2502 | debugstr_w(component)); | |
90c57396 | 2503 | |
38d67a45 | 2504 | comp->Action = comp->Installed; |
90c57396 | 2505 | |
92ef78ee AS |
2506 | return ERROR_SUCCESS; |
2507 | } | |
7d3e5973 | 2508 | |
38d67a45 | 2509 | comp->Action = INSTALLSTATE_LOCAL; |
90c57396 | 2510 | |
92ef78ee AS |
2511 | name = MSI_RecordGetString(row, 4); |
2512 | if( MSI_RecordIsNull(row,5) && name ) | |
2513 | { | |
2514 | /* null values can have special meanings */ | |
2515 | if (name[0]=='-' && name[1] == 0) | |
2516 | return ERROR_SUCCESS; | |
2517 | else if ((name[0]=='+' && name[1] == 0) || | |
2518 | (name[0] == '*' && name[1] == 0)) | |
b6bc6aa6 | 2519 | name = NULL; |
92ef78ee AS |
2520 | check_first = TRUE; |
2521 | } | |
401bd3f7 | 2522 | |
92ef78ee AS |
2523 | root = MSI_RecordGetInteger(row,2); |
2524 | key = MSI_RecordGetString(row, 3); | |
2525 | ||
2526 | /* get the root key */ | |
2527 | switch (root) | |
2528 | { | |
0713f098 AS |
2529 | case -1: |
2530 | { | |
2531 | static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0}; | |
062ad505 | 2532 | LPWSTR all_users = msi_dup_property( package, szALLUSER ); |
0713f098 AS |
2533 | if (all_users && all_users[0] == '1') |
2534 | { | |
2535 | root_key = HKEY_LOCAL_MACHINE; | |
2536 | szRoot = szHLM; | |
2537 | } | |
2538 | else | |
2539 | { | |
2540 | root_key = HKEY_CURRENT_USER; | |
2541 | szRoot = szHCU; | |
2542 | } | |
ee034ba4 | 2543 | msi_free(all_users); |
0713f098 AS |
2544 | } |
2545 | break; | |
92ef78ee AS |
2546 | case 0: root_key = HKEY_CLASSES_ROOT; |
2547 | szRoot = szHCR; | |
2548 | break; | |
2549 | case 1: root_key = HKEY_CURRENT_USER; | |
2550 | szRoot = szHCU; | |
2551 | break; | |
2552 | case 2: root_key = HKEY_LOCAL_MACHINE; | |
2553 | szRoot = szHLM; | |
2554 | break; | |
2555 | case 3: root_key = HKEY_USERS; | |
2556 | szRoot = szHU; | |
2557 | break; | |
2558 | default: | |
401bd3f7 AS |
2559 | ERR("Unknown root %i\n",root); |
2560 | root_key=NULL; | |
9db0e072 | 2561 | szRoot = NULL; |
401bd3f7 | 2562 | break; |
92ef78ee AS |
2563 | } |
2564 | if (!root_key) | |
2565 | return ERROR_SUCCESS; | |
401bd3f7 | 2566 | |
92ef78ee AS |
2567 | deformat_string(package, key , &deformated); |
2568 | size = strlenW(deformated) + strlenW(szRoot) + 1; | |
ee034ba4 | 2569 | uikey = msi_alloc(size*sizeof(WCHAR)); |
92ef78ee AS |
2570 | strcpyW(uikey,szRoot); |
2571 | strcatW(uikey,deformated); | |
1416b101 | 2572 | |
92ef78ee AS |
2573 | if (RegCreateKeyW( root_key, deformated, &hkey)) |
2574 | { | |
2575 | ERR("Could not create key %s\n",debugstr_w(deformated)); | |
ee034ba4 MM |
2576 | msi_free(deformated); |
2577 | msi_free(uikey); | |
92ef78ee AS |
2578 | return ERROR_SUCCESS; |
2579 | } | |
ee034ba4 | 2580 | msi_free(deformated); |
6e160f14 | 2581 | |
92ef78ee AS |
2582 | value = MSI_RecordGetString(row,5); |
2583 | if (value) | |
2584 | value_data = parse_value(package, value, &type, &size); | |
2585 | else | |
2586 | { | |
2587 | static const WCHAR szEmpty[] = {0}; | |
2588 | value_data = (LPSTR)strdupW(szEmpty); | |
06bf8ea2 | 2589 | size = sizeof(szEmpty); |
92ef78ee AS |
2590 | type = REG_SZ; |
2591 | } | |
401bd3f7 | 2592 | |
92ef78ee | 2593 | deformat_string(package, name, &deformated); |
1416b101 | 2594 | |
92ef78ee AS |
2595 | if (!check_first) |
2596 | { | |
2597 | TRACE("Setting value %s of %s\n",debugstr_w(deformated), | |
2598 | debugstr_w(uikey)); | |
16466af7 | 2599 | RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size); |
92ef78ee AS |
2600 | } |
2601 | else | |
2602 | { | |
2603 | DWORD sz = 0; | |
2604 | rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz); | |
2605 | if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA) | |
98e38082 | 2606 | { |
92ef78ee AS |
2607 | TRACE("value %s of %s checked already exists\n", |
2608 | debugstr_w(deformated), debugstr_w(uikey)); | |
98e38082 AS |
2609 | } |
2610 | else | |
2611 | { | |
92ef78ee AS |
2612 | TRACE("Checked and setting value %s of %s\n", |
2613 | debugstr_w(deformated), debugstr_w(uikey)); | |
2614 | if (deformated || size) | |
16466af7 | 2615 | RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size); |
98e38082 | 2616 | } |
92ef78ee AS |
2617 | } |
2618 | RegCloseKey(hkey); | |
d2c395ad | 2619 | |
92ef78ee AS |
2620 | uirow = MSI_CreateRecord(3); |
2621 | MSI_RecordSetStringW(uirow,2,deformated); | |
2622 | MSI_RecordSetStringW(uirow,1,uikey); | |
d2c395ad | 2623 | |
92ef78ee AS |
2624 | if (type == REG_SZ) |
2625 | MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data); | |
2626 | else | |
2627 | MSI_RecordSetStringW(uirow,3,value); | |
d2c395ad | 2628 | |
92ef78ee AS |
2629 | ui_actiondata(package,szWriteRegistryValues,uirow); |
2630 | msiobj_release( &uirow->hdr ); | |
d2c395ad | 2631 | |
ee034ba4 MM |
2632 | msi_free(value_data); |
2633 | msi_free(deformated); | |
2634 | msi_free(uikey); | |
92ef78ee AS |
2635 | |
2636 | return ERROR_SUCCESS; | |
2637 | } | |
2638 | ||
2639 | static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package) | |
2640 | { | |
2641 | UINT rc; | |
2642 | MSIQUERY * view; | |
2643 | static const WCHAR ExecSeqQuery[] = | |
2644 | {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', | |
2645 | '`','R','e','g','i','s','t','r','y','`',0 }; | |
2646 | ||
92ef78ee AS |
2647 | rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); |
2648 | if (rc != ERROR_SUCCESS) | |
2649 | return ERROR_SUCCESS; | |
2650 | ||
2651 | /* increment progress bar each time action data is sent */ | |
2652 | ui_progress(package,1,REG_PROGRESS_VALUE,1,0); | |
2653 | ||
2654 | rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package); | |
401bd3f7 | 2655 | |
a7a6f5f3 | 2656 | msiobj_release(&view->hdr); |
401bd3f7 AS |
2657 | return rc; |
2658 | } | |
2659 | ||
a7a6f5f3 | 2660 | static UINT ACTION_InstallInitialize(MSIPACKAGE *package) |
7d3e5973 | 2661 | { |
9cd707da AS |
2662 | package->script->CurrentlyScripting = TRUE; |
2663 | ||
7d3e5973 AS |
2664 | return ERROR_SUCCESS; |
2665 | } | |
2666 | ||
ae1aa32c | 2667 | |
a7a6f5f3 | 2668 | static UINT ACTION_InstallValidate(MSIPACKAGE *package) |
7d3e5973 | 2669 | { |
38d67a45 | 2670 | MSICOMPONENT *comp; |
7d3e5973 | 2671 | DWORD progress = 0; |
bd1bbc17 | 2672 | DWORD total = 0; |
8e233e9b AS |
2673 | static const WCHAR q1[]= |
2674 | {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', | |
98e38082 | 2675 | '`','R','e','g','i','s','t','r','y','`',0}; |
7d3e5973 | 2676 | UINT rc; |
a7a6f5f3 | 2677 | MSIQUERY * view; |
1da2858c | 2678 | MSIFEATURE *feature; |
e18f8abe | 2679 | MSIFILE *file; |
7d3e5973 | 2680 | |
f3f12ab5 | 2681 | TRACE("InstallValidate\n"); |
7d3e5973 | 2682 | |
a7a6f5f3 | 2683 | rc = MSI_DatabaseOpenViewW(package->db, q1, &view); |
f3f12ab5 | 2684 | if (rc == ERROR_SUCCESS) |
a7a6f5f3 | 2685 | { |
f3f12ab5 MM |
2686 | MSI_IterateRecords( view, &progress, NULL, package ); |
2687 | msiobj_release( &view->hdr ); | |
2688 | total += progress * REG_PROGRESS_VALUE; | |
a7a6f5f3 | 2689 | } |
7d3e5973 | 2690 | |
38d67a45 | 2691 | LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) |
38d67a45 | 2692 | total += COMPONENT_PROGRESS_VALUE; |
f3f12ab5 | 2693 | |
e18f8abe | 2694 | LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) |
e18f8abe | 2695 | total += file->FileSize; |
f3f12ab5 | 2696 | |
bd1bbc17 | 2697 | ui_progress(package,0,total,0,0); |
7d3e5973 | 2698 | |
1da2858c | 2699 | LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) |
b39d8fc2 | 2700 | { |
b39d8fc2 AS |
2701 | TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n", |
2702 | debugstr_w(feature->Feature), feature->Installed, feature->Action, | |
2703 | feature->ActionRequest); | |
2704 | } | |
2705 | ||
7d3e5973 AS |
2706 | return ERROR_SUCCESS; |
2707 | } | |
2708 | ||
c79f4e21 AS |
2709 | static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param) |
2710 | { | |
5f3ac30b | 2711 | MSIPACKAGE* package = param; |
c79f4e21 AS |
2712 | LPCWSTR cond = NULL; |
2713 | LPCWSTR message = NULL; | |
bafc4dc3 JH |
2714 | UINT r; |
2715 | ||
c79f4e21 AS |
2716 | static const WCHAR title[]= |
2717 | {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0}; | |
2718 | ||
2719 | cond = MSI_RecordGetString(row,1); | |
2720 | ||
bafc4dc3 JH |
2721 | r = MSI_EvaluateConditionW(package,cond); |
2722 | if (r == MSICONDITION_FALSE) | |
c79f4e21 | 2723 | { |
bafc4dc3 JH |
2724 | if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE) |
2725 | { | |
2726 | LPWSTR deformated; | |
2727 | message = MSI_RecordGetString(row,2); | |
2728 | deformat_string(package,message,&deformated); | |
2729 | MessageBoxW(NULL,deformated,title,MB_OK); | |
2730 | msi_free(deformated); | |
2731 | } | |
2732 | ||
2733 | return ERROR_INSTALL_FAILURE; | |
c79f4e21 AS |
2734 | } |
2735 | ||
2736 | return ERROR_SUCCESS; | |
2737 | } | |
2738 | ||
a7a6f5f3 | 2739 | static UINT ACTION_LaunchConditions(MSIPACKAGE *package) |
5b936ca2 AS |
2740 | { |
2741 | UINT rc; | |
f3c8b830 | 2742 | MSIQUERY * view = NULL; |
8e233e9b AS |
2743 | static const WCHAR ExecSeqQuery[] = |
2744 | {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', | |
98e38082 | 2745 | '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0}; |
5b936ca2 AS |
2746 | |
2747 | TRACE("Checking launch conditions\n"); | |
2748 | ||
a7a6f5f3 | 2749 | rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); |
5b936ca2 | 2750 | if (rc != ERROR_SUCCESS) |
84837d96 | 2751 | return ERROR_SUCCESS; |
5b936ca2 | 2752 | |
c79f4e21 | 2753 | rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package); |
a7a6f5f3 | 2754 | msiobj_release(&view->hdr); |
c79f4e21 | 2755 | |
5b936ca2 AS |
2756 | return rc; |
2757 | } | |
7d3e5973 | 2758 | |
38d67a45 | 2759 | static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp ) |
b942e186 | 2760 | { |
b942e186 | 2761 | |
efcc1ec5 | 2762 | if (!cmp->KeyPath) |
8cedb218 | 2763 | return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL); |
efcc1ec5 | 2764 | |
b6bc6aa6 | 2765 | if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath) |
b942e186 | 2766 | { |
6269f00c | 2767 | MSIRECORD * row = 0; |
0b352c7f | 2768 | UINT root,len; |
09b0abaa AS |
2769 | LPWSTR deformated,buffer,deformated_name; |
2770 | LPCWSTR key,name; | |
8e233e9b AS |
2771 | static const WCHAR ExecSeqQuery[] = |
2772 | {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', | |
98e38082 AS |
2773 | '`','R','e','g','i','s','t','r','y','`',' ', |
2774 | 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`', | |
2775 | ' ','=',' ' ,'\'','%','s','\'',0 }; | |
b6bc6aa6 | 2776 | static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0}; |
8e233e9b AS |
2777 | static const WCHAR fmt2[]= |
2778 | {'%','0','2','i',':','\\','%','s','\\','%','s',0}; | |
6269f00c | 2779 | |
0b352c7f MM |
2780 | row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath); |
2781 | if (!row) | |
6269f00c | 2782 | return NULL; |
6269f00c AS |
2783 | |
2784 | root = MSI_RecordGetInteger(row,2); | |
09b0abaa AS |
2785 | key = MSI_RecordGetString(row, 3); |
2786 | name = MSI_RecordGetString(row, 4); | |
6269f00c AS |
2787 | deformat_string(package, key , &deformated); |
2788 | deformat_string(package, name, &deformated_name); | |
2789 | ||
e15e5179 | 2790 | len = strlenW(deformated) + 6; |
6269f00c AS |
2791 | if (deformated_name) |
2792 | len+=strlenW(deformated_name); | |
2793 | ||
ee034ba4 | 2794 | buffer = msi_alloc( len *sizeof(WCHAR)); |
6269f00c AS |
2795 | |
2796 | if (deformated_name) | |
2797 | sprintfW(buffer,fmt2,root,deformated,deformated_name); | |
2798 | else | |
2799 | sprintfW(buffer,fmt,root,deformated); | |
2800 | ||
ee034ba4 MM |
2801 | msi_free(deformated); |
2802 | msi_free(deformated_name); | |
6269f00c | 2803 | msiobj_release(&row->hdr); |
6269f00c AS |
2804 | |
2805 | return buffer; | |
2806 | } | |
b6bc6aa6 | 2807 | else if (cmp->Attributes & msidbComponentAttributesODBCDataSource) |
6269f00c AS |
2808 | { |
2809 | FIXME("UNIMPLEMENTED keypath as ODBC Source\n"); | |
fa384f6b | 2810 | return NULL; |
b942e186 AS |
2811 | } |
2812 | else | |
2813 | { | |
e18f8abe | 2814 | MSIFILE *file = get_loaded_file( package, cmp->KeyPath ); |
fcb20c53 | 2815 | |
e18f8abe MM |
2816 | if (file) |
2817 | return strdupW( file->TargetPath ); | |
b942e186 | 2818 | } |
fa384f6b | 2819 | return NULL; |
b942e186 AS |
2820 | } |
2821 | ||
ac6f562b | 2822 | static HKEY openSharedDLLsKey(void) |
b6bc6aa6 AS |
2823 | { |
2824 | HKEY hkey=0; | |
8e233e9b AS |
2825 | static const WCHAR path[] = |
2826 | {'S','o','f','t','w','a','r','e','\\', | |
2827 | 'M','i','c','r','o','s','o','f','t','\\', | |
2828 | 'W','i','n','d','o','w','s','\\', | |
2829 | 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', | |
2830 | 'S','h','a','r','e','d','D','L','L','s',0}; | |
b6bc6aa6 AS |
2831 | |
2832 | RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey); | |
2833 | return hkey; | |
2834 | } | |
2835 | ||
2836 | static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll) | |
2837 | { | |
2838 | HKEY hkey; | |
2839 | DWORD count=0; | |
2840 | DWORD type; | |
2841 | DWORD sz = sizeof(count); | |
2842 | DWORD rc; | |
2843 | ||
2844 | hkey = openSharedDLLsKey(); | |
2845 | rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz); | |
2846 | if (rc != ERROR_SUCCESS) | |
2847 | count = 0; | |
2848 | RegCloseKey(hkey); | |
2849 | return count; | |
2850 | } | |
2851 | ||
2852 | static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count) | |
2853 | { | |
2854 | HKEY hkey; | |
2855 | ||
2856 | hkey = openSharedDLLsKey(); | |
2857 | if (count > 0) | |
4db02cdb | 2858 | msi_reg_set_val_dword( hkey, path, count ); |
b6bc6aa6 AS |
2859 | else |
2860 | RegDeleteValueW(hkey,path); | |
2861 | RegCloseKey(hkey); | |
2862 | return count; | |
2863 | } | |
2864 | ||
2865 | /* | |
2866 | * Return TRUE if the count should be written out and FALSE if not | |
2867 | */ | |
38d67a45 | 2868 | static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp ) |
b6bc6aa6 | 2869 | { |
1da2858c | 2870 | MSIFEATURE *feature; |
b6bc6aa6 AS |
2871 | INT count = 0; |
2872 | BOOL write = FALSE; | |
b6bc6aa6 AS |
2873 | |
2874 | /* only refcount DLLs */ | |
efcc1ec5 | 2875 | if (comp->KeyPath == NULL || |
38d67a45 MM |
2876 | comp->Attributes & msidbComponentAttributesRegistryKeyPath || |
2877 | comp->Attributes & msidbComponentAttributesODBCDataSource) | |
b6bc6aa6 AS |
2878 | write = FALSE; |
2879 | else | |
2880 | { | |
38d67a45 | 2881 | count = ACTION_GetSharedDLLsCount( comp->FullKeypath); |
b6bc6aa6 AS |
2882 | write = (count > 0); |
2883 | ||
38d67a45 | 2884 | if (comp->Attributes & msidbComponentAttributesSharedDllRefCount) |
b6bc6aa6 AS |
2885 | write = TRUE; |
2886 | } | |
2887 | ||
2888 | /* increment counts */ | |
1da2858c | 2889 | LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) |
b6bc6aa6 | 2890 | { |
3f2d5d7f | 2891 | ComponentList *cl; |
b6bc6aa6 | 2892 | |
1da2858c | 2893 | if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL )) |
b6bc6aa6 AS |
2894 | continue; |
2895 | ||
1da2858c | 2896 | LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) |
b6bc6aa6 | 2897 | { |
38d67a45 | 2898 | if ( cl->component == comp ) |
b6bc6aa6 AS |
2899 | count++; |
2900 | } | |
2901 | } | |
e18f8abe | 2902 | |
b6bc6aa6 | 2903 | /* decrement counts */ |
1da2858c | 2904 | LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) |
b6bc6aa6 | 2905 | { |
3f2d5d7f MM |
2906 | ComponentList *cl; |
2907 | ||
1da2858c | 2908 | if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT )) |
b6bc6aa6 AS |
2909 | continue; |
2910 | ||
1da2858c | 2911 | LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) |
b6bc6aa6 | 2912 | { |
38d67a45 | 2913 | if ( cl->component == comp ) |
b6bc6aa6 AS |
2914 | count--; |
2915 | } | |
2916 | } | |
2917 | ||
2918 | /* ref count all the files in the component */ | |
2919 | if (write) | |
e18f8abe MM |
2920 | { |
2921 | MSIFILE *file; | |
2922 | ||
2923 | LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) | |
b6bc6aa6 | 2924 | { |
e18f8abe MM |
2925 | if (file->Component == comp) |
2926 | ACTION_WriteSharedDLLsCount( file->TargetPath, count ); | |
b6bc6aa6 | 2927 | } |
e18f8abe | 2928 | } |
b6bc6aa6 | 2929 | |
5644f05e | 2930 | /* add a count for permanent */ |
38d67a45 | 2931 | if (comp->Attributes & msidbComponentAttributesPermanent) |
b6bc6aa6 AS |
2932 | count ++; |
2933 | ||
38d67a45 | 2934 | comp->RefCount = count; |
b6bc6aa6 AS |
2935 | |
2936 | if (write) | |
38d67a45 | 2937 | ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount ); |
b6bc6aa6 AS |
2938 | } |
2939 | ||
a7a6f5f3 | 2940 | static UINT ACTION_ProcessComponents(MSIPACKAGE *package) |
b942e186 | 2941 | { |
68b07494 AS |
2942 | WCHAR squished_pc[GUID_SIZE]; |
2943 | WCHAR squished_cc[GUID_SIZE]; | |
b942e186 | 2944 | UINT rc; |
38d67a45 | 2945 | MSICOMPONENT *comp; |
4aa3a997 | 2946 | HKEY hkey; |
b942e186 | 2947 | |
fc6b9dd4 JH |
2948 | TRACE("\n"); |
2949 | ||
adaef111 | 2950 | squash_guid(package->ProductCode,squished_pc); |
bd1bbc17 | 2951 | ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0); |
38d67a45 MM |
2952 | |
2953 | LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) | |
b942e186 | 2954 | { |
fe8cd388 MM |
2955 | MSIRECORD * uirow; |
2956 | ||
bd1bbc17 | 2957 | ui_progress(package,2,0,0,0); |
fe8cd388 MM |
2958 | if (!comp->ComponentId) |
2959 | continue; | |
b942e186 | 2960 | |
fe8cd388 | 2961 | squash_guid(comp->ComponentId,squished_cc); |
a3a2eaea | 2962 | |
fe8cd388 MM |
2963 | msi_free(comp->FullKeypath); |
2964 | comp->FullKeypath = resolve_keypath( package, comp ); | |
b6bc6aa6 | 2965 | |
fe8cd388 | 2966 | ACTION_RefCountComponent( package, comp ); |
b6bc6aa6 | 2967 | |
fe8cd388 | 2968 | TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n", |
38d67a45 | 2969 | debugstr_w(comp->Component), |
c5a1443f | 2970 | debugstr_w(squished_cc), |
fe8cd388 | 2971 | debugstr_w(comp->FullKeypath), |
38d67a45 | 2972 | comp->RefCount); |
96dd6ce1 JH |
2973 | |
2974 | if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL) || | |
2975 | ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE)) | |
fe8cd388 | 2976 | { |
fe8cd388 MM |
2977 | if (!comp->FullKeypath) |
2978 | continue; | |
b6bc6aa6 | 2979 | |
288af81a | 2980 | if (package->Context == MSIINSTALLCONTEXT_MACHINE) |
b198f4f2 JH |
2981 | rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, |
2982 | &hkey, TRUE); | |
288af81a | 2983 | else |
b198f4f2 JH |
2984 | rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, |
2985 | &hkey, TRUE); | |
288af81a | 2986 | |
4aa3a997 JH |
2987 | if (rc != ERROR_SUCCESS) |
2988 | continue; | |
b6bc6aa6 | 2989 | |
fe8cd388 | 2990 | if (comp->Attributes & msidbComponentAttributesPermanent) |
fa384f6b | 2991 | { |
fe8cd388 MM |
2992 | static const WCHAR szPermKey[] = |
2993 | { '0','0','0','0','0','0','0','0','0','0','0','0', | |
2994 | '0','0','0','0','0','0','0','0','0','0','0','0', | |
2995 | '0','0','0','0','0','0','0','0',0 }; | |
b39d8fc2 | 2996 | |
4aa3a997 | 2997 | msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath); |
fe8cd388 | 2998 | } |
b39d8fc2 | 2999 | |
96dd6ce1 JH |
3000 | if (comp->Action == INSTALLSTATE_LOCAL) |
3001 | msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath); | |
3002 | else | |
3003 | { | |
3004 | MSIFILE *file; | |
3005 | MSIRECORD *row; | |
3006 | LPWSTR ptr, ptr2; | |
3007 | WCHAR source[MAX_PATH]; | |
3008 | WCHAR base[MAX_PATH]; | |
d15fddf6 | 3009 | LPWSTR sourcepath; |
96dd6ce1 JH |
3010 | |
3011 | static const WCHAR fmt[] = {'%','0','2','d','\\',0}; | |
3012 | static const WCHAR query[] = { | |
3013 | 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', | |
3014 | '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ', | |
3015 | '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ', | |
3016 | '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ', | |
3017 | '`','D','i','s','k','I','d','`',0}; | |
3018 | ||
3019 | file = get_loaded_file(package, comp->KeyPath); | |
3020 | if (!file) | |
3021 | continue; | |
3022 | ||
3023 | row = MSI_QueryGetRecord(package->db, query, file->Sequence); | |
3024 | sprintfW(source, fmt, MSI_RecordGetInteger(row, 1)); | |
3025 | ptr2 = strrchrW(source, '\\') + 1; | |
3026 | msiobj_release(&row->hdr); | |
3027 | ||
3028 | lstrcpyW(base, package->PackagePath); | |
3029 | ptr = strrchrW(base, '\\'); | |
3030 | *(ptr + 1) = '\0'; | |
3031 | ||
d15fddf6 JH |
3032 | sourcepath = resolve_file_source(package, file); |
3033 | ptr = sourcepath + lstrlenW(base); | |
96dd6ce1 | 3034 | lstrcpyW(ptr2, ptr); |
d15fddf6 | 3035 | msi_free(sourcepath); |
96dd6ce1 JH |
3036 | |
3037 | msi_reg_set_val_str(hkey, squished_pc, source); | |
3038 | } | |
4aa3a997 | 3039 | RegCloseKey(hkey); |
fe8cd388 | 3040 | } |
4aa3a997 | 3041 | else if (ACTION_VerifyComponentForAction(comp, INSTALLSTATE_ABSENT)) |
288af81a JH |
3042 | { |
3043 | if (package->Context == MSIINSTALLCONTEXT_MACHINE) | |
a9e02909 | 3044 | MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid); |
288af81a | 3045 | else |
a9e02909 | 3046 | MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL); |
288af81a | 3047 | } |
a3a2eaea MM |
3048 | |
3049 | /* UI stuff */ | |
3050 | uirow = MSI_CreateRecord(3); | |
3051 | MSI_RecordSetStringW(uirow,1,package->ProductCode); | |
3052 | MSI_RecordSetStringW(uirow,2,comp->ComponentId); | |
3053 | MSI_RecordSetStringW(uirow,3,comp->FullKeypath); | |
3054 | ui_actiondata(package,szProcessComponents,uirow); | |
3055 | msiobj_release( &uirow->hdr ); | |
3056 | } | |
4aa3a997 JH |
3057 | |
3058 | return ERROR_SUCCESS; | |
b942e186 AS |
3059 | } |
3060 | ||
6e821739 AS |
3061 | typedef struct { |
3062 | CLSID clsid; | |
3063 | LPWSTR source; | |
3064 | ||
3065 | LPWSTR path; | |
3066 | ITypeLib *ptLib; | |
3067 | } typelib_struct; | |
3068 | ||
f9acfe63 | 3069 | static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType, |
6e821739 AS |
3070 | LPWSTR lpszName, LONG_PTR lParam) |
3071 | { | |
3072 | TLIBATTR *attr; | |
3073 | typelib_struct *tl_struct = (typelib_struct*) lParam; | |
3074 | static const WCHAR fmt[] = {'%','s','\\','%','i',0}; | |
3075 | int sz; | |
3076 | HRESULT res; | |
3077 | ||
3078 | if (!IS_INTRESOURCE(lpszName)) | |
3079 | { | |
3080 | ERR("Not Int Resource Name %s\n",debugstr_w(lpszName)); | |
3081 | return TRUE; | |
3082 | } | |
3083 | ||
3084 | sz = strlenW(tl_struct->source)+4; | |
3085 | sz *= sizeof(WCHAR); | |
3086 | ||
2acf800f | 3087 | if ((INT_PTR)lpszName == 1) |
ca8c4e41 AS |
3088 | tl_struct->path = strdupW(tl_struct->source); |
3089 | else | |
3090 | { | |
ee034ba4 | 3091 | tl_struct->path = msi_alloc(sz); |
ca8c4e41 AS |
3092 | sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName); |
3093 | } | |
6e821739 AS |
3094 | |
3095 | TRACE("trying %s\n", debugstr_w(tl_struct->path)); | |
3096 | res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib); | |
704ebf28 | 3097 | if (FAILED(res)) |
6e821739 | 3098 | { |
ee034ba4 | 3099 | msi_free(tl_struct->path); |
6e821739 AS |
3100 | tl_struct->path = NULL; |
3101 | ||
3102 | return TRUE; | |
3103 | } | |
3104 | ||
3105 | ITypeLib_GetLibAttr(tl_struct->ptLib, &attr); | |
3106 | if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid))) | |
3107 | { | |
3108 | ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr); | |
3109 | return FALSE; | |
3110 | } | |
3111 | ||
ee034ba4 | 3112 | msi_free(tl_struct->path); |
6e821739 AS |
3113 | tl_struct->path = NULL; |
3114 | ||
3115 | ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr); | |
3116 | ITypeLib_Release(tl_struct->ptLib); | |
3117 | ||
3118 | return TRUE; | |
3119 | } | |
3120 | ||
234dc4b2 | 3121 | static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param) |
fcb20c53 | 3122 | { |
5f3ac30b | 3123 | MSIPACKAGE* package = param; |
234dc4b2 | 3124 | LPCWSTR component; |
38d67a45 | 3125 | MSICOMPONENT *comp; |
e18f8abe | 3126 | MSIFILE *file; |
234dc4b2 | 3127 | typelib_struct tl_struct; |
469e4a5c | 3128 | ITypeLib *tlib; |
234dc4b2 | 3129 | HMODULE module; |
469e4a5c JH |
3130 | HRESULT hr; |
3131 | ||
234dc4b2 AS |
3132 | static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0}; |
3133 | ||
3134 | component = MSI_RecordGetString(row,3); | |
38d67a45 MM |
3135 | comp = get_loaded_component(package,component); |
3136 | if (!comp) | |
84837d96 | 3137 | return ERROR_SUCCESS; |
fcb20c53 | 3138 | |
d693f461 | 3139 | if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL)) |
fcb20c53 | 3140 | { |
234dc4b2 | 3141 | TRACE("Skipping typelib reg due to disabled component\n"); |
fcb20c53 | 3142 | |
38d67a45 | 3143 | comp->Action = comp->Installed; |
fcb20c53 | 3144 | |
234dc4b2 AS |
3145 | return ERROR_SUCCESS; |
3146 | } | |
fcb20c53 | 3147 | |
38d67a45 | 3148 | comp->Action = INSTALLSTATE_LOCAL; |
fcb20c53 | 3149 | |
e18f8abe MM |
3150 | file = get_loaded_file( package, comp->KeyPath ); |
3151 | if (!file) | |
234dc4b2 | 3152 | return ERROR_SUCCESS; |
90c57396 | 3153 | |
e18f8abe | 3154 | module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE ); |
51c6618d | 3155 | if (module) |
234dc4b2 | 3156 | { |
51c6618d MM |
3157 | LPCWSTR guid; |
3158 | guid = MSI_RecordGetString(row,1); | |
3159 | CLSIDFromString((LPWSTR)guid, &tl_struct.clsid); | |
e18f8abe | 3160 | tl_struct.source = strdupW( file->TargetPath ); |
234dc4b2 | 3161 | tl_struct.path = NULL; |
fcb20c53 | 3162 | |
234dc4b2 AS |
3163 | EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc, |
3164 | (LONG_PTR)&tl_struct); | |
90c57396 | 3165 | |
51c6618d | 3166 | if (tl_struct.path) |
fcb20c53 | 3167 | { |
234dc4b2 AS |
3168 | LPWSTR help = NULL; |
3169 | LPCWSTR helpid; | |
3170 | HRESULT res; | |
fcb20c53 | 3171 | |
234dc4b2 | 3172 | helpid = MSI_RecordGetString(row,6); |
fcb20c53 | 3173 | |
234dc4b2 | 3174 | if (helpid) |
8cedb218 | 3175 | help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL); |
234dc4b2 | 3176 | res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help); |
ee034ba4 | 3177 | msi_free(help); |
ba8200bf | 3178 | |
704ebf28 | 3179 | if (FAILED(res)) |
234dc4b2 AS |
3180 | ERR("Failed to register type library %s\n", |
3181 | debugstr_w(tl_struct.path)); | |
3182 | else | |
fcb20c53 | 3183 | { |
234dc4b2 | 3184 | ui_actiondata(package,szRegisterTypeLibraries,row); |
6e821739 | 3185 | |
234dc4b2 | 3186 | TRACE("Registered %s\n", debugstr_w(tl_struct.path)); |
6e821739 | 3187 | } |
234dc4b2 AS |
3188 | |
3189 | ITypeLib_Release(tl_struct.ptLib); | |
ee034ba4 | 3190 | msi_free(tl_struct.path); |
fcb20c53 AS |
3191 | } |
3192 | else | |
234dc4b2 AS |
3193 | ERR("Failed to load type library %s\n", |
3194 | debugstr_w(tl_struct.source)); | |
3195 | ||
3196 | FreeLibrary(module); | |
ee034ba4 | 3197 | msi_free(tl_struct.source); |
fcb20c53 | 3198 | } |
234dc4b2 | 3199 | else |
469e4a5c JH |
3200 | { |
3201 | hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib); | |
3202 | if (FAILED(hr)) | |
3203 | { | |
3204 | ERR("Failed to load type library: %08x\n", hr); | |
3205 | return ERROR_FUNCTION_FAILED; | |
3206 | } | |
3207 | ||
3208 | ITypeLib_Release(tlib); | |
3209 | } | |
234dc4b2 AS |
3210 | |
3211 | return ERROR_SUCCESS; | |
3212 | } | |
3213 | ||
3214 | static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package) | |
3215 | { | |
3216 | /* | |
3217 | * OK this is a bit confusing.. I am given a _Component key and I believe | |
3218 | * that the file that is being registered as a type library is the "key file | |
3219 | * of that component" which I interpret to mean "The file in the KeyPath of | |
3220 | * that component". | |
3221 | */ | |
3222 | UINT rc; | |
3223 | MSIQUERY * view; | |
3224 | static const WCHAR Query[] = | |
3225 | {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', | |
3226 | '`','T','y','p','e','L','i','b','`',0}; | |
3227 | ||
234dc4b2 AS |
3228 | rc = MSI_DatabaseOpenViewW(package->db, Query, &view); |
3229 | if (rc != ERROR_SUCCESS) | |
3230 | return ERROR_SUCCESS; | |
3231 | ||
3232 | rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package); | |
a7a6f5f3 | 3233 | msiobj_release(&view->hdr); |
fcb20c53 | 3234 | return rc; |
fcb20c53 AS |
3235 | } |
3236 | ||
9adacf6a | 3237 | static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param) |
2cf222f9 | 3238 | { |
5f3ac30b | 3239 | MSIPACKAGE *package = param; |
477bce38 | 3240 | LPWSTR target_file, target_folder, filename; |
4ac85674 | 3241 | LPCWSTR buffer, extension; |
38d67a45 | 3242 | MSICOMPONENT *comp; |
9adacf6a | 3243 | static const WCHAR szlnk[]={'.','l','n','k',0}; |
20c57466 MM |
3244 | IShellLinkW *sl = NULL; |
3245 | IPersistFile *pf = NULL; | |
2cf222f9 AS |
3246 | HRESULT res; |
3247 | ||
9adacf6a | 3248 | buffer = MSI_RecordGetString(row,4); |
38d67a45 MM |
3249 | comp = get_loaded_component(package,buffer); |
3250 | if (!comp) | |
84837d96 | 3251 | return ERROR_SUCCESS; |
2cf222f9 | 3252 | |
d693f461 | 3253 | if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL )) |
2cf222f9 | 3254 | { |
9adacf6a | 3255 | TRACE("Skipping shortcut creation due to disabled component\n"); |
2cf222f9 | 3256 | |
38d67a45 | 3257 | comp->Action = comp->Installed; |
2cf222f9 | 3258 | |
9adacf6a AS |
3259 | return ERROR_SUCCESS; |
3260 | } | |
2cf222f9 | 3261 | |
38d67a45 | 3262 | comp->Action = INSTALLSTATE_LOCAL; |
2cf222f9 | 3263 | |
9adacf6a | 3264 | ui_actiondata(package,szCreateShortcuts,row); |
90c57396 | 3265 | |
9adacf6a AS |
3266 | res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, |
3267 | &IID_IShellLinkW, (LPVOID *) &sl ); | |
90c57396 | 3268 | |
20c57466 | 3269 | if (FAILED( res )) |
9adacf6a | 3270 | { |
20c57466 MM |
3271 | ERR("CLSID_ShellLink not available\n"); |
3272 | goto err; | |
9adacf6a | 3273 | } |
2cf222f9 | 3274 | |
9adacf6a | 3275 | res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf ); |
20c57466 | 3276 | if (FAILED( res )) |
9adacf6a | 3277 | { |
20c57466 MM |
3278 | ERR("QueryInterface(IID_IPersistFile) failed\n"); |
3279 | goto err; | |
9adacf6a | 3280 | } |
90c57396 | 3281 | |
9adacf6a | 3282 | buffer = MSI_RecordGetString(row,2); |
8cedb218 | 3283 | target_folder = resolve_folder(package, buffer,FALSE,FALSE,TRUE,NULL); |
2cf222f9 | 3284 | |
5644f05e | 3285 | /* may be needed because of a bug somewhere else */ |
9adacf6a | 3286 | create_full_pathW(target_folder); |
2cf222f9 | 3287 | |
477bce38 | 3288 | filename = msi_dup_record_field( row, 3 ); |
9adacf6a | 3289 | reduce_to_longfilename(filename); |
4ac85674 RS |
3290 | |
3291 | extension = strchrW(filename,'.'); | |
3292 | if (!extension || strcmpiW(extension,szlnk)) | |
3293 | { | |
3294 | int len = strlenW(filename); | |
3295 | filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk)); | |
3296 | memcpy(filename + len, szlnk, sizeof(szlnk)); | |
3297 | } | |
9adacf6a | 3298 | target_file = build_directory_name(2, target_folder, filename); |
ee034ba4 | 3299 | msi_free(target_folder); |
477bce38 | 3300 | msi_free(filename); |
2cf222f9 | 3301 | |
9adacf6a AS |
3302 | buffer = MSI_RecordGetString(row,5); |
3303 | if (strchrW(buffer,'[')) | |
3304 | { | |
3305 | LPWSTR deformated; | |
3306 | deformat_string(package,buffer,&deformated); | |
3307 | IShellLinkW_SetPath(sl,deformated); | |
ee034ba4 | 3308 | msi_free(deformated); |
9adacf6a AS |
3309 | } |
3310 | else | |
3311 | { | |
9adacf6a | 3312 | FIXME("poorly handled shortcut format, advertised shortcut\n"); |
566c69e7 | 3313 | IShellLinkW_SetPath(sl,comp->FullKeypath); |
9adacf6a | 3314 | } |
2cf222f9 | 3315 | |
9adacf6a AS |
3316 | if (!MSI_RecordIsNull(row,6)) |
3317 | { | |
3318 | LPWSTR deformated; | |
3319 | buffer = MSI_RecordGetString(row,6); | |
3320 | deformat_string(package,buffer,&deformated); | |
3321 | IShellLinkW_SetArguments(sl,deformated); | |
ee034ba4 | 3322 | msi_free(deformated); |
9adacf6a | 3323 | } |
2cf222f9 | 3324 | |
9adacf6a AS |
3325 | if (!MSI_RecordIsNull(row,7)) |
3326 | { | |
3327 | buffer = MSI_RecordGetString(row,7); | |
3328 | IShellLinkW_SetDescription(sl,buffer); | |
3329 | } | |
8cc14a93 | 3330 | |
9adacf6a AS |
3331 | if (!MSI_RecordIsNull(row,8)) |
3332 | IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8)); | |
2cf222f9 | 3333 | |
9adacf6a AS |
3334 | if (!MSI_RecordIsNull(row,9)) |
3335 | { | |
75658d7a | 3336 | LPWSTR Path; |
9adacf6a | 3337 | INT index; |
2cf222f9 | 3338 | |
9adacf6a | 3339 | buffer = MSI_RecordGetString(row,9); |
2cf222f9 | 3340 | |
75658d7a | 3341 | Path = build_icon_path(package,buffer); |
9adacf6a | 3342 | index = MSI_RecordGetInteger(row,10); |
2cf222f9 | 3343 | |
ab378803 RS |
3344 | /* no value means 0 */ |
3345 | if (index == MSI_NULL_INTEGER) | |
3346 | index = 0; | |
3347 | ||
9adacf6a | 3348 | IShellLinkW_SetIconLocation(sl,Path,index); |
ee034ba4 | 3349 | msi_free(Path); |
9adacf6a | 3350 | } |
2cf222f9 | 3351 | |
9adacf6a AS |
3352 | if (!MSI_RecordIsNull(row,11)) |
3353 | IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11)); | |
2cf222f9 | 3354 | |
9adacf6a AS |
3355 | if (!MSI_RecordIsNull(row,12)) |
3356 | { | |
3357 | LPWSTR Path; | |
3358 | buffer = MSI_RecordGetString(row,12); | |
8cedb218 | 3359 | Path = resolve_folder(package, buffer, FALSE, FALSE, TRUE, NULL); |
43f7f3ec MM |
3360 | if (Path) |
3361 | IShellLinkW_SetWorkingDirectory(sl,Path); | |
ee034ba4 | 3362 | msi_free(Path); |
9adacf6a | 3363 | } |
2cf222f9 | 3364 | |
9adacf6a AS |
3365 | TRACE("Writing shortcut to %s\n",debugstr_w(target_file)); |
3366 | IPersistFile_Save(pf,target_file,FALSE); | |
2cf222f9 | 3367 | |
ee034ba4 | 3368 | msi_free(target_file); |
2cf222f9 | 3369 | |
20c57466 MM |
3370 | err: |
3371 | if (pf) | |
3372 | IPersistFile_Release( pf ); | |
3373 | if (sl) | |
3374 | IShellLinkW_Release( sl ); | |
2cf222f9 | 3375 | |
9adacf6a AS |
3376 | return ERROR_SUCCESS; |
3377 | } | |
2cf222f9 | 3378 | |
9adacf6a AS |
3379 | static UINT ACTION_CreateShortcuts(MSIPACKAGE *package) |
3380 | { | |
3381 | UINT rc; | |
3382 | HRESULT res; | |
3383 | MSIQUERY * view; | |
3384 | static const WCHAR Query[] = | |
3385 | {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', | |
3386 | '`','S','h','o','r','t','c','u','t','`',0}; | |
fa384f6b | 3387 | |
9adacf6a AS |
3388 | rc = MSI_DatabaseOpenViewW(package->db, Query, &view); |
3389 | if (rc != ERROR_SUCCESS) | |
3390 | return ERROR_SUCCESS; | |
3391 | ||
3392 | res = CoInitialize( NULL ); | |
2cf222f9 | 3393 | |
9adacf6a AS |
3394 | rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package); |
3395 | msiobj_release(&view->hdr); | |
2cf222f9 | 3396 | |
dd1ca6ca HL |
3397 | if (SUCCEEDED(res)) |
3398 | CoUninitialize(); | |
2cf222f9 | 3399 | |
8f0a7619 AS |
3400 | return rc; |
3401 | } | |
3402 | ||
fac97bb8 | 3403 | static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param) |
916ef949 | 3404 | { |
5f3ac30b | 3405 | MSIPACKAGE* package = param; |
916ef949 | 3406 | HANDLE the_file; |
75658d7a MM |
3407 | LPWSTR FilePath; |
3408 | LPCWSTR FileName; | |
916ef949 AS |
3409 | CHAR buffer[1024]; |
3410 | DWORD sz; | |
3411 | UINT rc; | |
d2e48e01 | 3412 | MSIRECORD *uirow; |
916ef949 AS |
3413 | |
3414 | FileName = MSI_RecordGetString(row,1); | |
3415 | if (!FileName) | |
3416 | { | |
3417 | ERR("Unable to get FileName\n"); | |
3418 | return ERROR_SUCCESS; | |
3419 | } | |
3420 | ||
75658d7a | 3421 | FilePath = build_icon_path(package,FileName); |
916ef949 AS |
3422 | |
3423 | TRACE("Creating icon file at %s\n",debugstr_w(FilePath)); | |
3424 | ||
3425 | the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, | |
3426 | FILE_ATTRIBUTE_NORMAL, NULL); | |
3427 | ||
3428 | if (the_file == INVALID_HANDLE_VALUE) | |
3429 | { | |
3430 | ERR("Unable to create file %s\n",debugstr_w(FilePath)); | |
ee034ba4 | 3431 | msi_free(FilePath); |
916ef949 AS |
3432 | return ERROR_SUCCESS; |
3433 | } | |
3434 | ||
3435 | do | |
3436 | { | |
3437 | DWORD write; | |
3438 | sz = 1024; | |
3439 | rc = MSI_RecordReadStream(row,2,buffer,&sz); | |
3440 | if (rc != ERROR_SUCCESS) | |
3441 | { | |
3442 | ERR("Failed to get stream\n"); | |
3443 | CloseHandle(the_file); | |
3444 | DeleteFileW(FilePath); | |
3445 | break; | |
3446 | } | |
3447 | WriteFile(the_file,buffer,sz,&write,NULL); | |
3448 | } while (sz == 1024); | |
3449 | ||
ee034ba4 | 3450 | msi_free(FilePath); |
916ef949 AS |
3451 | |
3452 | CloseHandle(the_file); | |
d2e48e01 RS |
3453 | |
3454 | uirow = MSI_CreateRecord(1); | |
3455 | MSI_RecordSetStringW(uirow,1,FileName); | |
3456 | ui_actiondata(package,szPublishProduct,uirow); | |
3457 | msiobj_release( &uirow->hdr ); | |
3458 | ||
916ef949 AS |
3459 | return ERROR_SUCCESS; |
3460 | } | |
2cf222f9 | 3461 | |
fac97bb8 JH |
3462 | static UINT msi_publish_icons(MSIPACKAGE *package) |
3463 | { | |
3464 | UINT r; | |
3465 | MSIQUERY *view; | |
3466 | ||
3467 | static const WCHAR query[]= { | |
3468 | 'S','E','L','E','C','T',' ','*',' ', | |
3469 | 'F','R','O','M',' ','`','I','c','o','n','`',0}; | |
3470 | ||
3471 | r = MSI_DatabaseOpenViewW(package->db, query, &view); | |
3472 | if (r == ERROR_SUCCESS) | |
3473 | { | |
3474 | MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package); | |
3475 | msiobj_release(&view->hdr); | |
3476 | } | |
3477 | ||
3478 | return ERROR_SUCCESS; | |
3479 | } | |
3480 | ||
2d4e4b6a | 3481 | static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey) |
68e6071d JH |
3482 | { |
3483 | UINT r; | |
2d4e4b6a | 3484 | HKEY source; |
68e6071d JH |
3485 | LPWSTR buffer; |
3486 | MSIMEDIADISK *disk; | |
3487 | MSISOURCELISTINFO *info; | |
3488 | ||
3489 | static const WCHAR szEmpty[] = {0}; | |
2d4e4b6a JH |
3490 | static const WCHAR szSourceList[] = {'S','o','u','r','c','e','L','i','s','t',0}; |
3491 | ||
3492 | r = RegCreateKeyW(hkey, szSourceList, &source); | |
3493 | if (r != ERROR_SUCCESS) | |
3494 | return r; | |
3495 | ||
3496 | RegCloseKey(source); | |
68e6071d JH |
3497 | |
3498 | buffer = strrchrW(package->PackagePath, '\\') + 1; | |
3499 | r = MsiSourceListSetInfoW(package->ProductCode, NULL, | |
3500 | package->Context, MSICODE_PRODUCT, | |
3501 | INSTALLPROPERTY_PACKAGENAMEW, buffer); | |
3502 | if (r != ERROR_SUCCESS) | |
3503 | return r; | |
3504 | ||
3505 | r = MsiSourceListSetInfoW(package->ProductCode, NULL, | |
3506 | package->Context, MSICODE_PRODUCT, | |
3507 | INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty); | |
3508 | if (r != ERROR_SUCCESS) | |
3509 | return r; | |
3510 | ||
3511 | r = MsiSourceListSetInfoW(package->ProductCode, NULL, | |
3512 | package->Context, MSICODE_PRODUCT, | |
3513 | INSTALLPROPERTY_DISKPROMPTW, szEmpty); | |
3514 | if (r != ERROR_SUCCESS) | |
3515 | return r; | |
3516 | ||
3517 | LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry) | |
3518 | { | |
3519 | if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW)) | |
3520 | msi_set_last_used_source(package->ProductCode, NULL, info->context, | |
3521 | info->options, info->value); | |
3522 | else | |
3523 | MsiSourceListSetInfoW(package->ProductCode, NULL, | |
3524 | info->context, info->options, | |
3525 | info->property, info->value); | |
3526 | } | |
3527 | ||
3528 | LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry) | |
3529 | { | |
3530 | MsiSourceListAddMediaDiskW(package->ProductCode, NULL, | |
3531 | disk->context, disk->options, | |
3532 | disk->disk_id, disk->volume_label, disk->disk_prompt); | |
3533 | } | |
3534 | ||
3535 | return ERROR_SUCCESS; | |
3536 | } | |
3537 | ||
ebeb5379 JH |
3538 | static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey) |
3539 | { | |
3540 | MSIHANDLE hdb, suminfo; | |
3541 | WCHAR guids[MAX_PATH]; | |
db2e8d2f | 3542 | WCHAR packcode[SQUISH_GUID_SIZE]; |
ebeb5379 JH |
3543 | LPWSTR buffer; |
3544 | LPWSTR ptr; | |
3545 | DWORD langid; | |
3546 | DWORD size; | |
3547 | UINT r; | |
3548 | ||
3549 | static const WCHAR szProductLanguage[] = | |
3550 | {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0}; | |
3551 | static const WCHAR szARPProductIcon[] = | |
3552 | {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0}; | |
3553 | static const WCHAR szProductVersion[] = | |
3554 | {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0}; | |
ef640a6c JH |
3555 | static const WCHAR szAssignment[] = |
3556 | {'A','s','s','i','g','n','m','e','n','t',0}; | |
3557 | static const WCHAR szAdvertiseFlags[] = | |
3558 | {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0}; | |
3559 | static const WCHAR szClients[] = | |
3560 | {'C','l','i','e','n','t','s',0}; | |
3561 | static const WCHAR szColon[] = {':',0}; | |
ebeb5379 JH |
3562 | |
3563 | buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW); | |
3564 | msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer); | |
3565 | msi_free(buffer); | |
3566 | ||
3567 | langid = msi_get_property_int(package, szProductLanguage, 0); | |
3568 | msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid); | |
3569 | ||
ebeb5379 JH |
3570 | /* FIXME */ |
3571 | msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0); | |
3572 | ||
3573 | buffer = msi_dup_property(package, szARPProductIcon); | |
3574 | if (buffer) | |
3575 | { | |
3576 | LPWSTR path = build_icon_path(package,buffer); | |
3577 | msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path); | |
3578 | msi_free(path); | |
3579 | msi_free(buffer); | |
3580 | } | |
3581 | ||
3582 | buffer = msi_dup_property(package, szProductVersion); | |
3583 | if (buffer) | |
3584 | { | |
3585 | DWORD verdword = msi_version_str_to_dword(buffer); | |
3586 | msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword); | |
3587 | msi_free(buffer); | |
3588 | } | |
3589 | ||
ef640a6c JH |
3590 | msi_reg_set_val_dword(hkey, szAssignment, 0); |
3591 | msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184); | |
3592 | msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0); | |
3593 | msi_reg_set_val_str(hkey, szClients, szColon); | |
3594 | ||
ebeb5379 JH |
3595 | hdb = alloc_msihandle(&package->db->hdr); |
3596 | if (!hdb) | |
3597 | return ERROR_NOT_ENOUGH_MEMORY; | |
3598 | ||
3599 | r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo); | |
3600 | MsiCloseHandle(hdb); | |
3601 | if (r != ERROR_SUCCESS) | |
3602 | goto done; | |
3603 | ||
3604 | size = MAX_PATH; | |
3605 | r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL, | |
3606 | NULL, guids, &size); | |
3607 | if (r != ERROR_SUCCESS) | |
3608 | goto done; | |
3609 | ||
3610 | ptr = strchrW(guids, ';'); | |
3611 | if (ptr) *ptr = 0; | |
db2e8d2f JH |
3612 | squash_guid(guids, packcode); |
3613 | msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode); | |
ebeb5379 JH |
3614 | |
3615 | done: | |
3616 | MsiCloseHandle(suminfo); | |
3617 | return ERROR_SUCCESS; | |
3618 | } | |
3619 | ||
cdb33f8a JH |
3620 | static UINT msi_publish_upgrade_code(MSIPACKAGE *package) |
3621 | { | |
3622 | UINT r; | |
3623 | HKEY hkey; | |
3624 | LPWSTR upgrade; | |
3625 | WCHAR squashed_pc[SQUISH_GUID_SIZE]; | |
3626 | ||
3627 | static const WCHAR szUpgradeCode[] = | |
3628 | {'U','p','g','r','a','d','e','C','o','d','e',0}; | |
3629 | ||
3630 | upgrade = msi_dup_property(package, szUpgradeCode); | |
3631 | if (!upgrade) | |
3632 | return ERROR_SUCCESS; | |
3633 | ||
58e15439 JH |
3634 | if (package->Context == MSIINSTALLCONTEXT_MACHINE) |
3635 | { | |
3636 | r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE); | |
3637 | if (r != ERROR_SUCCESS) | |
3638 | goto done; | |
3639 | } | |
3640 | else | |
3641 | { | |
3642 | r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE); | |
3643 | if (r != ERROR_SUCCESS) | |
3644 | goto done; | |
3645 | } | |
cdb33f8a JH |
3646 | |
3647 | squash_guid(package->ProductCode, squashed_pc); | |
3648 | msi_reg_set_val_str(hkey, squashed_pc, NULL); | |
3649 | ||
3650 | RegCloseKey(hkey); | |
3651 | ||
3652 | done: | |
3653 | msi_free(upgrade); | |
3654 | return r; | |
3655 | } | |
3656 | ||
a2df31ae JH |
3657 | static BOOL msi_check_publish(MSIPACKAGE *package) |
3658 | { | |
3659 | MSIFEATURE *feature; | |
3660 | ||
3661 | LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry) | |
3662 | { | |
3663 | if (feature->ActionRequest == INSTALLSTATE_LOCAL) | |
3664 | return TRUE; | |
3665 | } | |
3666 | ||
3667 | return FALSE; | |
3668 | } | |
3669 | ||
cdb33f8a JH |
3670 | static BOOL msi_check_unpublish(MSIPACKAGE *package) |
3671 | { | |
3672 | MSIFEATURE *feature; | |
3673 | ||
3674 | LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry) | |
3675 | { | |
3676 | if (feature->ActionRequest != INSTALLSTATE_ABSENT) | |
3677 | return FALSE; | |
3678 | } | |
3679 | ||
3680 | return TRUE; | |
3681 | } | |
3682 | ||
01eb9300 JH |
3683 | static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey) |
3684 | { | |
3685 | WCHAR patch_squashed[GUID_SIZE]; | |
3686 | HKEY patches; | |
3687 | LONG res; | |
3688 | UINT r = ERROR_FUNCTION_FAILED; | |
3689 | ||
3690 | static const WCHAR szPatches[] = {'P','a','t','c','h','e','s',0}; | |
3691 | ||
3692 | res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, | |
3693 | &patches, NULL); | |
3694 | if (res != ERROR_SUCCESS) | |
3695 | return ERROR_FUNCTION_FAILED; | |
3696 | ||
3697 | squash_guid(package->patch->patchcode, patch_squashed); | |
3698 | ||
3699 | res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ, | |
3700 | (const BYTE *)patch_squashed, | |
3701 | (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR)); | |
3702 | if (res != ERROR_SUCCESS) | |
3703 | goto done; | |
3704 | ||
3705 | res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ, | |
3706 | (const BYTE *)package->patch->transforms, | |
3707 | (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR)); | |
3708 | if (res == ERROR_SUCCESS) | |
3709 | r = ERROR_SUCCESS; | |
3710 | ||
3711 | done: | |
3712 | RegCloseKey(patches); | |
3713 | return r; | |
3714 | } | |
3715 | ||
2cf222f9 AS |
3716 | /* |
3717 | * 99% of the work done here is only done for | |
3718 | * advertised installs. However this is where the | |
3719 | * Icon table is processed and written out | |
817c5209 | 3720 | * so that is what I am going to do here. |
2cf222f9 | 3721 | */ |
a7a6f5f3 | 3722 | static UINT ACTION_PublishProduct(MSIPACKAGE *package) |
2cf222f9 AS |
3723 | { |
3724 | UINT rc; | |
68b07494 | 3725 | HKEY hukey=0; |
ee8b4a01 | 3726 | HKEY hudkey=0; |
2cf222f9 | 3727 | |
a2df31ae JH |
3728 | /* FIXME: also need to publish if the product is in advertise mode */ |
3729 | if (!msi_check_publish(package)) | |
3730 | return ERROR_SUCCESS; | |
3731 | ||
c965d839 | 3732 | rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context, |
70be1e77 JH |
3733 | &hukey, TRUE); |
3734 | if (rc != ERROR_SUCCESS) | |
3735 | goto end; | |
3736 | ||
4a9f6995 JH |
3737 | rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context, |
3738 | NULL, &hudkey, TRUE); | |
3739 | if (rc != ERROR_SUCCESS) | |
3740 | goto end; | |
6269f00c | 3741 | |
cdb33f8a JH |
3742 | rc = msi_publish_upgrade_code(package); |
3743 | if (rc != ERROR_SUCCESS) | |
3744 | goto end; | |
ebeb5379 | 3745 | |
01eb9300 JH |
3746 | if (package->patch) |
3747 | { | |
3748 | rc = msi_publish_patch(package, hukey, hudkey); | |
3749 | if (rc != ERROR_SUCCESS) | |
3750 | goto end; | |
3751 | } | |
3752 | ||
ebeb5379 JH |
3753 | rc = msi_publish_product_properties(package, hukey); |
3754 | if (rc != ERROR_SUCCESS) | |
337e1e20 | 3755 | goto end; |
2cae30b6 | 3756 | |
2d4e4b6a | 3757 | rc = msi_publish_sourcelist(package, hukey); |
68e6071d JH |
3758 | if (rc != ERROR_SUCCESS) |
3759 | goto end; | |
5e46fc90 | 3760 | |
68e6071d | 3761 | rc = msi_publish_icons(package); |
fac97bb8 | 3762 | |
6269f00c | 3763 | end: |
6269f00c | 3764 | RegCloseKey(hukey); |
c18b7755 | 3765 | RegCloseKey(hudkey); |
6269f00c | 3766 | |
2cf222f9 | 3767 | return rc; |
2cf222f9 AS |
3768 | } |
3769 | ||
aded32f3 | 3770 | static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param) |
516a9c70 | 3771 | { |
5f3ac30b | 3772 | MSIPACKAGE *package = param; |
bf9538f3 | 3773 | LPCWSTR component, section, key, value, identifier, dirproperty; |
aded32f3 | 3774 | LPWSTR deformated_section, deformated_key, deformated_value; |
bf9538f3 JH |
3775 | LPWSTR folder, filename, fullname = NULL; |
3776 | LPCWSTR filenameptr; | |
aded32f3 | 3777 | MSIRECORD * uirow; |
38d67a45 MM |
3778 | INT action; |
3779 | MSICOMPONENT *comp; | |
516a9c70 AS |
3780 | static const WCHAR szWindowsFolder[] = |
3781 | {'W','i','n','d','o','w','s','F','o','l','d','e','r',0}; | |
516a9c70 | 3782 | |
aded32f3 | 3783 | component = MSI_RecordGetString(row, 8); |
38d67a45 | 3784 | comp = get_loaded_component(package,component); |
516a9c70 | 3785 | |
d693f461 | 3786 | if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL)) |
516a9c70 | 3787 | { |
aded32f3 AS |
3788 | TRACE("Skipping ini file due to disabled component %s\n", |
3789 | debugstr_w(component)); | |
516a9c70 | 3790 | |
38d67a45 | 3791 | comp->Action = comp->Installed; |
516a9c70 | 3792 | |
aded32f3 AS |
3793 | return ERROR_SUCCESS; |
3794 | } | |
90c57396 | 3795 | |
38d67a45 | 3796 | comp->Action = INSTALLSTATE_LOCAL; |
90c57396 | 3797 | |
aded32f3 | 3798 | identifier = MSI_RecordGetString(row,1); |
aded32f3 AS |
3799 | dirproperty = MSI_RecordGetString(row,3); |
3800 | section = MSI_RecordGetString(row,4); | |
3801 | key = MSI_RecordGetString(row,5); | |
3802 | value = MSI_RecordGetString(row,6); | |
3803 | action = MSI_RecordGetInteger(row,7); | |
90c57396 | 3804 | |
aded32f3 AS |
3805 | deformat_string(package,section,&deformated_section); |
3806 | deformat_string(package,key,&deformated_key); | |
3807 | deformat_string(package,value,&deformated_value); | |
516a9c70 | 3808 | |
bf9538f3 JH |
3809 | filename = msi_dup_record_field(row, 2); |
3810 | if (filename && (filenameptr = strchrW(filename, '|'))) | |
3811 | filenameptr++; | |
3812 | else | |
3813 | filenameptr = filename; | |
3814 | ||
aded32f3 AS |
3815 | if (dirproperty) |
3816 | { | |
8cedb218 | 3817 | folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL); |
516a9c70 | 3818 | if (!folder) |
062ad505 | 3819 | folder = msi_dup_property( package, dirproperty ); |
aded32f3 AS |
3820 | } |
3821 | else | |
062ad505 | 3822 | folder = msi_dup_property( package, szWindowsFolder ); |
aded32f3 AS |
3823 | |
3824 | if (!folder) | |
3825 | { | |
3826 | ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty)); | |
3827 | goto cleanup; | |
3828 | } | |
516a9c70 | 3829 | |
bf9538f3 | 3830 | fullname = build_directory_name(2, folder, filenameptr); |
516a9c70 | 3831 | |
aded32f3 AS |
3832 | if (action == 0) |
3833 | { | |
3834 | TRACE("Adding value %s to section %s in %s\n", | |
516a9c70 AS |
3835 | debugstr_w(deformated_key), debugstr_w(deformated_section), |
3836 | debugstr_w(fullname)); | |
aded32f3 AS |
3837 | WritePrivateProfileStringW(deformated_section, deformated_key, |
3838 | deformated_value, fullname); | |
3839 | } | |
3840 | else if (action == 1) | |
3841 | { | |
3842 | WCHAR returned[10]; | |
3843 | GetPrivateProfileStringW(deformated_section, deformated_key, NULL, | |
3844 | returned, 10, fullname); | |
3845 | if (returned[0] == 0) | |
516a9c70 | 3846 | { |
aded32f3 | 3847 | TRACE("Adding value %s to section %s in %s\n", |
516a9c70 AS |
3848 | debugstr_w(deformated_key), debugstr_w(deformated_section), |
3849 | debugstr_w(fullname)); | |
3850 | ||
aded32f3 | 3851 | WritePrivateProfileStringW(deformated_section, deformated_key, |
516a9c70 | 3852 | deformated_value, fullname); |
516a9c70 | 3853 | } |
aded32f3 AS |
3854 | } |
3855 | else if (action == 3) | |
3856 | FIXME("Append to existing section not yet implemented\n"); | |
3857 | ||
3858 | uirow = MSI_CreateRecord(4); | |
3859 | MSI_RecordSetStringW(uirow,1,identifier); | |
3860 | MSI_RecordSetStringW(uirow,2,deformated_section); | |
3861 | MSI_RecordSetStringW(uirow,3,deformated_key); | |
3862 | MSI_RecordSetStringW(uirow,4,deformated_value); | |
3863 | ui_actiondata(package,szWriteIniValues,uirow); | |
3864 | msiobj_release( &uirow->hdr ); | |
bf9538f3 | 3865 | |
516a9c70 | 3866 | cleanup: |
bf9538f3 | 3867 | msi_free(filename); |
ee034ba4 MM |
3868 | msi_free(fullname); |
3869 | msi_free(folder); | |
3870 | msi_free(deformated_key); | |
3871 | msi_free(deformated_value); | |
3872 | msi_free(deformated_section); | |
aded32f3 AS |
3873 | return ERROR_SUCCESS; |
3874 | } | |
3875 | ||
3876 | static UINT ACTION_WriteIniValues(MSIPACKAGE *package) | |
3877 | { | |
3878 | UINT rc; | |
3879 | MSIQUERY * view; | |
3880 | static const WCHAR ExecSeqQuery[] = | |
3881 | {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', | |
3882 | '`','I','n','i','F','i','l','e','`',0}; | |
3883 | ||
3884 | rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); | |
3885 | if (rc != ERROR_SUCCESS) | |
3886 | { | |
3887 | TRACE("no IniFile table\n"); | |
3888 | return ERROR_SUCCESS; | |
516a9c70 | 3889 | } |
aded32f3 AS |
3890 | |
3891 | rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package); | |
516a9c70 AS |
3892 | msiobj_release(&view->hdr); |
3893 | return rc; | |
3894 | } | |
3895 | ||
854bfc4b | 3896 | static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param) |
6269f00c | 3897 | { |
5f3ac30b | 3898 | MSIPACKAGE *package = param; |
854bfc4b AS |
3899 | LPCWSTR filename; |
3900 | LPWSTR FullName; | |
e18f8abe | 3901 | MSIFILE *file; |
854bfc4b | 3902 | DWORD len; |
8e233e9b | 3903 | static const WCHAR ExeStr[] = |
c5a1443f AS |
3904 | {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0}; |
3905 | static const WCHAR close[] = {'\"',0}; | |
2cae30b6 AS |
3906 | STARTUPINFOW si; |
3907 | PROCESS_INFORMATION info; | |
3908 | BOOL brc; | |
d2e48e01 RS |
3909 | MSIRECORD *uirow; |
3910 | LPWSTR uipath, p; | |
2cae30b6 AS |
3911 | |
3912 | memset(&si,0,sizeof(STARTUPINFOW)); | |
3913 | ||
854bfc4b | 3914 | filename = MSI_RecordGetString(row,1); |
e18f8abe | 3915 | file = get_loaded_file( package, filename ); |
6269f00c | 3916 | |
e18f8abe | 3917 | if (!file) |
6269f00c | 3918 | { |
854bfc4b AS |
3919 | ERR("Unable to find file id %s\n",debugstr_w(filename)); |
3920 | return ERROR_SUCCESS; | |
6269f00c AS |
3921 | } |
3922 | ||
e18f8abe | 3923 | len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2; |
6269f00c | 3924 | |
ee034ba4 | 3925 | FullName = msi_alloc(len*sizeof(WCHAR)); |
854bfc4b | 3926 | strcpyW(FullName,ExeStr); |
e18f8abe | 3927 | strcatW( FullName, file->TargetPath ); |
854bfc4b | 3928 | strcatW(FullName,close); |
6269f00c | 3929 | |
854bfc4b AS |
3930 | TRACE("Registering %s\n",debugstr_w(FullName)); |
3931 | brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon, | |
3932 | &si, &info); | |
6269f00c | 3933 | |
854bfc4b | 3934 | if (brc) |
cda469c8 RS |
3935 | { |
3936 | CloseHandle(info.hThread); | |
854bfc4b | 3937 | msi_dialog_check_messages(info.hProcess); |
cda469c8 RS |
3938 | CloseHandle(info.hProcess); |
3939 | } | |
6269f00c | 3940 | |
ee034ba4 | 3941 | msi_free(FullName); |
d2e48e01 RS |
3942 | |
3943 | /* the UI chunk */ | |
3944 | uirow = MSI_CreateRecord( 2 ); | |
3945 | uipath = strdupW( file->TargetPath ); | |
3946 | p = strrchrW(uipath,'\\'); | |
3947 | if (p) | |
220f93db RS |
3948 | p[0]=0; |
3949 | MSI_RecordSetStringW( uirow, 1, &p[1] ); | |
d2e48e01 RS |
3950 | MSI_RecordSetStringW( uirow, 2, uipath); |
3951 | ui_actiondata( package, szSelfRegModules, uirow); | |
3952 | msiobj_release( &uirow->hdr ); | |
3953 | msi_free( uipath ); | |
3954 | /* FIXME: call ui_progress? */ | |
3955 | ||
854bfc4b AS |
3956 | return ERROR_SUCCESS; |
3957 | } | |
6269f00c | 3958 | |
854bfc4b AS |
3959 | static UINT ACTION_SelfRegModules(MSIPACKAGE *package) |
3960 | { | |
3961 | UINT rc; | |
3962 | MSIQUERY * view; | |
3963 | static const WCHAR ExecSeqQuery[] = | |
3964 | {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', | |
3965 | '`','S','e','l','f','R','e','g','`',0}; | |
6269f00c | 3966 | |
854bfc4b AS |
3967 | rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); |
3968 | if (rc != ERROR_SUCCESS) | |
3969 | { | |
3970 | TRACE("no SelfReg table\n"); | |
3971 | return ERROR_SUCCESS; | |
6269f00c | 3972 | } |
854bfc4b AS |
3973 | |
3974 | MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package); | |
6269f00c | 3975 | msiobj_release(&view->hdr); |
854bfc4b AS |
3976 | |
3977 | return ERROR_SUCCESS; | |
6269f00c AS |
3978 | } |
3979 | ||
3980 | static UINT ACTION_PublishFeatures(MSIPACKAGE *package) | |
3981 | { | |
1da2858c | 3982 | MSIFEATURE *feature; |
6269f00c | 3983 | UINT rc; |
2a180e06 | 3984 | HKEY hkey; |
be759ddd | 3985 | HKEY userdata = NULL; |
6ac08161 JH |
3986 | |
3987 | if (!msi_check_publish(package)) | |
3988 | return ERROR_SUCCESS; | |
3989 | ||
0c01c586 JH |
3990 | rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context, |
3991 | &hkey, TRUE); | |
3992 | if (rc != ERROR_SUCCESS) | |
3993 | goto end; | |
3994 | ||
e3074348 JH |
3995 | rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context, |
3996 | &userdata, TRUE); | |
3997 | if (rc != ERROR_SUCCESS) | |
3998 | goto end; | |
9f11a5a8 | 3999 | |
6269f00c | 4000 | /* here the guids are base 85 encoded */ |
1da2858c | 4001 | LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) |
6269f00c | 4002 | { |
3f2d5d7f | 4003 | ComponentList *cl; |
6269f00c AS |
4004 | LPWSTR data = NULL; |
4005 | GUID clsid; | |
6269f00c | 4006 | INT size; |
b39d8fc2 | 4007 | BOOL absent = FALSE; |
d2e48e01 | 4008 | MSIRECORD *uirow; |
6269f00c | 4009 | |
1da2858c MM |
4010 | if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) && |
4011 | !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) && | |
4012 | !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED )) | |
b39d8fc2 | 4013 | absent = TRUE; |
b6bc6aa6 | 4014 | |
3f2d5d7f | 4015 | size = 1; |
1da2858c | 4016 | LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) |
3f2d5d7f MM |
4017 | { |
4018 | size += 21; | |
4019 | } | |
79ca56cd | 4020 | if (feature->Feature_Parent) |
1da2858c | 4021 | size += strlenW( feature->Feature_Parent )+2; |
6269f00c | 4022 | |
ee034ba4 | 4023 | data = msi_alloc(size * sizeof(WCHAR)); |
6269f00c AS |
4024 | |
4025 | data[0] = 0; | |
1da2858c | 4026 | LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) |
6269f00c | 4027 | { |
38d67a45 | 4028 | MSICOMPONENT* component = cl->component; |
6269f00c | 4029 | WCHAR buf[21]; |
3f2d5d7f | 4030 | |
3a94011a | 4031 | buf[0] = 0; |
efcc1ec5 | 4032 | if (component->ComponentId) |
c5a1443f | 4033 | { |
3f2d5d7f MM |
4034 | TRACE("From %s\n",debugstr_w(component->ComponentId)); |
4035 | CLSIDFromString(component->ComponentId, &clsid); | |
c5a1443f AS |
4036 | encode_base85_guid(&clsid,buf); |
4037 | TRACE("to %s\n",debugstr_w(buf)); | |
4038 | strcatW(data,buf); | |
4039 | } | |
6269f00c | 4040 | } |
9f11a5a8 | 4041 | |
79ca56cd | 4042 | if (feature->Feature_Parent) |
6269f00c AS |
4043 | { |
4044 | static const WCHAR sep[] = {'\2',0}; | |
4045 | strcatW(data,sep); | |
1da2858c | 4046 | strcatW(data,feature->Feature_Parent); |
6269f00c AS |
4047 | } |
4048 | ||
9f11a5a8 | 4049 | msi_reg_set_val_str( userdata, feature->Feature, data ); |
ee034ba4 | 4050 | msi_free(data); |
6269f00c | 4051 | |
79ca56cd MM |
4052 | size = 0; |
4053 | if (feature->Feature_Parent) | |
4054 | size = strlenW(feature->Feature_Parent)*sizeof(WCHAR); | |
b39d8fc2 AS |
4055 | if (!absent) |
4056 | { | |
06bf8ea2 AJ |
4057 | static const WCHAR emptyW[] = {0}; |
4058 | size += sizeof(WCHAR); | |
2a180e06 | 4059 | RegSetValueExW(hkey,feature->Feature,0,REG_SZ, |
06bf8ea2 | 4060 | (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : emptyW),size); |
b39d8fc2 AS |
4061 | } |
4062 | else | |
4063 | { | |
79ca56cd | 4064 | size += 2*sizeof(WCHAR); |
ee034ba4 | 4065 | data = msi_alloc(size); |
b39d8fc2 | 4066 | data[0] = 0x6; |
79ca56cd MM |
4067 | data[1] = 0; |
4068 | if (feature->Feature_Parent) | |
4069 | strcpyW( &data[1], feature->Feature_Parent ); | |
2a180e06 | 4070 | RegSetValueExW(hkey,feature->Feature,0,REG_SZ, |
16466af7 | 4071 | (LPBYTE)data,size); |
ee034ba4 | 4072 | msi_free(data); |
b39d8fc2 | 4073 | } |
d2e48e01 RS |
4074 | |
4075 | /* the UI chunk */ | |
4076 | uirow = MSI_CreateRecord( 1 ); | |
4077 | MSI_RecordSetStringW( uirow, 1, feature->Feature ); | |
4078 | ui_actiondata( package, szPublishFeatures, uirow); | |
4079 | msiobj_release( &uirow->hdr ); | |
4080 | /* FIXME: call ui_progress? */ | |
6269f00c AS |
4081 | } |
4082 | ||
6269f00c | 4083 | end: |
2a180e06 JH |
4084 | RegCloseKey(hkey); |
4085 | RegCloseKey(userdata); | |
6269f00c AS |
4086 | return rc; |
4087 | } | |
4088 | ||
6ac08161 JH |
4089 | static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature) |
4090 | { | |
4091 | UINT r; | |
4092 | HKEY hkey; | |
4093 | ||
4094 | TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature)); | |
4095 | ||
0c01c586 JH |
4096 | r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context, |
4097 | &hkey, FALSE); | |
6ac08161 JH |
4098 | if (r == ERROR_SUCCESS) |
4099 | { | |
4100 | RegDeleteValueW(hkey, feature->Feature); | |
4101 | RegCloseKey(hkey); | |
4102 | } | |
4103 | ||
e3074348 JH |
4104 | r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context, |
4105 | &hkey, FALSE); | |
6ac08161 JH |
4106 | if (r == ERROR_SUCCESS) |
4107 | { | |
4108 | RegDeleteValueW(hkey, feature->Feature); | |
4109 | RegCloseKey(hkey); | |
4110 | } | |
4111 | ||
4112 | return ERROR_SUCCESS; | |
4113 | } | |
4114 | ||
4115 | static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package) | |
4116 | { | |
4117 | MSIFEATURE *feature; | |
4118 | ||
ccdf578b | 4119 | if (!msi_check_unpublish(package)) |
6ac08161 JH |
4120 | return ERROR_SUCCESS; |
4121 | ||
4122 | LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry) | |
4123 | { | |
4124 | msi_unpublish_feature(package, feature); | |
4125 | } | |
4126 | ||
4127 | return ERROR_SUCCESS; | |
4128 | } | |
4129 | ||
5f83069b | 4130 | static UINT msi_get_local_package_name( LPWSTR path ) |
61f24a4c | 4131 | { |
5f83069b MM |
4132 | static const WCHAR szInstaller[] = { |
4133 | '\\','I','n','s','t','a','l','l','e','r','\\',0}; | |
4134 | static const WCHAR fmt[] = { '%','x','.','m','s','i',0}; | |
4135 | DWORD time, len, i; | |
4136 | HANDLE handle; | |
4137 | ||
4138 | time = GetTickCount(); | |
4139 | GetWindowsDirectoryW( path, MAX_PATH ); | |
4140 | lstrcatW( path, szInstaller ); | |
4141 | CreateDirectoryW( path, NULL ); | |
4142 | ||
4143 | len = lstrlenW(path); | |
4144 | for (i=0; i<0x10000; i++) | |
61f24a4c | 4145 | { |
5f83069b MM |
4146 | snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff ); |
4147 | handle = CreateFileW( path, GENERIC_WRITE, 0, NULL, | |
4148 | CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 ); | |
61f24a4c MM |
4149 | if (handle != INVALID_HANDLE_VALUE) |
4150 | { | |
4151 | CloseHandle(handle); | |
4152 | break; | |
4153 | } | |
4154 | if (GetLastError() != ERROR_FILE_EXISTS && | |
4155 | GetLastError() != ERROR_SHARING_VIOLATION) | |
5f83069b MM |
4156 | return ERROR_FUNCTION_FAILED; |
4157 | } | |
4158 | ||
4159 | return ERROR_SUCCESS; | |
4160 | } | |
61f24a4c | 4161 | |
5f83069b MM |
4162 | static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey ) |
4163 | { | |
5f83069b | 4164 | WCHAR packagefile[MAX_PATH]; |
5f83069b MM |
4165 | UINT r; |
4166 | ||
4167 | r = msi_get_local_package_name( packagefile ); | |
4168 | if (r != ERROR_SUCCESS) | |
4169 | return r; | |
61f24a4c MM |
4170 | |
4171 | TRACE("Copying to local package %s\n",debugstr_w(packagefile)); | |
4172 | ||
c37849ad | 4173 | r = CopyFileW( package->db->path, packagefile, FALSE); |
61f24a4c MM |
4174 | |
4175 | if (!r) | |
4176 | { | |
f1d4646a | 4177 | ERR("Unable to copy package (%s -> %s) (error %d)\n", |
c37849ad | 4178 | debugstr_w(package->db->path), debugstr_w(packagefile), GetLastError()); |
61f24a4c MM |
4179 | return ERROR_FUNCTION_FAILED; |
4180 | } | |
4181 | ||
61f24a4c | 4182 | msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile ); |
fc6b9dd4 | 4183 | |
61f24a4c MM |
4184 | return ERROR_SUCCESS; |
4185 | } | |
4186 | ||
45de896a | 4187 | static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey) |
ba293eef MM |
4188 | { |
4189 | LPWSTR prop, val, key; | |
45de896a JH |
4190 | SYSTEMTIME systime; |
4191 | DWORD size, langid; | |
4192 | WCHAR date[9]; | |
4193 | LPWSTR buffer; | |
4194 | ||
4195 | static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0}; | |
4196 | static const WCHAR szWindowsInstaller[] = | |
4197 | {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0}; | |
4198 | static const WCHAR modpath_fmt[] = | |
4199 | {'M','s','i','E','x','e','c','.','e','x','e',' ', | |
4200 | '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0}; | |
4201 | static const WCHAR szModifyPath[] = | |
4202 | {'M','o','d','i','f','y','P','a','t','h',0}; | |
4203 | static const WCHAR szUninstallString[] = | |
4204 | {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0}; | |
4205 | static const WCHAR szEstimatedSize[] = | |
4206 | {'E','s','t','i','m','a','t','e','d','S','i','z','e',0}; | |
4207 | static const WCHAR szProductLanguage[] = | |
4208 | {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0}; | |
4209 | static const WCHAR szProductVersion[] = | |
4210 | {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0}; | |
4211 | static const WCHAR szProductName[] = | |
4212 | {'P','r','o','d','u','c','t','N','a','m','e',0}; | |
4213 | static const WCHAR szDisplayName[] = | |
4214 | {'D','i','s','p','l','a','y','N','a','m','e',0}; | |
4215 | static const WCHAR szDisplayVersion[] = | |
4216 | {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0}; | |
4217 | static const WCHAR szManufacturer[] = | |
4218 | {'M','a','n','u','f','a','c','t','u','r','e','r',0}; | |
4219 | ||
ba293eef MM |
4220 | static const LPCSTR propval[] = { |
4221 | "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix", | |
4222 | "ARPCONTACT", "Contact", | |
4223 | "ARPCOMMENTS", "Comments", | |
4224 | "ProductName", "DisplayName", | |
4225 | "ProductVersion", "DisplayVersion", | |
4226 | "ARPHELPLINK", "HelpLink", | |
4227 | "ARPHELPTELEPHONE", "HelpTelephone", | |
4228 | "ARPINSTALLLOCATION", "InstallLocation", | |
4229 | "SourceDir", "InstallSource", | |
4230 | "Manufacturer", "Publisher", | |
4231 | "ARPREADME", "Readme", | |
4232 | "ARPSIZE", "Size", | |
4233 | "ARPURLINFOABOUT", "URLInfoAbout", | |
4234 | "ARPURLUPDATEINFO", "URLUpdateInfo", | |
4235 | NULL, | |
4236 | }; | |
4237 | const LPCSTR *p = propval; | |
4238 | ||
45de896a | 4239 | while (*p) |
ba293eef | 4240 | { |
45de896a JH |
4241 | prop = strdupAtoW(*p++); |
4242 | key = strdupAtoW(*p++); | |
4243 | val = msi_dup_property(package, prop); | |
4244 | msi_reg_set_val_str(hkey, key, val); | |
ba293eef MM |
4245 | msi_free(val); |
4246 | msi_free(key); | |
4247 | msi_free(prop); | |
4248 | } | |
45de896a JH |
4249 | |
4250 | msi_reg_set_val_dword(hkey, szWindowsInstaller, 1); | |
4251 | ||
4252 | size = deformat_string(package, modpath_fmt, &buffer); | |
4253 | RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size); | |
4254 | RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size); | |
4255 | msi_free(buffer); | |
4256 | ||
4257 | /* FIXME: Write real Estimated Size when we have it */ | |
4258 | msi_reg_set_val_dword(hkey, szEstimatedSize, 0); | |
4259 | ||
4260 | buffer = msi_dup_property(package, szProductName); | |
4261 | msi_reg_set_val_str(hkey, szDisplayName, buffer); | |
4262 | msi_free(buffer); | |
4263 | ||
4264 | buffer = msi_dup_property(package, cszSourceDir); | |
4265 | msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer); | |
4266 | msi_free(buffer); | |
4267 | ||
4268 | buffer = msi_dup_property(package, szManufacturer); | |
4269 | msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer); | |
4270 | msi_free(buffer); | |
4271 | ||
4272 | GetLocalTime(&systime); | |
4273 | sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay); | |
4274 | msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date); | |
4275 | ||
4276 | langid = msi_get_property_int(package, szProductLanguage, 0); | |
4277 | msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid); | |
4278 | ||
4279 | buffer = msi_dup_property(package, szProductVersion); | |
4280 | msi_reg_set_val_str(hkey, szDisplayVersion, buffer); | |
4281 | if (buffer) | |
4282 | { | |
4283 | DWORD verdword = msi_version_str_to_dword(buffer); | |
4284 | ||
4285 | msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword); | |
4286 | msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24); | |
4287 | msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF); | |
4288 | msi_free(buffer); | |
4289 | } | |
4290 | ||
ba293eef MM |
4291 | return ERROR_SUCCESS; |
4292 | } | |
4293 | ||
2cae30b6 AS |
4294 | static UINT ACTION_RegisterProduct(MSIPACKAGE *package) |
4295 | { | |
45de896a JH |
4296 | WCHAR squashed_pc[SQUISH_GUID_SIZE]; |
4297 | LPWSTR upgrade_code; | |
4298 | HKEY hkey, props; | |
4299 | HKEY upgrade; | |
ba293eef | 4300 | UINT rc; |
e9db87b9 | 4301 | |
45de896a JH |
4302 | static const WCHAR szUpgradeCode[] = { |
4303 | 'U','p','g','r','a','d','e','C','o','d','e',0}; | |
0e44e090 JH |
4304 | |
4305 | /* FIXME: also need to publish if the product is in advertise mode */ | |
4306 | if (!msi_check_publish(package)) | |
4307 | return ERROR_SUCCESS; | |
2cae30b6 | 4308 | |
45de896a | 4309 | rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE); |
2cae30b6 | 4310 | if (rc != ERROR_SUCCESS) |
ba293eef | 4311 | return rc; |
2cae30b6 | 4312 | |
b5e3e19a JH |
4313 | rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, |
4314 | NULL, &props, TRUE); | |
4315 | if (rc != ERROR_SUCCESS) | |
4316 | goto done; | |
d52f48fe | 4317 | |
45de896a | 4318 | msi_make_package_local(package, props); |
d52f48fe | 4319 | |
45de896a JH |
4320 | rc = msi_publish_install_properties(package, hkey); |
4321 | if (rc != ERROR_SUCCESS) | |
4322 | goto done; | |
e9db87b9 | 4323 | |
45de896a JH |
4324 | rc = msi_publish_install_properties(package, props); |
4325 | if (rc != ERROR_SUCCESS) | |
4326 | goto done; | |
4db02cdb | 4327 | |
45de896a | 4328 | upgrade_code = msi_dup_property(package, szUpgradeCode); |
36a01505 AS |
4329 | if (upgrade_code) |
4330 | { | |
45de896a JH |
4331 | MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE); |
4332 | squash_guid(package->ProductCode, squashed_pc); | |
4333 | msi_reg_set_val_str(upgrade, squashed_pc, NULL); | |
4334 | RegCloseKey(upgrade); | |
ee034ba4 | 4335 | msi_free(upgrade_code); |
36a01505 | 4336 | } |
bcba82dc | 4337 | |
45de896a | 4338 | done: |
2cae30b6 | 4339 | RegCloseKey(hkey); |
2cae30b6 AS |
4340 | |
4341 | return ERROR_SUCCESS; | |
4342 | } | |
4343 | ||
4344 | static UINT ACTION_InstallExecute(MSIPACKAGE *package) | |
4345 | { | |
a977b2c3 | 4346 | return execute_script(package,INSTALL_SCRIPT); |
2cae30b6 AS |
4347 | } |
4348 | ||
624bbbe7 JH |
4349 | static UINT msi_unpublish_product(MSIPACKAGE *package) |
4350 | { | |
cdb33f8a | 4351 | LPWSTR upgrade; |
624bbbe7 JH |
4352 | LPWSTR remove = NULL; |
4353 | LPWSTR *features = NULL; | |
4354 | BOOL full_uninstall = TRUE; | |
4355 | MSIFEATURE *feature; | |
4356 | ||
4357 | static const WCHAR szRemove[] = {'R','E','M','O','V','E',0}; | |
4358 | static const WCHAR szAll[] = {'A','L','L',0}; | |
cdb33f8a JH |
4359 | static const WCHAR szUpgradeCode[] = |
4360 | {'U','p','g','r','a','d','e','C','o','d','e',0}; | |
624bbbe7 JH |
4361 | |
4362 | remove = msi_dup_property(package, szRemove); | |
4363 | if (!remove) | |
4364 | return ERROR_SUCCESS; | |
4365 | ||
4366 | features = msi_split_string(remove, ','); | |
4367 | if (!features) | |
4368 | { | |
4369 | msi_free(remove); | |
4370 | ERR("REMOVE feature list is empty!\n"); | |
4371 | return ERROR_FUNCTION_FAILED; | |
4372 | } | |
4373 | ||
4374 | if (!lstrcmpW(features[0], szAll)) | |
4375 | full_uninstall = TRUE; | |
4376 | else | |
4377 | { | |
4378 | LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry) | |
4379 | { | |
4380 | if (feature->Action != INSTALLSTATE_ABSENT) | |
4381 | full_uninstall = FALSE; | |
4382 | } | |
4383 | } | |
4384 | ||
4385 | if (!full_uninstall) | |
4386 | goto done; | |
4387 | ||
4388 | MSIREG_DeleteProductKey(package->ProductCode); | |
624bbbe7 | 4389 | MSIREG_DeleteUserDataProductKey(package->ProductCode); |
f6b27673 | 4390 | MSIREG_DeleteUninstallKey(package->ProductCode); |
624bbbe7 | 4391 | |
38106ac2 JH |
4392 | if (package->Context == MSIINSTALLCONTEXT_MACHINE) |
4393 | { | |
4394 | MSIREG_DeleteLocalClassesProductKey(package->ProductCode); | |
4395 | MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode); | |
4396 | } | |
4397 | else | |
4398 | { | |
4399 | MSIREG_DeleteUserProductKey(package->ProductCode); | |
4400 | MSIREG_DeleteUserFeaturesKey(package->ProductCode); | |
4401 | } | |
4402 | ||
cdb33f8a JH |
4403 | upgrade = msi_dup_property(package, szUpgradeCode); |
4404 | if (upgrade) | |
4405 | { | |
4406 | MSIREG_DeleteUserUpgradeCodesKey(upgrade); | |
4407 | msi_free(upgrade); | |
4408 | } | |
4409 | ||
624bbbe7 JH |
4410 | done: |
4411 | msi_free(remove); | |
4412 | msi_free(features); | |
4413 | return ERROR_SUCCESS; | |
4414 | } | |
4415 | ||
2cae30b6 AS |
4416 | static UINT ACTION_InstallFinalize(MSIPACKAGE *package) |
4417 | { | |
9cd707da AS |
4418 | UINT rc; |
4419 | ||
624bbbe7 JH |
4420 | rc = msi_unpublish_product(package); |
4421 | if (rc != ERROR_SUCCESS) | |
4422 | return rc; | |
4423 | ||
1ccf9449 | 4424 | /* turn off scheduling */ |
9cd707da AS |
4425 | package->script->CurrentlyScripting= FALSE; |
4426 | ||
54c67dd1 | 4427 | /* first do the same as an InstallExecute */ |
9cd707da AS |
4428 | rc = ACTION_InstallExecute(package); |
4429 | if (rc != ERROR_SUCCESS) | |
4430 | return rc; | |
54c67dd1 AS |
4431 | |
4432 | /* then handle Commit Actions */ | |
9cd707da | 4433 | rc = execute_script(package,COMMIT_SCRIPT); |
2cae30b6 | 4434 | |
9cd707da | 4435 | return rc; |
2cae30b6 AS |
4436 | } |
4437 | ||
c2e91588 | 4438 | UINT ACTION_ForceReboot(MSIPACKAGE *package) |
2cae30b6 AS |
4439 | { |
4440 | static const WCHAR RunOnce[] = { | |
4441 | 'S','o','f','t','w','a','r','e','\\', | |
4442 | 'M','i','c','r','o','s','o','f','t','\\', | |
4443 | 'W','i','n','d','o','w','s','\\', | |
4444 | 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', | |
09b8264f | 4445 | 'R','u','n','O','n','c','e',0}; |
2cae30b6 AS |
4446 | static const WCHAR InstallRunOnce[] = { |
4447 | 'S','o','f','t','w','a','r','e','\\', | |
4448 | 'M','i','c','r','o','s','o','f','t','\\', | |
4449 | 'W','i','n','d','o','w','s','\\', | |
4450 | 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', | |
4451 | 'I','n','s','t','a','l','l','e','r','\\', | |
09b8264f | 4452 | 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0}; |
2cae30b6 AS |
4453 | |
4454 | static const WCHAR msiexec_fmt[] = { | |
014ad3ba | 4455 | '%','s', |
2cae30b6 AS |
4456 | '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ', |
4457 | '\"','%','s','\"',0}; | |
4458 | static const WCHAR install_fmt[] = { | |
4459 | '/','I',' ','\"','%','s','\"',' ', | |
4460 | 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ', | |
4461 | 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0}; | |
014ad3ba | 4462 | WCHAR buffer[256], sysdir[MAX_PATH]; |
adaef111 | 4463 | HKEY hkey; |
4db02cdb | 4464 | WCHAR squished_pc[100]; |
2cae30b6 | 4465 | |
adaef111 | 4466 | squash_guid(package->ProductCode,squished_pc); |
2cae30b6 | 4467 | |
014ad3ba | 4468 | GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0])); |
2cae30b6 | 4469 | RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey); |
014ad3ba JL |
4470 | snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir, |
4471 | squished_pc); | |
2cae30b6 | 4472 | |
4db02cdb | 4473 | msi_reg_set_val_str( hkey, squished_pc, buffer ); |
2cae30b6 AS |
4474 | RegCloseKey(hkey); |
4475 | ||
4476 | TRACE("Reboot command %s\n",debugstr_w(buffer)); | |
4477 | ||
4478 | RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey); | |
adaef111 | 4479 | sprintfW(buffer,install_fmt,package->ProductCode,squished_pc); |
b6bc6aa6 | 4480 | |
4db02cdb | 4481 | msi_reg_set_val_str( hkey, squished_pc, buffer ); |
2cae30b6 AS |
4482 | RegCloseKey(hkey); |
4483 | ||
68b07494 | 4484 | return ERROR_INSTALL_SUSPEND; |
2cae30b6 AS |
4485 | } |
4486 | ||
563a50ab | 4487 | static UINT ACTION_ResolveSource(MSIPACKAGE* package) |
90c57396 | 4488 | { |
b921118f | 4489 | DWORD attrib; |
94d6818c | 4490 | UINT rc; |
fc564239 | 4491 | |
90c57396 | 4492 | /* |
fc564239 MM |
4493 | * We are currently doing what should be done here in the top level Install |
4494 | * however for Administrative and uninstalls this step will be needed | |
90c57396 | 4495 | */ |
94d6818c AS |
4496 | if (!package->PackagePath) |
4497 | return ERROR_SUCCESS; | |
4498 | ||
c777d309 | 4499 | msi_set_sourcedir_props(package, TRUE); |
c5075435 | 4500 | |
e28cedf6 | 4501 | attrib = GetFileAttributesW(package->db->path); |
94d6818c AS |
4502 | if (attrib == INVALID_FILE_ATTRIBUTES) |
4503 | { | |
4504 | LPWSTR prompt; | |
4505 | LPWSTR msg; | |
4506 | DWORD size = 0; | |
4507 | ||
4508 | rc = MsiSourceListGetInfoW(package->ProductCode, NULL, | |
82517d6d | 4509 | package->Context, MSICODE_PRODUCT, |
94d6818c AS |
4510 | INSTALLPROPERTY_DISKPROMPTW,NULL,&size); |
4511 | if (rc == ERROR_MORE_DATA) | |
4512 | { | |
ee034ba4 | 4513 | prompt = msi_alloc(size * sizeof(WCHAR)); |
94d6818c | 4514 | MsiSourceListGetInfoW(package->ProductCode, NULL, |
82517d6d | 4515 | package->Context, MSICODE_PRODUCT, |
94d6818c AS |
4516 | INSTALLPROPERTY_DISKPROMPTW,prompt,&size); |
4517 | } | |
4518 | else | |
e28cedf6 | 4519 | prompt = strdupW(package->db->path); |
94d6818c AS |
4520 | |
4521 | msg = generate_error_string(package,1302,1,prompt); | |
4522 | while(attrib == INVALID_FILE_ATTRIBUTES) | |
4523 | { | |
4524 | rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL); | |
4525 | if (rc == IDCANCEL) | |
4526 | { | |
4527 | rc = ERROR_INSTALL_USEREXIT; | |
4528 | break; | |
4529 | } | |
e28cedf6 | 4530 | attrib = GetFileAttributesW(package->db->path); |
94d6818c | 4531 | } |
ee034ba4 | 4532 | msi_free(prompt); |
94d6818c AS |
4533 | rc = ERROR_SUCCESS; |
4534 | } | |
4535 | else | |
4536 | return ERROR_SUCCESS; | |
4537 | ||
4538 | return rc; | |
90c57396 AS |
4539 | } |
4540 | ||
c7e88e08 AS |
4541 | static UINT ACTION_RegisterUser(MSIPACKAGE *package) |
4542 | { | |
c7e88e08 AS |
4543 | HKEY hkey=0; |
4544 | LPWSTR buffer; | |
c7e88e08 AS |
4545 | LPWSTR productid; |
4546 | UINT rc,i; | |
c7e88e08 AS |
4547 | |
4548 | static const WCHAR szPropKeys[][80] = | |
4549 | { | |
8e233e9b AS |
4550 | {'P','r','o','d','u','c','t','I','D',0}, |
4551 | {'U','S','E','R','N','A','M','E',0}, | |
4552 | {'C','O','M','P','A','N','Y','N','A','M','E',0}, | |
4553 | {0}, | |
c7e88e08 AS |
4554 | }; |
4555 | ||
4556 | static const WCHAR szRegKeys[][80] = | |
4557 | { | |
8e233e9b AS |
4558 | {'P','r','o','d','u','c','t','I','D',0}, |
4559 | {'R','e','g','O','w','n','e','r',0}, | |
4560 | {'R','e','g','C','o','m','p','a','n','y',0}, | |
4561 | {0}, | |
c7e88e08 AS |
4562 | }; |
4563 | ||
d52f48fe JH |
4564 | if (msi_check_unpublish(package)) |
4565 | { | |
4566 | MSIREG_DeleteUserDataProductKey(package->ProductCode); | |
4567 | return ERROR_SUCCESS; | |
4568 | } | |
4569 | ||
062ad505 | 4570 | productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW ); |
c7e88e08 AS |
4571 | if (!productid) |
4572 | return ERROR_SUCCESS; | |
4573 | ||
b5e3e19a JH |
4574 | rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, |
4575 | NULL, &hkey, TRUE); | |
c7e88e08 AS |
4576 | if (rc != ERROR_SUCCESS) |
4577 | goto end; | |
4578 | ||
67189f9d | 4579 | for( i = 0; szPropKeys[i][0]; i++ ) |
c7e88e08 | 4580 | { |
062ad505 | 4581 | buffer = msi_dup_property( package, szPropKeys[i] ); |
4db02cdb | 4582 | msi_reg_set_val_str( hkey, szRegKeys[i], buffer ); |
ee034ba4 | 4583 | msi_free( buffer ); |
c7e88e08 AS |
4584 | } |
4585 | ||
4586 | end: | |
ee034ba4 | 4587 | msi_free(productid); |
c7e88e08 AS |
4588 | RegCloseKey(hkey); |
4589 | ||
d2e48e01 RS |
4590 | /* FIXME: call ui_actiondata */ |
4591 | ||
d52f48fe | 4592 | return rc; |
c7e88e08 AS |
4593 | } |
4594 | ||
b6bc6aa6 AS |
4595 | |
4596 | static UINT ACTION_ExecuteAction(MSIPACKAGE *package) | |
4597 | { | |
4598 | UINT rc; | |
25f1e75d | 4599 | |
c9802931 | 4600 | package->script->InWhatSequence |= SEQUENCE_EXEC; |
b39d8fc2 | 4601 | rc = ACTION_ProcessExecSequence(package,FALSE); |
b6bc6aa6 AS |
4602 | return rc; |
4603 | } | |
4604 | ||
0af2487a | 4605 | |
072c5e56 AS |
4606 | static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param) |
4607 | { | |
5f3ac30b | 4608 | MSIPACKAGE *package = param; |
09b0abaa AS |
4609 | LPCWSTR compgroupid=NULL; |
4610 | LPCWSTR feature=NULL; | |
4611 | LPCWSTR text = NULL; | |
4612 | LPCWSTR qualifier = NULL; | |
4613 | LPCWSTR component = NULL; | |
6f43c18f AS |
4614 | LPWSTR advertise = NULL; |
4615 | LPWSTR output = NULL; | |
072c5e56 AS |
4616 | HKEY hkey; |
4617 | UINT rc = ERROR_SUCCESS; | |
38d67a45 | 4618 | MSICOMPONENT *comp; |
072c5e56 | 4619 | DWORD sz = 0; |
d2e48e01 | 4620 | MSIRECORD *uirow; |
b39d8fc2 | 4621 | |
09b0abaa | 4622 | component = MSI_RecordGetString(rec,3); |
38d67a45 MM |
4623 | comp = get_loaded_component(package,component); |
4624 | ||
d693f461 MM |
4625 | if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) && |
4626 | !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) && | |
4627 | !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED )) | |
b39d8fc2 AS |
4628 | { |
4629 | TRACE("Skipping: Component %s not scheduled for install\n", | |
4630 | debugstr_w(component)); | |
6f43c18f | 4631 | |
b39d8fc2 AS |
4632 | return ERROR_SUCCESS; |
4633 | } | |
072c5e56 | 4634 | |
09b0abaa | 4635 | compgroupid = MSI_RecordGetString(rec,1); |
d2e48e01 | 4636 | qualifier = MSI_RecordGetString(rec,2); |
072c5e56 AS |
4637 | |
4638 | rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE); | |
4639 | if (rc != ERROR_SUCCESS) | |
4640 | goto end; | |
4641 | ||
09b0abaa | 4642 | text = MSI_RecordGetString(rec,4); |
09b0abaa | 4643 | feature = MSI_RecordGetString(rec,5); |
072c5e56 | 4644 | |
38d67a45 | 4645 | advertise = create_component_advertise_string(package, comp, feature); |
6f43c18f AS |
4646 | |
4647 | sz = strlenW(advertise); | |
072c5e56 | 4648 | |
072c5e56 AS |
4649 | if (text) |
4650 | sz += lstrlenW(text); | |
072c5e56 AS |
4651 | |
4652 | sz+=3; | |
4653 | sz *= sizeof(WCHAR); | |
4654 | ||
3a94011a | 4655 | output = msi_alloc_zero(sz); |
6f43c18f | 4656 | strcpyW(output,advertise); |
470f23d4 | 4657 | msi_free(advertise); |
072c5e56 AS |
4658 | |
4659 | if (text) | |
4660 | strcatW(output,text); | |
4661 | ||
4db02cdb | 4662 | msi_reg_set_val_multi_str( hkey, qualifier, output ); |
072c5e56 AS |
4663 | |
4664 | end: | |
4665 | RegCloseKey(hkey); | |
ee034ba4 | 4666 | msi_free(output); |
d2e48e01 RS |
4667 | |
4668 | /* the UI chunk */ | |
4669 | uirow = MSI_CreateRecord( 2 ); | |
4670 | MSI_RecordSetStringW( uirow, 1, compgroupid ); | |
4671 | MSI_RecordSetStringW( uirow, 2, qualifier); | |
4672 | ui_actiondata( package, szPublishComponents, uirow); | |
4673 | msiobj_release( &uirow->hdr ); | |
4674 | /* FIXME: call ui_progress? */ | |
4675 | ||
072c5e56 AS |
4676 | return rc; |
4677 | } | |
4678 | ||
4679 | /* | |
4680 | * At present I am ignorning the advertised components part of this and only | |
4681 | * focusing on the qualified component sets | |
4682 | */ | |
4683 | static UINT ACTION_PublishComponents(MSIPACKAGE *package) | |
4684 | { | |
4685 | UINT rc; | |
4686 | MSIQUERY * view; | |
4687 | static const WCHAR ExecSeqQuery[] = | |
4688 | {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', | |
98e38082 AS |
4689 | '`','P','u','b','l','i','s','h', |
4690 | 'C','o','m','p','o','n','e','n','t','`',0}; | |
072c5e56 AS |
4691 | |
4692 | rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); | |
4693 | if (rc != ERROR_SUCCESS) | |
4694 | return ERROR_SUCCESS; | |
4695 | ||
4696 | rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package); | |
4697 | msiobj_release(&view->hdr); | |
4698 | ||
4699 | return rc; | |
4700 | } | |
202166c3 | 4701 | |
9bc12ade JH |
4702 | static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param) |
4703 | { | |
5f3ac30b | 4704 | MSIPACKAGE *package = param; |
9bc12ade JH |
4705 | MSIRECORD *row; |
4706 | MSIFILE *file; | |
4707 | SC_HANDLE hscm, service = NULL; | |
de4cab20 | 4708 | LPCWSTR comp, depends, pass; |
db71fb15 | 4709 | LPWSTR name = NULL, disp = NULL; |
9bc12ade JH |
4710 | LPCWSTR load_order, serv_name, key; |
4711 | DWORD serv_type, start_type; | |
4712 | DWORD err_control; | |
4713 | ||
4714 | static const WCHAR query[] = | |
4715 | {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ', | |
4716 | '`','C','o','m','p','o','n','e','n','t','`',' ', | |
4717 | 'W','H','E','R','E',' ', | |
4718 | '`','C','o','m','p','o','n','e','n','t','`',' ', | |
4719 | '=','\'','%','s','\'',0}; | |
4720 | ||
4721 | hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE); | |
4722 | if (!hscm) | |
4723 | { | |
4724 | ERR("Failed to open the SC Manager!\n"); | |
4725 | goto done; | |
4726 | } | |
4727 | ||
4728 | start_type = MSI_RecordGetInteger(rec, 5); | |
4729 | if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START) | |
4730 | goto done; | |
4731 | ||
4732 | depends = MSI_RecordGetString(rec, 8); | |
4733 | if (depends && *depends) | |
4734 | FIXME("Dependency list unhandled!\n"); | |
4735 | ||
de4cab20 JH |
4736 | deformat_string(package, MSI_RecordGetString(rec, 2), &name); |
4737 | deformat_string(package, MSI_RecordGetString(rec, 3), &disp); | |
9bc12ade JH |
4738 | serv_type = MSI_RecordGetInteger(rec, 4); |
4739 | err_control = MSI_RecordGetInteger(rec, 6); | |
4740 | load_order = MSI_RecordGetString(rec, 7); | |
4741 | serv_name = MSI_RecordGetString(rec, 9); | |
4742 | pass = MSI_RecordGetString(rec, 10); | |
4743 | comp = MSI_RecordGetString(rec, 12); | |
4744 | ||
4745 | /* fetch the service path */ | |
4746 | row = MSI_QueryGetRecord(package->db, query, comp); | |
4747 | if (!row) | |
4748 | { | |
4749 | ERR("Control query failed!\n"); | |
4750 | goto done; | |
4751 | } | |
4752 | ||
4753 | key = MSI_RecordGetString(row, 6); | |
9bc12ade JH |
4754 | |
4755 | file = get_loaded_file(package, key); | |
b6cfc405 | 4756 | msiobj_release(&row->hdr); |
9bc12ade JH |
4757 | if (!file) |
4758 | { | |
4759 | ERR("Failed to load the service file\n"); | |
4760 | goto done; | |
4761 | } | |
4762 | ||
4763 | service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type, | |
4764 | start_type, err_control, file->TargetPath, | |
4765 | load_order, NULL, NULL, serv_name, pass); | |
4766 | if (!service) | |
4767 | { | |
4768 | if (GetLastError() != ERROR_SERVICE_EXISTS) | |
4769 | ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError()); | |
4770 | } | |
4771 | ||
4772 | done: | |
4773 | CloseServiceHandle(service); | |
4774 | CloseServiceHandle(hscm); | |
de4cab20 JH |
4775 | msi_free(name); |
4776 | msi_free(disp); | |
9bc12ade JH |
4777 | |
4778 | return ERROR_SUCCESS; | |
4779 | } | |
4780 | ||
4781 | static UINT ACTION_InstallServices( MSIPACKAGE *package ) | |
4782 | { | |
4783 | UINT rc; | |
4784 | MSIQUERY * view; | |
4785 | static const WCHAR ExecSeqQuery[] = | |
4786 | {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', | |
4787 | 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0}; | |
4788 | ||
4789 | rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); | |
4790 | if (rc != ERROR_SUCCESS) | |
4791 | return ERROR_SUCCESS; | |
4792 | ||
4793 | rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package); | |
4794 | msiobj_release(&view->hdr); | |
4795 | ||
4796 | return rc; | |
4797 | } | |
4798 | ||
58bb3571 | 4799 | /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */ |
cf8e9e33 | 4800 | static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs) |
58bb3571 | 4801 | { |
99ad76c3 | 4802 | LPCWSTR *vector, *temp_vector; |
58bb3571 JH |
4803 | LPWSTR p, q; |
4804 | DWORD sep_len; | |
4805 | ||
4806 | static const WCHAR separator[] = {'[','~',']',0}; | |
4807 | ||
4808 | *numargs = 0; | |
4809 | sep_len = sizeof(separator) / sizeof(WCHAR) - 1; | |
4810 | ||
4811 | if (!args) | |
4812 | return NULL; | |
4813 | ||
4814 | vector = msi_alloc(sizeof(LPWSTR)); | |
4815 | if (!vector) | |
4816 | return NULL; | |
4817 | ||
4818 | p = args; | |
4819 | do | |
4820 | { | |
4821 | (*numargs)++; | |
4822 | vector[*numargs - 1] = p; | |
4823 | ||
4824 | if ((q = strstrW(p, separator))) | |
4825 | { | |
4826 | *q = '\0'; | |
4827 | ||
99ad76c3 LD |
4828 | temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR)); |
4829 | if (!temp_vector) | |
4830 | { | |
4831 | msi_free(vector); | |
58bb3571 | 4832 | return NULL; |
99ad76c3 LD |
4833 | } |
4834 | vector = temp_vector; | |
58bb3571 JH |
4835 | |
4836 | p = q + sep_len; | |
4837 | } | |
4838 | } while (q); | |
4839 | ||
4840 | return vector; | |
4841 | } | |
4842 | ||
58bb3571 JH |
4843 | static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param) |
4844 | { | |
5f3ac30b | 4845 | MSIPACKAGE *package = param; |
58bb3571 JH |
4846 | MSICOMPONENT *comp; |
4847 | SC_HANDLE scm, service = NULL; | |
4848 | LPCWSTR name, *vector = NULL; | |
4849 | LPWSTR args; | |
4850 | DWORD event, numargs; | |
4851 | UINT r = ERROR_FUNCTION_FAILED; | |
4852 | ||
eec9bbb1 | 4853 | comp = get_loaded_component(package, MSI_RecordGetString(rec, 6)); |
58bb3571 JH |
4854 | if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT) |
4855 | return ERROR_SUCCESS; | |
4856 | ||
4857 | name = MSI_RecordGetString(rec, 2); | |
4858 | event = MSI_RecordGetInteger(rec, 3); | |
4859 | args = strdupW(MSI_RecordGetString(rec, 4)); | |
4860 | ||
4861 | if (!(event & msidbServiceControlEventStart)) | |
4862 | return ERROR_SUCCESS; | |
4863 | ||
4864 | scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); | |
4865 | if (!scm) | |
4866 | { | |
4867 | ERR("Failed to open the service control manager\n"); | |
4868 | goto done; | |
4869 | } | |
4870 | ||
4871 | service = OpenServiceW(scm, name, SERVICE_START); | |
4872 | if (!service) | |
4873 | { | |
aab5e585 | 4874 | ERR("Failed to open service %s\n", debugstr_w(name)); |
58bb3571 JH |
4875 | goto done; |
4876 | } | |
4877 | ||
cf8e9e33 | 4878 | vector = msi_service_args_to_vector(args, &numargs); |
58bb3571 JH |
4879 | |
4880 | if (!StartServiceW(service, numargs, vector)) | |
4881 | { | |
aab5e585 | 4882 | ERR("Failed to start service %s\n", debugstr_w(name)); |
58bb3571 JH |
4883 | goto done; |
4884 | } | |
4885 | ||
4886 | r = ERROR_SUCCESS; | |
4887 | ||
4888 | done: | |
4889 | CloseServiceHandle(service); | |
4890 | CloseServiceHandle(scm); | |
4891 | ||
4892 | msi_free(args); | |
4893 | msi_free(vector); | |
4894 | return r; | |
4895 | } | |
4896 | ||
4897 | static UINT ACTION_StartServices( MSIPACKAGE *package ) | |
4898 | { | |
4899 | UINT rc; | |
4900 | MSIQUERY *view; | |
4901 | ||
4902 | static const WCHAR query[] = { | |
4903 | 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', | |
4904 | 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 }; | |
4905 | ||
4906 | rc = MSI_DatabaseOpenViewW(package->db, query, &view); | |
4907 | if (rc != ERROR_SUCCESS) | |
4908 | return ERROR_SUCCESS; | |
4909 | ||
4910 | rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package); | |
4911 | msiobj_release(&view->hdr); | |
4912 | ||
4913 | return rc; | |
4914 | } | |
4915 | ||
fb508ff8 JH |
4916 | static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service) |
4917 | { | |
4918 | DWORD i, needed, count; | |
4919 | ENUM_SERVICE_STATUSW *dependencies; | |
4920 | SERVICE_STATUS ss; | |
4921 | SC_HANDLE depserv; | |
4922 | ||
4923 | if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL, | |
4924 | 0, &needed, &count)) | |
4925 | return TRUE; | |
4926 | ||
4927 | if (GetLastError() != ERROR_MORE_DATA) | |
4928 | return FALSE; | |
4929 | ||
4930 | dependencies = msi_alloc(needed); | |
4931 | if (!dependencies) | |
4932 | return FALSE; | |
4933 | ||
4934 | if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies, | |
4935 | needed, &needed, &count)) | |
4936 | goto error; | |
4937 | ||
4938 | for (i = 0; i < count; i++) | |
4939 | { | |
4940 | depserv = OpenServiceW(scm, dependencies[i].lpServiceName, | |
4941 | SERVICE_STOP | SERVICE_QUERY_STATUS); | |
4942 | if (!depserv) | |
4943 | goto error; | |
4944 | ||
4945 | if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss)) | |
4946 | goto error; | |
4947 | } | |
4948 | ||
4949 | return TRUE; | |
4950 | ||
4951 | error: | |
4952 | msi_free(dependencies); | |
4953 | return FALSE; | |
4954 | } | |
4955 | ||
4956 | static UINT ITERATE_StopService(MSIRECORD *rec, LPVOID param) | |
4957 | { | |
5f3ac30b | 4958 | MSIPACKAGE *package = param; |
fb508ff8 JH |
4959 | MSICOMPONENT *comp; |
4960 | SERVICE_STATUS status; | |
4961 | SERVICE_STATUS_PROCESS ssp; | |
4962 | SC_HANDLE scm = NULL, service = NULL; | |
4963 | LPWSTR name, args; | |
4964 | DWORD event, needed; | |
4965 | ||
4966 | event = MSI_RecordGetInteger(rec, 3); | |
4967 | if (!(event & msidbServiceControlEventStop)) | |
4968 | return ERROR_SUCCESS; | |
4969 | ||
4970 | comp = get_loaded_component(package, MSI_RecordGetString(rec, 6)); | |
4971 | if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT) | |
4972 | return ERROR_SUCCESS; | |
4973 | ||
4974 | deformat_string(package, MSI_RecordGetString(rec, 2), &name); | |
4975 | deformat_string(package, MSI_RecordGetString(rec, 4), &args); | |
4976 | args = strdupW(MSI_RecordGetString(rec, 4)); | |
4977 | ||
4978 | scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); | |
4979 | if (!scm) | |
4980 | { | |
4981 | WARN("Failed to open the SCM: %d\n", GetLastError()); | |
4982 | goto done; | |
4983 | } | |
4984 | ||
4985 | service = OpenServiceW(scm, name, | |
4986 | SERVICE_STOP | | |
4987 | SERVICE_QUERY_STATUS | | |
4988 | SERVICE_ENUMERATE_DEPENDENTS); | |
4989 | if (!service) | |
4990 | { | |
4991 | WARN("Failed to open service (%s): %d\n", | |
4992 | debugstr_w(name), GetLastError()); | |
4993 | goto done; | |
4994 | } | |
4995 | ||
4996 | if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, | |
4997 | sizeof(SERVICE_STATUS_PROCESS), &needed)) | |
4998 | { | |
4999 | WARN("Failed to query service status (%s): %d\n", | |
5000 | debugstr_w(name), GetLastError()); | |
5001 | goto done; | |
5002 | } | |
5003 | ||
5004 | if (ssp.dwCurrentState == SERVICE_STOPPED) | |
5005 | goto done; | |
5006 | ||
5007 | stop_service_dependents(scm, service); | |
5008 | ||
ddfefc03 | 5009 | if (!ControlService(service, SERVICE_CONTROL_STOP, &status)) |
fb508ff8 JH |
5010 | WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError()); |
5011 | ||
5012 | done: | |
5013 | CloseServiceHandle(service); | |
5014 | CloseServiceHandle(scm); | |
5015 | msi_free(name); | |
5016 | msi_free(args); | |
5017 | ||
5018 | return ERROR_SUCCESS; | |
5019 | } | |
5020 | ||
5021 | static UINT ACTION_StopServices( MSIPACKAGE *package ) | |
5022 | { | |
5023 | UINT rc; | |
5024 | MSIQUERY *view; | |
5025 | ||
5026 | static const WCHAR query[] = { | |
5027 | 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', | |
5028 | 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 }; | |
5029 | ||
5030 | rc = MSI_DatabaseOpenViewW(package->db, query, &view); | |
5031 | if (rc != ERROR_SUCCESS) | |
5032 | return ERROR_SUCCESS; | |
5033 | ||
5034 | rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package); | |
5035 | msiobj_release(&view->hdr); | |
5036 | ||
5037 | return rc; | |
5038 | } | |
5039 | ||
d3bec325 JH |
5040 | static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename ) |
5041 | { | |
5042 | MSIFILE *file; | |
5043 | ||
5044 | LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry) | |
5045 | { | |
5046 | if (!lstrcmpW(file->File, filename)) | |
5047 | return file; | |
5048 | } | |
5049 | ||
5050 | return NULL; | |
5051 | } | |
5052 | ||
5053 | static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param ) | |
5054 | { | |
5f3ac30b | 5055 | MSIPACKAGE *package = param; |
d3bec325 JH |
5056 | LPWSTR driver, driver_path, ptr; |
5057 | WCHAR outpath[MAX_PATH]; | |
5058 | MSIFILE *driver_file, *setup_file; | |
5059 | LPCWSTR desc; | |
5060 | DWORD len, usage; | |
5061 | UINT r = ERROR_SUCCESS; | |
5062 | ||
5063 | static const WCHAR driver_fmt[] = { | |
5064 | 'D','r','i','v','e','r','=','%','s',0}; | |
5065 | static const WCHAR setup_fmt[] = { | |
5066 | 'S','e','t','u','p','=','%','s',0}; | |
5067 | static const WCHAR usage_fmt[] = { | |
5068 | 'F','i','l','e','U','s','a','g','e','=','1',0}; | |
5069 | ||
5070 | desc = MSI_RecordGetString(rec, 3); | |
5071 | ||
5072 | driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4)); | |
5073 | setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5)); | |
5074 | ||
5075 | if (!driver_file || !setup_file) | |
5076 | { | |
5077 | ERR("ODBC Driver entry not found!\n"); | |
5078 | return ERROR_FUNCTION_FAILED; | |
5079 | } | |
5080 | ||
5081 | len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) + | |
5082 | lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + | |
5083 | lstrlenW(usage_fmt) + 1; | |
5084 | driver = msi_alloc(len * sizeof(WCHAR)); | |
5085 | if (!driver) | |
5086 | return ERROR_OUTOFMEMORY; | |
5087 | ||
5088 | ptr = driver; | |
5089 | lstrcpyW(ptr, desc); | |
5090 | ptr += lstrlenW(ptr) + 1; | |
5091 | ||
5092 | sprintfW(ptr, driver_fmt, driver_file->FileName); | |
5093 | ptr += lstrlenW(ptr) + 1; | |
5094 | ||
5095 | sprintfW(ptr, setup_fmt, setup_file->FileName); | |
5096 | ptr += lstrlenW(ptr) + 1; | |
5097 | ||
5098 | lstrcpyW(ptr, usage_fmt); | |
5099 | ptr += lstrlenW(ptr) + 1; | |
5100 | *ptr = '\0'; | |
5101 | ||
5102 | driver_path = strdupW(driver_file->TargetPath); | |
5103 | ptr = strrchrW(driver_path, '\\'); | |
5104 | if (ptr) *ptr = '\0'; | |
5105 | ||
5106 | if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH, | |
5107 | NULL, ODBC_INSTALL_COMPLETE, &usage)) | |
5108 | { | |
5109 | ERR("Failed to install SQL driver!\n"); | |
5110 | r = ERROR_FUNCTION_FAILED; | |
5111 | } | |
5112 | ||
5113 | msi_free(driver); | |
5114 | msi_free(driver_path); | |
5115 | ||
5116 | return r; | |
5117 | } | |
5118 | ||
33c025b7 HL |
5119 | static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param ) |
5120 | { | |
5f3ac30b | 5121 | MSIPACKAGE *package = param; |
33c025b7 HL |
5122 | LPWSTR translator, translator_path, ptr; |
5123 | WCHAR outpath[MAX_PATH]; | |
5124 | MSIFILE *translator_file, *setup_file; | |
5125 | LPCWSTR desc; | |
5126 | DWORD len, usage; | |
5127 | UINT r = ERROR_SUCCESS; | |
5128 | ||
5129 | static const WCHAR translator_fmt[] = { | |
5130 | 'T','r','a','n','s','l','a','t','o','r','=','%','s',0}; | |
5131 | static const WCHAR setup_fmt[] = { | |
5132 | 'S','e','t','u','p','=','%','s',0}; | |
5133 | ||
5134 | desc = MSI_RecordGetString(rec, 3); | |
5135 | ||
5136 | translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4)); | |
5137 | setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5)); | |
5138 | ||
5139 | if (!translator_file || !setup_file) | |
5140 | { | |
5141 | ERR("ODBC Translator entry not found!\n"); | |
5142 | return ERROR_FUNCTION_FAILED; | |
5143 | } | |
5144 | ||
5145 | len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + | |
5146 | lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + 1; | |
5147 | translator = msi_alloc(len * sizeof(WCHAR)); | |
5148 | if (!translator) | |
5149 | return ERROR_OUTOFMEMORY; | |
5150 | ||
5151 | ptr = translator; | |
5152 | lstrcpyW(ptr, desc); | |
5153 | ptr += lstrlenW(ptr) + 1; | |
5154 | ||
5155 | sprintfW(ptr, translator_fmt, translator_file->FileName); | |
5156 | ptr += lstrlenW(ptr) + 1; | |
5157 | ||
5158 | sprintfW(ptr, setup_fmt, setup_file->FileName); | |
5159 | ptr += lstrlenW(ptr) + 1; | |
5160 | *ptr = '\0'; | |
5161 | ||
5162 | translator_path = strdupW(translator_file->TargetPath); | |
5163 | ptr = strrchrW(translator_path, '\\'); | |
5164 | if (ptr) *ptr = '\0'; | |
5165 | ||
5166 | if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH, | |
5167 | NULL, ODBC_INSTALL_COMPLETE, &usage)) | |
5168 | { | |
5169 | ERR("Failed to install SQL translator!\n"); | |
5170 | r = ERROR_FUNCTION_FAILED; | |
5171 | } | |
5172 | ||
5173 | msi_free(translator); | |
5174 | msi_free(translator_path); | |
5175 | ||
5176 | return r; | |
5177 | } | |
5178 | ||
1d19c2b7 HL |
5179 | static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param ) |
5180 | { | |
5181 | LPWSTR attrs; | |
5182 | LPCWSTR desc, driver; | |
5183 | WORD request = ODBC_ADD_SYS_DSN; | |
5184 | INT registration; | |
5185 | DWORD len; | |
5186 | UINT r = ERROR_SUCCESS; | |
5187 | ||
5188 | static const WCHAR attrs_fmt[] = { | |
5189 | 'D','S','N','=','%','s',0 }; | |
5190 | ||
5191 | desc = MSI_RecordGetString(rec, 3); | |
5192 | driver = MSI_RecordGetString(rec, 4); | |
5193 | registration = MSI_RecordGetInteger(rec, 5); | |
5194 | ||
5195 | if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN; | |
5196 | else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN; | |
5197 | ||
5198 | len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 1 + 1; | |
5199 | attrs = msi_alloc(len * sizeof(WCHAR)); | |
5200 | if (!attrs) | |
5201 | return ERROR_OUTOFMEMORY; | |
5202 | ||
5203 | sprintfW(attrs, attrs_fmt, desc); | |
5204 | attrs[len - 1] = '\0'; | |
5205 | ||
5206 | if (!SQLConfigDataSourceW(NULL, request, driver, attrs)) | |
5207 | { | |
5208 | ERR("Failed to install SQL data source!\n"); | |
5209 | r = ERROR_FUNCTION_FAILED; | |
5210 | } | |
5211 | ||
5212 | msi_free(attrs); | |
5213 | ||
5214 | return r; | |
5215 | } | |
5216 | ||
d3bec325 JH |
5217 | static UINT ACTION_InstallODBC( MSIPACKAGE *package ) |
5218 | { | |
5219 | UINT rc; | |
5220 | MSIQUERY *view; | |
5221 | ||
33c025b7 | 5222 | static const WCHAR driver_query[] = { |
d3bec325 JH |
5223 | 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', |
5224 | 'O','D','B','C','D','r','i','v','e','r',0 }; | |
5225 | ||
33c025b7 HL |
5226 | static const WCHAR translator_query[] = { |
5227 | 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', | |
5228 | 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 }; | |
5229 | ||
1d19c2b7 HL |
5230 | static const WCHAR source_query[] = { |
5231 | 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', | |
5232 | 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 }; | |
5233 | ||
33c025b7 | 5234 | rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view); |
d3bec325 JH |
5235 | if (rc != ERROR_SUCCESS) |
5236 | return ERROR_SUCCESS; | |
5237 | ||
5238 | rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package); | |
5239 | msiobj_release(&view->hdr); | |
5240 | ||
33c025b7 HL |
5241 | rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view); |
5242 | if (rc != ERROR_SUCCESS) | |
5243 | return ERROR_SUCCESS; | |
5244 | ||
5245 | rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package); | |
5246 | msiobj_release(&view->hdr); | |
5247 | ||
1d19c2b7 HL |
5248 | rc = MSI_DatabaseOpenViewW(package->db, source_query, &view); |
5249 | if (rc != ERROR_SUCCESS) | |
5250 | return ERROR_SUCCESS; | |
5251 | ||
5252 | rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package); | |
5253 | msiobj_release(&view->hdr); | |
5254 | ||
d3bec325 JH |
5255 | return rc; |
5256 | } | |
5257 | ||
5b8641a5 JH |
5258 | #define ENV_ACT_SETALWAYS 0x1 |
5259 | #define ENV_ACT_SETABSENT 0x2 | |
5260 | #define ENV_ACT_REMOVE 0x4 | |
881f5925 | 5261 | #define ENV_ACT_REMOVEMATCH 0x8 |
5b8641a5 JH |
5262 | |
5263 | #define ENV_MOD_MACHINE 0x20000000 | |
5264 | #define ENV_MOD_APPEND 0x40000000 | |
5265 | #define ENV_MOD_PREFIX 0x80000000 | |
881f5925 JH |
5266 | #define ENV_MOD_MASK 0xC0000000 |
5267 | ||
5268 | #define check_flag_combo(x, y) ((x) & ~(y)) == (y) | |
5269 | ||
d5b620ea | 5270 | static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags ) |
881f5925 JH |
5271 | { |
5272 | LPCWSTR cptr = *name; | |
d5b620ea | 5273 | LPCWSTR ptr = *value; |
881f5925 JH |
5274 | |
5275 | static const WCHAR prefix[] = {'[','~',']',0}; | |
d5b620ea | 5276 | static const int prefix_len = 3; |
881f5925 JH |
5277 | |
5278 | *flags = 0; | |
6076485f | 5279 | while (*cptr) |
881f5925 | 5280 | { |
6076485f | 5281 | if (*cptr == '=') |
881f5925 | 5282 | *flags |= ENV_ACT_SETALWAYS; |
6076485f | 5283 | else if (*cptr == '+') |
881f5925 | 5284 | *flags |= ENV_ACT_SETABSENT; |
6076485f | 5285 | else if (*cptr == '-') |
881f5925 | 5286 | *flags |= ENV_ACT_REMOVE; |
6076485f | 5287 | else if (*cptr == '!') |
881f5925 | 5288 | *flags |= ENV_ACT_REMOVEMATCH; |
6076485f | 5289 | else if (*cptr == '*') |
881f5925 | 5290 | *flags |= ENV_MOD_MACHINE; |
6076485f | 5291 | else |
881f5925 | 5292 | break; |
881f5925 JH |
5293 | |
5294 | cptr++; | |
5295 | (*name)++; | |
5296 | } | |
5297 | ||
5298 | if (!*cptr) | |
5299 | { | |
5300 | ERR("Missing environment variable\n"); | |
5301 | return ERROR_FUNCTION_FAILED; | |
5302 | } | |
5303 | ||
d5b620ea | 5304 | if (!strncmpW(ptr, prefix, prefix_len)) |
881f5925 | 5305 | { |
d5b620ea | 5306 | *flags |= ENV_MOD_APPEND; |
881f5925 JH |
5307 | *value += lstrlenW(prefix); |
5308 | } | |
d5b620ea | 5309 | else if (lstrlenW(*value) >= prefix_len) |
881f5925 | 5310 | { |
d5b620ea | 5311 | ptr += lstrlenW(ptr) - prefix_len; |
881f5925 JH |
5312 | if (!lstrcmpW(ptr, prefix)) |
5313 | { | |
d5b620ea MZ |
5314 | *flags |= ENV_MOD_PREFIX; |
5315 | /* the "[~]" will be removed by deformat_string */; | |
881f5925 JH |
5316 | } |
5317 | } | |
5318 | ||
659768e2 | 5319 | if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) || |
881f5925 JH |
5320 | check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) || |
5321 | check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) || | |
5322 | check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK)) | |
5323 | { | |
5324 | ERR("Invalid flags: %08x\n", *flags); | |
5325 | return ERROR_FUNCTION_FAILED; | |
5326 | } | |
5327 | ||
659768e2 HL |
5328 | if (!*flags) |
5329 | *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE; | |
5330 | ||
881f5925 JH |
5331 | return ERROR_SUCCESS; |
5332 | } | |
5b8641a5 JH |
5333 | |
5334 | static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param ) | |
5335 | { | |
881f5925 | 5336 | MSIPACKAGE *package = param; |
68975938 | 5337 | LPCWSTR name, value; |
881f5925 | 5338 | LPWSTR data = NULL, newval = NULL; |
d5b620ea | 5339 | LPWSTR deformatted = NULL, ptr; |
5b8641a5 JH |
5340 | DWORD flags, type, size; |
5341 | LONG res; | |
9d71238a JH |
5342 | HKEY env = NULL, root; |
5343 | LPCWSTR environment; | |
5b8641a5 | 5344 | |
9d71238a JH |
5345 | static const WCHAR user_env[] = |
5346 | {'E','n','v','i','r','o','n','m','e','n','t',0}; | |
5347 | static const WCHAR machine_env[] = | |
5b8641a5 JH |
5348 | {'S','y','s','t','e','m','\\', |
5349 | 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', | |
5350 | 'C','o','n','t','r','o','l','\\', | |
5351 | 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\', | |
5352 | 'E','n','v','i','r','o','n','m','e','n','t',0}; | |
5353 | static const WCHAR semicolon[] = {';',0}; | |
5354 | ||
881f5925 JH |
5355 | name = MSI_RecordGetString(rec, 2); |
5356 | value = MSI_RecordGetString(rec, 3); | |
881f5925 | 5357 | |
659768e2 HL |
5358 | TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value)); |
5359 | ||
d5b620ea | 5360 | res = env_set_flags(&name, &value, &flags); |
881f5925 JH |
5361 | if (res != ERROR_SUCCESS) |
5362 | goto done; | |
5b8641a5 | 5363 | |
d5b620ea MZ |
5364 | deformat_string(package, value, &deformatted); |
5365 | if (!deformatted) | |
5366 | { | |
5367 | res = ERROR_OUTOFMEMORY; | |
5368 | goto done; | |
5369 | } | |
5370 | ||
881f5925 | 5371 | value = deformatted; |
5b8641a5 JH |
5372 | |
5373 | if (flags & ENV_MOD_MACHINE) | |
9d71238a JH |
5374 | { |
5375 | environment = machine_env; | |
5b8641a5 | 5376 | root = HKEY_LOCAL_MACHINE; |
9d71238a JH |
5377 | } |
5378 | else | |
5379 | { | |
5380 | environment = user_env; | |
5381 | root = HKEY_CURRENT_USER; | |
5382 | } | |
5b8641a5 | 5383 | |
9d71238a JH |
5384 | res = RegCreateKeyExW(root, environment, 0, NULL, 0, |
5385 | KEY_ALL_ACCESS, NULL, &env, NULL); | |
5b8641a5 | 5386 | if (res != ERROR_SUCCESS) |
881f5925 | 5387 | goto done; |
5b8641a5 JH |
5388 | |
5389 | if (flags & ENV_ACT_REMOVE) | |
881f5925 | 5390 | FIXME("Not removing environment variable on uninstall!\n"); |
5b8641a5 JH |
5391 | |
5392 | size = 0; | |
881f5925 JH |
5393 | res = RegQueryValueExW(env, name, NULL, &type, NULL, &size); |
5394 | if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) || | |
31c461ea | 5395 | (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ)) |
881f5925 | 5396 | goto done; |
5b8641a5 JH |
5397 | |
5398 | if (res != ERROR_FILE_NOT_FOUND) | |
5399 | { | |
5400 | if (flags & ENV_ACT_SETABSENT) | |
5401 | { | |
5402 | res = ERROR_SUCCESS; | |
5403 | goto done; | |
5404 | } | |
5405 | ||
881f5925 JH |
5406 | data = msi_alloc(size); |
5407 | if (!data) | |
5b8641a5 | 5408 | { |
881f5925 JH |
5409 | RegCloseKey(env); |
5410 | return ERROR_OUTOFMEMORY; | |
5b8641a5 JH |
5411 | } |
5412 | ||
881f5925 JH |
5413 | res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size); |
5414 | if (res != ERROR_SUCCESS) | |
5415 | goto done; | |
5416 | ||
5417 | if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value))) | |
5b8641a5 | 5418 | { |
881f5925 JH |
5419 | res = RegDeleteKeyW(env, name); |
5420 | goto done; | |
5b8641a5 JH |
5421 | } |
5422 | ||
881f5925 JH |
5423 | size = (lstrlenW(value) + 1 + size) * sizeof(WCHAR); |
5424 | newval = msi_alloc(size); | |
5425 | ptr = newval; | |
5426 | if (!newval) | |
5427 | { | |
5428 | res = ERROR_OUTOFMEMORY; | |
5b8641a5 | 5429 | goto done; |
881f5925 | 5430 | } |
5b8641a5 | 5431 | |
881f5925 JH |
5432 | if (!(flags & ENV_MOD_MASK)) |
5433 | lstrcpyW(newval, value); | |
5434 | else | |
5b8641a5 | 5435 | { |
881f5925 JH |
5436 | if (flags & ENV_MOD_PREFIX) |
5437 | { | |
5438 | lstrcpyW(newval, value); | |
5439 | lstrcatW(newval, semicolon); | |
5440 | ptr = newval + lstrlenW(value) + 1; | |
5441 | } | |
5442 | ||
5443 | lstrcpyW(ptr, data); | |
5444 | ||
5445 | if (flags & ENV_MOD_APPEND) | |
5446 | { | |
5447 | lstrcatW(newval, semicolon); | |
5448 | lstrcatW(newval, value); | |
5449 | } | |
5b8641a5 JH |
5450 | } |
5451 | } | |
5452 | else | |
5453 | { | |
5454 | size = (lstrlenW(value) + 1) * sizeof(WCHAR); | |
881f5925 JH |
5455 | newval = msi_alloc(size); |
5456 | if (!newval) | |
5b8641a5 JH |
5457 | { |
5458 | res = ERROR_OUTOFMEMORY; | |
5459 | goto done; | |
5460 | } | |
5461 | ||
881f5925 | 5462 | lstrcpyW(newval, value); |
5b8641a5 JH |
5463 | } |
5464 | ||
881f5925 JH |
5465 | TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval)); |
5466 | res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size); | |
5b8641a5 JH |
5467 | |
5468 | done: | |
0e4ccb82 | 5469 | if (env) RegCloseKey(env); |
881f5925 JH |
5470 | msi_free(deformatted); |
5471 | msi_free(data); | |
5472 | msi_free(newval); | |
5b8641a5 JH |
5473 | return res; |
5474 | } | |
5475 | ||
5476 | static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package ) | |
5477 | { | |
5478 | UINT rc; | |
5479 | MSIQUERY * view; | |
5480 | static const WCHAR ExecSeqQuery[] = | |
5481 | {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', | |
5482 | '`','E','n','v','i','r','o','n','m','e','n','t','`',0}; | |
5483 | rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); | |
5484 | if (rc != ERROR_SUCCESS) | |
5485 | return ERROR_SUCCESS; | |
5486 | ||
5487 | rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package); | |
5488 | msiobj_release(&view->hdr); | |
5489 | ||
5490 | return rc; | |
5491 | } | |
5492 | ||
c3df74e2 JH |
5493 | #define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0)))) |
5494 | ||
5495 | typedef struct | |
5496 | { | |
5497 | struct list entry; | |
5498 | LPWSTR sourcename; | |
5499 | LPWSTR destname; | |
5500 | LPWSTR source; | |
5501 | LPWSTR dest; | |
5502 | } FILE_LIST; | |
5503 | ||
5504 | static BOOL msi_move_file(LPCWSTR source, LPCWSTR dest, int options) | |
5505 | { | |
5506 | BOOL ret; | |
5507 | ||
5508 | if (GetFileAttributesW(source) == FILE_ATTRIBUTE_DIRECTORY || | |
5509 | GetFileAttributesW(dest) == FILE_ATTRIBUTE_DIRECTORY) | |
5510 | { | |
5511 | WARN("Source or dest is directory, not moving\n"); | |
5512 | return FALSE; | |
5513 | } | |
5514 | ||
5515 | if (options == msidbMoveFileOptionsMove) | |
5516 | { | |
5517 | TRACE("moving %s -> %s\n", debugstr_w(source), debugstr_w(dest)); | |
5518 | ret = MoveFileExW(source, dest, MOVEFILE_REPLACE_EXISTING); | |
5519 | if (!ret) | |
5520 | { | |
5521 | WARN("MoveFile failed: %d\n", GetLastError()); | |
5522 | return FALSE; | |
5523 | } | |
5524 | } | |
5525 | else | |
5526 | { | |
5527 | TRACE("copying %s -> %s\n", debugstr_w(source), debugstr_w(dest)); | |
5528 | ret = CopyFileW(source, dest, FALSE); | |
5529 | if (!ret) | |
5530 | { | |
5531 | WARN("CopyFile failed: %d\n", GetLastError()); | |
5532 | return FALSE; | |
5533 | } | |
5534 | } | |
5535 | ||
5536 | return TRUE; | |
5537 | } | |
5538 | ||
5539 | static LPWSTR wildcard_to_file(LPWSTR wildcard, LPWSTR filename) | |
5540 | { | |
5541 | LPWSTR path, ptr; | |
5542 | DWORD dirlen, pathlen; | |
5543 | ||
5544 | ptr = strrchrW(wildcard, '\\'); | |
5545 | dirlen = ptr - wildcard + 1; | |
5546 | ||
5547 | pathlen = dirlen + lstrlenW(filename) + 1; | |
5548 | path = msi_alloc(pathlen * sizeof(WCHAR)); | |
5549 | ||
5550 | lstrcpynW(path, wildcard, dirlen + 1); | |
5551 | lstrcatW(path, filename); | |
5552 | ||
5553 | return path; | |
5554 | } | |
5555 | ||
5556 | static void free_file_entry(FILE_LIST *file) | |
5557 | { | |
5558 | msi_free(file->source); | |
5559 | msi_free(file->dest); | |
5560 | msi_free(file); | |
5561 | } | |
5562 | ||
5563 | static void free_list(FILE_LIST *list) | |
5564 | { | |
5565 | while (!list_empty(&list->entry)) | |
5566 | { | |
5567 | FILE_LIST *file = LIST_ENTRY(list_head(&list->entry), FILE_LIST, entry); | |
5568 | ||
5569 | list_remove(&file->entry); | |
5570 | free_file_entry(file); | |
5571 | } | |
5572 | } | |
5573 | ||
5574 | static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest) | |
5575 | { | |
5576 | FILE_LIST *new, *file; | |
5577 | LPWSTR ptr, filename; | |
5578 | DWORD size; | |
5579 | ||
5580 | new = msi_alloc_zero(sizeof(FILE_LIST)); | |
5581 | if (!new) | |
5582 | return FALSE; | |
5583 | ||
5584 | new->source = strdupW(source); | |
5585 | ptr = strrchrW(dest, '\\') + 1; | |
5586 | filename = strrchrW(new->source, '\\') + 1; | |
5587 | ||
5588 | new->sourcename = filename; | |
5589 | ||
5590 | if (*ptr) | |
5591 | new->destname = ptr; | |
5592 | else | |
5593 | new->destname = new->sourcename; | |
5594 | ||
5595 | size = (ptr - dest) + lstrlenW(filename) + 1; | |
5596 | new->dest = msi_alloc(size * sizeof(WCHAR)); | |
5597 | if (!new->dest) | |
5598 | { | |
5599 | free_file_entry(new); | |
5600 | return FALSE; | |
5601 | } | |
5602 | ||
5603 | lstrcpynW(new->dest, dest, ptr - dest + 1); | |
5604 | lstrcatW(new->dest, filename); | |
5605 | ||
5606 | if (list_empty(&files->entry)) | |
5607 | { | |
5608 | list_add_head(&files->entry, &new->entry); | |
5609 | return TRUE; | |
5610 | } | |
5611 | ||
5612 | LIST_FOR_EACH_ENTRY(file, &files->entry, FILE_LIST, entry) | |
5613 | { | |
5614 | if (lstrcmpW(source, file->source) < 0) | |
5615 | { | |
5616 | list_add_before(&file->entry, &new->entry); | |
5617 | return TRUE; | |
5618 | } | |
5619 | } | |
5620 | ||
5621 | list_add_after(&file->entry, &new->entry); | |
5622 | return TRUE; | |
5623 | } | |
5624 | ||
4439e0b5 | 5625 | static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options) |
c3df74e2 JH |
5626 | { |
5627 | WIN32_FIND_DATAW wfd; | |
5628 | HANDLE hfile; | |
5629 | LPWSTR path; | |
5630 | BOOL res; | |
5631 | FILE_LIST files, *file; | |
5632 | DWORD size; | |
5633 | ||
5634 | hfile = FindFirstFileW(source, &wfd); | |
5635 | if (hfile == INVALID_HANDLE_VALUE) return FALSE; | |
5636 | ||
5637 | list_init(&files.entry); | |
5638 | ||
5639 | for (res = TRUE; res; res = FindNextFileW(hfile, &wfd)) | |
5640 | { | |
5641 | if (is_dot_dir(wfd.cFileName)) continue; | |
5642 | ||
5643 | path = wildcard_to_file(source, wfd.cFileName); | |
5644 | if (!path) | |
5645 | { | |
fa8476e7 JH |
5646 | res = FALSE; |
5647 | goto done; | |
c3df74e2 JH |
5648 | } |
5649 | ||
5650 | add_wildcard(&files, path, dest); | |
5651 | msi_free(path); | |
5652 | } | |
5653 | ||
a7d02a1f JH |
5654 | /* no files match the wildcard */ |
5655 | if (list_empty(&files.entry)) | |
5656 | goto done; | |
5657 | ||
c3df74e2 JH |
5658 | /* only the first wildcard match gets renamed to dest */ |
5659 | file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry); | |
5660 | size = (strrchrW(file->dest, '\\') - file->dest) + lstrlenW(file->destname) + 2; | |
5661 | file->dest = msi_realloc(file->dest, size * sizeof(WCHAR)); | |
5662 | if (!file->dest) | |
5663 | { | |
fa8476e7 JH |
5664 | res = FALSE; |
5665 | goto done; | |
c3df74e2 JH |
5666 | } |
5667 | ||
5668 | lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname); | |
5669 | ||
5670 | while (!list_empty(&files.entry)) | |
5671 | { | |
5672 | file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry); | |
5673 | ||
5f3ac30b | 5674 | msi_move_file(file->source, file->dest, options); |
c3df74e2 JH |
5675 | |
5676 | list_remove(&file->entry); | |
5677 | free_file_entry(file); | |
5678 | } | |
5679 | ||
fa8476e7 JH |
5680 | res = TRUE; |
5681 | ||
5682 | done: | |
5683 | free_list(&files); | |
5684 | FindClose(hfile); | |
5685 | return res; | |
c3df74e2 JH |
5686 | } |
5687 | ||
5688 | static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param ) | |
5689 | { | |
5690 | MSIPACKAGE *package = param; | |
5691 | MSICOMPONENT *comp; | |
ef1b0cac RS |
5692 | LPCWSTR sourcename; |
5693 | LPWSTR destname = NULL; | |
c3df74e2 JH |
5694 | LPWSTR sourcedir = NULL, destdir = NULL; |
5695 | LPWSTR source = NULL, dest = NULL; | |
5696 | int options; | |
5697 | DWORD size; | |
5698 | BOOL ret, wildcards; | |
5699 | ||
5700 | static const WCHAR backslash[] = {'\\',0}; | |
5701 | ||
5702 | comp = get_loaded_component(package, MSI_RecordGetString(rec, 2)); | |
5703 | if (!comp || !comp->Enabled || | |
5704 | !(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE))) | |
5705 | { | |
5706 | TRACE("Component not set for install, not moving file\n"); | |
5707 | return ERROR_SUCCESS; | |
5708 | } | |
5709 | ||
5710 | sourcename = MSI_RecordGetString(rec, 3); | |
c3df74e2 JH |
5711 | options = MSI_RecordGetInteger(rec, 7); |
5712 | ||
5713 | sourcedir = msi_dup_property(package, MSI_RecordGetString(rec, 5)); | |
5714 | if (!sourcedir) | |
5715 | goto done; | |
5716 | ||
5717 | destdir = msi_dup_property(package, MSI_RecordGetString(rec, 6)); | |
5718 | if (!destdir) | |
5719 | goto done; | |
5720 | ||
5721 | if (!sourcename) | |
5722 | { | |
5723 | if (GetFileAttributesW(sourcedir) == INVALID_FILE_ATTRIBUTES) | |
5724 | goto done; | |
5725 | ||
5726 | source = strdupW(sourcedir); | |
5727 | if (!source) | |
5728 | goto done; | |
5729 | } | |
5730 | else | |
5731 | { | |
5732 | size = lstrlenW(sourcedir) + lstrlenW(sourcename) + 2; | |
5733 | source = msi_alloc(size * sizeof(WCHAR)); | |
5734 | if (!source) | |
5735 | goto done; | |
5736 | ||
5737 | lstrcpyW(source, sourcedir); | |
5738 | if (source[lstrlenW(source) - 1] != '\\') | |
5739 | lstrcatW(source, backslash); | |
5740 | lstrcatW(source, sourcename); | |
5741 | } | |
5742 | ||
5743 | wildcards = strchrW(source, '*') || strchrW(source, '?'); | |
5744 | ||
ef1b0cac | 5745 | if (MSI_RecordIsNull(rec, 4)) |
c3df74e2 | 5746 | { |
ef1b0cac RS |
5747 | if (!wildcards) |
5748 | { | |
5749 | destname = strdupW(sourcename); | |
5750 | if (!destname) | |
5751 | goto done; | |
5752 | } | |
5753 | } | |
5754 | else | |
5755 | { | |
5756 | destname = strdupW(MSI_RecordGetString(rec, 4)); | |
5757 | if (destname) | |
5758 | reduce_to_longfilename(destname); | |
c3df74e2 JH |
5759 | } |
5760 | ||
5761 | size = 0; | |
5762 | if (destname) | |
5763 | size = lstrlenW(destname); | |
5764 | ||
5765 | size += lstrlenW(destdir) + 2; | |
5766 | dest = msi_alloc(size * sizeof(WCHAR)); | |
5767 | if (!dest) | |
5768 | goto done; | |
5769 | ||
5770 | lstrcpyW(dest, destdir); | |
5771 | if (dest[lstrlenW(dest) - 1] != '\\') | |
5772 | lstrcatW(dest, backslash); | |
5773 | ||
5774 | if (destname) | |
5775 | lstrcatW(dest, destname); | |
5776 | ||
5777 | if (GetFileAttributesW(destdir) == INVALID_FILE_ATTRIBUTES) | |
5778 | { | |
5779 | ret = CreateDirectoryW(destdir, NULL); | |
5780 | if (!ret) | |
5781 | { | |
5782 | WARN("CreateDirectory failed: %d\n", GetLastError()); | |
5783 | return ERROR_SUCCESS; | |
5784 | } | |
5785 | } | |
5786 | ||
5787 | if (!wildcards) | |
5788 | msi_move_file(source, dest, options); | |
5789 | else | |
5790 | move_files_wildcard(source, dest, options); | |
5791 | ||
5792 | done: | |
5793 | msi_free(sourcedir); | |
5794 | msi_free(destdir); | |
ef1b0cac | 5795 | msi_free(destname); |
c3df74e2 JH |
5796 | msi_free(source); |
5797 | msi_free(dest); | |
5798 | ||
5799 | return ERROR_SUCCESS; | |
5800 | } | |
5801 | ||
5802 | static UINT ACTION_MoveFiles( MSIPACKAGE *package ) | |
5803 | { | |
5804 | UINT rc; | |
5805 | MSIQUERY *view; | |
5806 | ||
5807 | static const WCHAR ExecSeqQuery[] = | |
5808 | {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', | |
5809 | '`','M','o','v','e','F','i','l','e','`',0}; | |
5810 | ||
5811 | rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); | |
5812 | if (rc != ERROR_SUCCESS) | |
5813 | return ERROR_SUCCESS; | |
5814 | ||
5815 | rc = MSI_IterateRecords(view, NULL, ITERATE_MoveFiles, package); | |
5816 | msiobj_release(&view->hdr); | |
5817 | ||
5818 | return rc; | |
5819 | } | |
5820 | ||
74239fcd JH |
5821 | typedef struct tagMSIASSEMBLY |
5822 | { | |
5823 | struct list entry; | |
5824 | MSICOMPONENT *component; | |
5825 | MSIFEATURE *feature; | |
5826 | MSIFILE *file; | |
5827 | LPWSTR manifest; | |
5828 | LPWSTR application; | |
5829 | DWORD attributes; | |
5830 | BOOL installed; | |
5831 | } MSIASSEMBLY; | |
5832 | ||
bfe07d1d JH |
5833 | static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache, |
5834 | DWORD dwReserved); | |
5835 | static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion, | |
5836 | LPVOID pvReserved, HMODULE *phModDll); | |
5837 | ||
5838 | static BOOL init_functionpointers(void) | |
5839 | { | |
5840 | HRESULT hr; | |
5841 | HMODULE hfusion; | |
5842 | HMODULE hmscoree; | |
5843 | ||
5844 | static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0}; | |
5845 | ||
5846 | hmscoree = LoadLibraryA("mscoree.dll"); | |
5847 | if (!hmscoree) | |
5848 | { | |
5849 | WARN("mscoree.dll not available\n"); | |
5850 | return FALSE; | |
5851 | } | |
5852 | ||
5853 | pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim"); | |
5854 | if (!pLoadLibraryShim) | |
5855 | { | |
5856 | WARN("LoadLibraryShim not available\n"); | |
5857 | FreeLibrary(hmscoree); | |
5858 | return FALSE; | |
5859 | } | |
5860 | ||
5861 | hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion); | |
5862 | if (FAILED(hr)) | |
5863 | { | |
5864 | WARN("fusion.dll not available\n"); | |
5865 | FreeLibrary(hmscoree); | |
5866 | return FALSE; | |
5867 | } | |
5868 | ||
5869 | pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache"); | |
5870 | ||
5871 | FreeLibrary(hmscoree); | |
5872 | return TRUE; | |
5873 | } | |
5874 | ||
d596ae29 JH |
5875 | static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly, |
5876 | LPWSTR path) | |
bfe07d1d JH |
5877 | { |
5878 | IAssemblyCache *cache; | |
5879 | HRESULT hr; | |
5880 | UINT r = ERROR_FUNCTION_FAILED; | |
5881 | ||
74239fcd JH |
5882 | TRACE("installing assembly: %s\n", debugstr_w(path)); |
5883 | ||
5884 | if (assembly->feature) | |
d596ae29 | 5885 | msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL); |
74239fcd JH |
5886 | |
5887 | if (assembly->manifest) | |
5888 | FIXME("Manifest unhandled\n"); | |
5889 | ||
5890 | if (assembly->application) | |
5891 | { | |
5892 | FIXME("Assembly should be privately installed\n"); | |
5893 | return ERROR_SUCCESS; | |
5894 | } | |
5895 | ||
5896 | if (assembly->attributes == msidbAssemblyAttributesWin32) | |
5897 | { | |
5898 | FIXME("Win32 assemblies not handled\n"); | |
5899 | return ERROR_SUCCESS; | |
5900 | } | |
5901 | ||
bfe07d1d JH |
5902 | hr = pCreateAssemblyCache(&cache, 0); |
5903 | if (FAILED(hr)) | |
5904 | goto done; | |
5905 | ||
5906 | hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL); | |
5907 | if (FAILED(hr)) | |
5908 | ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr); | |
5909 | ||
5910 | r = ERROR_SUCCESS; | |
5911 | ||
5912 | done: | |
5913 | IAssemblyCache_Release(cache); | |
5914 | return r; | |
5915 | } | |
5916 | ||
74239fcd | 5917 | typedef struct tagASSEMBLY_LIST |
bfe07d1d | 5918 | { |
74239fcd | 5919 | MSIPACKAGE *package; |
019f4af1 | 5920 | IAssemblyCache *cache; |
74239fcd JH |
5921 | struct list *assemblies; |
5922 | } ASSEMBLY_LIST; | |
bfe07d1d | 5923 | |
019f4af1 JH |
5924 | typedef struct tagASSEMBLY_NAME |
5925 | { | |
5926 | LPWSTR name; | |
5927 | LPWSTR version; | |
5928 | LPWSTR culture; | |
5929 | LPWSTR pubkeytoken; | |
5930 | } ASSEMBLY_NAME; | |
5931 | ||
5932 | static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param) | |
5933 | { | |
5f3ac30b | 5934 | ASSEMBLY_NAME *asmname = param; |
019f4af1 JH |
5935 | LPCWSTR name = MSI_RecordGetString(rec, 2); |
5936 | LPWSTR val = msi_dup_record_field(rec, 3); | |
5937 | ||
5938 | static const WCHAR Name[] = {'N','a','m','e',0}; | |
5939 | static const WCHAR Version[] = {'V','e','r','s','i','o','n',0}; | |
5940 | static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0}; | |
5941 | static const WCHAR PublicKeyToken[] = { | |
5942 | 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0}; | |
5943 | ||
43094e4a | 5944 | if (!strcmpiW(name, Name)) |
019f4af1 | 5945 | asmname->name = val; |
43094e4a | 5946 | else if (!strcmpiW(name, Version)) |
019f4af1 | 5947 | asmname->version = val; |
43094e4a | 5948 | else if (!strcmpiW(name, Culture)) |
019f4af1 | 5949 | asmname->culture = val; |
43094e4a | 5950 | else if (!strcmpiW(name, PublicKeyToken)) |
019f4af1 JH |
5951 | asmname->pubkeytoken = val; |
5952 | else | |
5953 | msi_free(val); | |
5954 | ||
5955 | return ERROR_SUCCESS; | |
5956 | } | |
5957 | ||
5958 | static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append) | |
5959 | { | |
5960 | if (!*str) | |
5961 | { | |
5962 | *size = lstrlenW(append) + 1; | |
5963 | *str = msi_alloc((*size) * sizeof(WCHAR)); | |
5964 | lstrcpyW(*str, append); | |
5965 | return; | |
5966 | } | |
5967 | ||
5968 | (*size) += lstrlenW(append); | |
5969 | *str = msi_realloc(*str, (*size) * sizeof(WCHAR)); | |
5970 | lstrcatW(*str, append); | |
5971 | } | |
5972 | ||
5973 | static BOOL check_assembly_installed(MSIDATABASE *db, IAssemblyCache *cache, | |
5974 | MSICOMPONENT *comp) | |
5975 | { | |
5976 | ASSEMBLY_INFO asminfo; | |
5977 | ASSEMBLY_NAME name; | |
5978 | MSIQUERY *view; | |
5979 | LPWSTR disp; | |
5980 | DWORD size; | |
5981 | BOOL found; | |
5982 | UINT r; | |
5983 | ||
5984 | static const WCHAR separator[] = {',',' ',0}; | |
5985 | static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0}; | |
5986 | static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0}; | |
5987 | static const WCHAR PublicKeyToken[] = { | |
5988 | 'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0}; | |
5989 | static const WCHAR query[] = { | |
5990 | 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', | |
5991 | '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ', | |
5992 | 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`', | |
5993 | '=','\'','%','s','\'',0}; | |
5994 | ||
5995 | disp = NULL; | |
5996 | found = FALSE; | |
5997 | ZeroMemory(&name, sizeof(ASSEMBLY_NAME)); | |
5998 | ZeroMemory(&asminfo, sizeof(ASSEMBLY_INFO)); | |
5999 | ||
6000 | r = MSI_OpenQuery(db, &view, query, comp->Component); | |
6001 | if (r != ERROR_SUCCESS) | |
6002 | return ERROR_SUCCESS; | |
6003 | ||
6004 | MSI_IterateRecords(view, NULL, parse_assembly_name, &name); | |
6005 | msiobj_release(&view->hdr); | |
6006 | ||
6007 | if (!name.name) | |
6008 | { | |
6009 | ERR("No assembly name specified!\n"); | |
6010 | goto done; | |
6011 | } | |
6012 | ||
6013 | append_str(&disp, &size, name.name); | |
6014 | ||
6015 | if (name.version) | |
6016 | { | |
6017 | append_str(&disp, &size, separator); | |
6018 | append_str(&disp, &size, Version); | |
6019 | append_str(&disp, &size, name.version); | |
6020 | } | |
6021 | ||
6022 | if (name.culture) | |
6023 | { | |
6024 | append_str(&disp, &size, separator); | |
6025 | append_str(&disp, &size, Culture); | |
6026 | append_str(&disp, &size, name.culture); | |
6027 | } | |
6028 | ||
6029 | if (name.pubkeytoken) | |
6030 | { | |
6031 | append_str(&disp, &size, separator); | |
6032 | append_str(&disp, &size, PublicKeyToken); | |
6033 | append_str(&disp, &size, name.pubkeytoken); | |
6034 | } | |
6035 | ||
6036 | asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO); | |
6037 | IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_VALIDATE, | |
6038 | disp, &asminfo); | |
6039 | found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED); | |
6040 | ||
6041 | done: | |
019f4af1 JH |
6042 | msi_free(disp); |
6043 | msi_free(name.name); | |
6044 | msi_free(name.version); | |
6045 | msi_free(name.culture); | |
6046 | msi_free(name.pubkeytoken); | |
6047 | ||
6048 | return found; | |
6049 | } | |
6050 | ||
74239fcd JH |
6051 | static UINT load_assembly(MSIRECORD *rec, LPVOID param) |
6052 | { | |
5f3ac30b | 6053 | ASSEMBLY_LIST *list = param; |
74239fcd JH |
6054 | MSIASSEMBLY *assembly; |
6055 | ||
6056 | assembly = msi_alloc_zero(sizeof(MSIASSEMBLY)); | |
6057 | if (!assembly) | |
6058 | return ERROR_OUTOFMEMORY; | |
6059 | ||
6060 | assembly->component = get_loaded_component(list->package, MSI_RecordGetString(rec, 1)); | |
6061 | ||
6062 | if (!assembly->component || !assembly->component->Enabled || | |
6063 | !(assembly->component->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE))) | |
bfe07d1d | 6064 | { |
92ed390b | 6065 | TRACE("Component not set for install, not publishing assembly\n"); |
74239fcd | 6066 | msi_free(assembly); |
bfe07d1d JH |
6067 | return ERROR_SUCCESS; |
6068 | } | |
6069 | ||
74239fcd JH |
6070 | assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2)); |
6071 | assembly->file = msi_find_file(list->package, assembly->component->KeyPath); | |
bfe07d1d | 6072 | |
74239fcd | 6073 | if (!assembly->file) |
bfe07d1d | 6074 | { |
74239fcd JH |
6075 | ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath)); |
6076 | return ERROR_FUNCTION_FAILED; | |
bfe07d1d JH |
6077 | } |
6078 | ||
74239fcd JH |
6079 | assembly->manifest = strdupW(MSI_RecordGetString(rec, 3)); |
6080 | assembly->application = strdupW(MSI_RecordGetString(rec, 4)); | |
6081 | assembly->attributes = MSI_RecordGetInteger(rec, 5); | |
9c6e6efa HL |
6082 | |
6083 | if (assembly->application) | |
6084 | { | |
6085 | WCHAR version[24]; | |
6086 | DWORD size = sizeof(version)/sizeof(WCHAR); | |
6087 | ||
6088 | /* FIXME: we should probably check the manifest file here */ | |
6089 | ||
6090 | if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) && | |
7d837b9f | 6091 | (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0)) |
9c6e6efa HL |
6092 | { |
6093 | assembly->installed = TRUE; | |
6094 | } | |
6095 | } | |
6096 | else | |
6097 | assembly->installed = check_assembly_installed(list->package->db, | |
6098 | list->cache, | |
6099 | assembly->component); | |
74239fcd JH |
6100 | |
6101 | list_add_head(list->assemblies, &assembly->entry); | |
74239fcd JH |
6102 | return ERROR_SUCCESS; |
6103 | } | |
6104 | ||
6105 | static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies) | |
6106 | { | |
019f4af1 | 6107 | IAssemblyCache *cache = NULL; |
74239fcd | 6108 | ASSEMBLY_LIST list; |
019f4af1 JH |
6109 | MSIQUERY *view; |
6110 | HRESULT hr; | |
74239fcd JH |
6111 | UINT r; |
6112 | ||
6113 | static const WCHAR query[] = | |
6114 | {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', | |
6115 | '`','M','s','i','A','s','s','e','m','b','l','y','`',0}; | |
6116 | ||
6117 | r = MSI_DatabaseOpenViewW(package->db, query, &view); | |
6118 | if (r != ERROR_SUCCESS) | |
bfe07d1d | 6119 | return ERROR_SUCCESS; |
bfe07d1d | 6120 | |
019f4af1 JH |
6121 | hr = pCreateAssemblyCache(&cache, 0); |
6122 | if (FAILED(hr)) | |
6123 | return ERROR_FUNCTION_FAILED; | |
6124 | ||
74239fcd | 6125 | list.package = package; |
019f4af1 | 6126 | list.cache = cache; |
74239fcd JH |
6127 | list.assemblies = assemblies; |
6128 | ||
6129 | r = MSI_IterateRecords(view, NULL, load_assembly, &list); | |
6130 | msiobj_release(&view->hdr); | |
6131 | ||
019f4af1 JH |
6132 | IAssemblyCache_Release(cache); |
6133 | ||
74239fcd JH |
6134 | return r; |
6135 | } | |
6136 | ||
6137 | static void free_assemblies(struct list *assemblies) | |
6138 | { | |
6139 | struct list *item, *cursor; | |
6140 | ||
6141 | LIST_FOR_EACH_SAFE(item, cursor, assemblies) | |
70cd6bfb | 6142 | { |
74239fcd JH |
6143 | MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry); |
6144 | ||
6145 | list_remove(&assembly->entry); | |
6146 | msi_free(assembly->application); | |
6147 | msi_free(assembly->manifest); | |
6148 | msi_free(assembly); | |
70cd6bfb | 6149 | } |
74239fcd | 6150 | } |
bfe07d1d | 6151 | |
74239fcd JH |
6152 | static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out) |
6153 | { | |
6154 | MSIASSEMBLY *assembly; | |
9460ae35 | 6155 | |
74239fcd | 6156 | LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry) |
bfe07d1d | 6157 | { |
74239fcd | 6158 | if (!lstrcmpW(assembly->file->File, file)) |
9460ae35 | 6159 | { |
74239fcd JH |
6160 | *out = assembly; |
6161 | return TRUE; | |
9460ae35 | 6162 | } |
bfe07d1d | 6163 | } |
74239fcd JH |
6164 | |
6165 | return FALSE; | |
6166 | } | |
6167 | ||
6168 | static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action, | |
6169 | LPWSTR *path, DWORD *attrs, PVOID user) | |
6170 | { | |
6171 | MSIASSEMBLY *assembly; | |
6172 | WCHAR temppath[MAX_PATH]; | |
5f3ac30b | 6173 | struct list *assemblies = user; |
74239fcd JH |
6174 | UINT r; |
6175 | ||
6176 | if (!find_assembly(assemblies, file, &assembly)) | |
6177 | return FALSE; | |
6178 | ||
6179 | GetTempPathW(MAX_PATH, temppath); | |
6180 | PathAddBackslashW(temppath); | |
6181 | lstrcatW(temppath, assembly->file->FileName); | |
6182 | ||
6183 | if (action == MSICABEXTRACT_BEGINEXTRACT) | |
9460ae35 | 6184 | { |
74239fcd JH |
6185 | if (assembly->installed) |
6186 | return FALSE; | |
bfe07d1d | 6187 | |
74239fcd JH |
6188 | *path = strdupW(temppath); |
6189 | *attrs = assembly->file->Attributes; | |
9460ae35 | 6190 | } |
74239fcd JH |
6191 | else if (action == MSICABEXTRACT_FILEEXTRACTED) |
6192 | { | |
6193 | assembly->installed = TRUE; | |
bfe07d1d | 6194 | |
d596ae29 | 6195 | r = install_assembly(package, assembly, temppath); |
74239fcd JH |
6196 | if (r != ERROR_SUCCESS) |
6197 | ERR("Failed to install assembly\n"); | |
6198 | } | |
bfe07d1d | 6199 | |
74239fcd | 6200 | return TRUE; |
bfe07d1d JH |
6201 | } |
6202 | ||
6203 | static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package ) | |
6204 | { | |
74239fcd JH |
6205 | UINT r; |
6206 | struct list assemblies = LIST_INIT(assemblies); | |
6207 | MSIASSEMBLY *assembly; | |
6208 | MSIMEDIAINFO *mi; | |
bfe07d1d | 6209 | |
019f4af1 JH |
6210 | if (!init_functionpointers() || !pCreateAssemblyCache) |
6211 | return ERROR_FUNCTION_FAILED; | |
6212 | ||
74239fcd JH |
6213 | r = load_assemblies(package, &assemblies); |
6214 | if (r != ERROR_SUCCESS) | |
6215 | goto done; | |
bfe07d1d | 6216 | |
74239fcd JH |
6217 | if (list_empty(&assemblies)) |
6218 | goto done; | |
bfe07d1d | 6219 | |
74239fcd JH |
6220 | mi = msi_alloc_zero(sizeof(MSIMEDIAINFO)); |
6221 | if (!mi) | |
6222 | { | |
6223 | r = ERROR_OUTOFMEMORY; | |
6224 | goto done; | |
6225 | } | |
bfe07d1d | 6226 | |
74239fcd JH |
6227 | LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry) |
6228 | { | |
6229 | if (assembly->installed && !mi->is_continuous) | |
6230 | continue; | |
6231 | ||
6232 | if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous || | |
6233 | (assembly->file->IsCompressed && !mi->is_extracted)) | |
6234 | { | |
6235 | MSICABDATA data; | |
6236 | ||
6237 | r = ready_media(package, assembly->file, mi); | |
6238 | if (r != ERROR_SUCCESS) | |
6239 | { | |
6240 | ERR("Failed to ready media\n"); | |
6241 | break; | |
6242 | } | |
6243 | ||
6244 | data.mi = mi; | |
6245 | data.package = package; | |
6246 | data.cb = installassembly_cb; | |
6247 | data.user = &assemblies; | |
6248 | ||
6249 | if (assembly->file->IsCompressed && | |
6250 | !msi_cabextract(package, mi, &data)) | |
6251 | { | |
6252 | ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet)); | |
6253 | r = ERROR_FUNCTION_FAILED; | |
6254 | break; | |
6255 | } | |
6256 | } | |
6257 | ||
6258 | if (!assembly->file->IsCompressed) | |
6259 | { | |
d15fddf6 | 6260 | LPWSTR source = resolve_file_source(package, assembly->file); |
74239fcd | 6261 | |
d15fddf6 | 6262 | r = install_assembly(package, assembly, source); |
74239fcd JH |
6263 | if (r != ERROR_SUCCESS) |
6264 | ERR("Failed to install assembly\n"); | |
d15fddf6 JH |
6265 | |
6266 | msi_free(source); | |
74239fcd JH |
6267 | } |
6268 | ||
6269 | /* FIXME: write Installer assembly reg values */ | |
6270 | } | |
6271 | ||
6272 | done: | |
6273 | free_assemblies(&assemblies); | |
6274 | return r; | |
bfe07d1d JH |
6275 | } |
6276 | ||
2586a095 MM |
6277 | static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, |
6278 | LPCSTR action, LPCWSTR table ) | |
202166c3 | 6279 | { |
2586a095 MM |
6280 | static const WCHAR query[] = { |
6281 | 'S','E','L','E','C','T',' ','*',' ', | |
6282 | 'F','R','O','M',' ','`','%','s','`',0 }; | |
202166c3 MM |
6283 | MSIQUERY *view = NULL; |
6284 | DWORD count = 0; | |
2586a095 | 6285 | UINT r; |
202166c3 | 6286 | |
2586a095 MM |
6287 | r = MSI_OpenQuery( package->db, &view, query, table ); |
6288 | if (r == ERROR_SUCCESS) | |
202166c3 | 6289 | { |
2586a095 | 6290 | r = MSI_IterateRecords(view, &count, NULL, package); |
202166c3 MM |
6291 | msiobj_release(&view->hdr); |
6292 | } | |
6293 | ||
2586a095 | 6294 | if (count) |
f1d4646a | 6295 | FIXME("%s -> %u ignored %s table values\n", |
2586a095 MM |
6296 | action, count, debugstr_w(table)); |
6297 | ||
202166c3 MM |
6298 | return ERROR_SUCCESS; |
6299 | } | |
8e22e7d7 | 6300 | |
55942702 MM |
6301 | static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package ) |
6302 | { | |
6303 | TRACE("%p\n", package); | |
6304 | return ERROR_SUCCESS; | |
6305 | } | |
6306 | ||
2586a095 | 6307 | static UINT ACTION_RemoveIniValues( MSIPACKAGE *package ) |
8e22e7d7 | 6308 | { |
2586a095 MM |
6309 | static const WCHAR table[] = |
6310 | {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 }; | |
6311 | return msi_unimplemented_action_stub( package, "RemoveIniValues", table ); | |
6312 | } | |
8e22e7d7 | 6313 | |
2586a095 | 6314 | static UINT ACTION_PatchFiles( MSIPACKAGE *package ) |
567f0314 | 6315 | { |
2586a095 MM |
6316 | static const WCHAR table[] = { 'P','a','t','c','h',0 }; |
6317 | return msi_unimplemented_action_stub( package, "PatchFiles", table ); | |
6318 | } | |
567f0314 | 6319 | |
2586a095 MM |
6320 | static UINT ACTION_BindImage( MSIPACKAGE *package ) |
6321 | { | |
6322 | static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 }; | |
6323 | return msi_unimplemented_action_stub( package, "BindImage", table ); | |
567f0314 | 6324 | } |
94fbe09c | 6325 | |
2586a095 | 6326 | static UINT ACTION_IsolateComponents( MSIPACKAGE *package ) |
94fbe09c | 6327 | { |
2586a095 MM |
6328 | static const WCHAR table[] = { |
6329 | 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 }; | |
6330 | return msi_unimplemented_action_stub( package, "IsolateComponents", table ); | |
6331 | } | |
94fbe09c | 6332 | |
2586a095 MM |
6333 | static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package ) |
6334 | { | |
6335 | static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 }; | |
6336 | return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table ); | |
94fbe09c | 6337 | } |
b9a3a7a1 | 6338 | |
2586a095 | 6339 | static UINT ACTION_SelfUnregModules( MSIPACKAGE *package ) |
b9a3a7a1 | 6340 | { |
2586a095 MM |
6341 | static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 }; |
6342 | return msi_unimplemented_action_stub( package, "SelfUnregModules", table ); | |
6343 | } | |
b9a3a7a1 | 6344 | |
2586a095 MM |
6345 | static UINT ACTION_DeleteServices( MSIPACKAGE *package ) |
6346 | { | |
6347 | static const WCHAR table[] = { | |
6348 | 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 }; | |
6349 | return msi_unimplemented_action_stub( package, "DeleteServices", table ); | |
b9a3a7a1 | 6350 | } |
ee3ac7a8 SS |
6351 | static UINT ACTION_ValidateProductID( MSIPACKAGE *package ) |
6352 | { | |
6353 | static const WCHAR table[] = { | |
6354 | 'P','r','o','d','u','c','t','I','D',0 }; | |
6355 | return msi_unimplemented_action_stub( package, "ValidateProductID", table ); | |
6356 | } | |
3b955150 | 6357 | |
3b955150 MM |
6358 | static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package ) |
6359 | { | |
6360 | static const WCHAR table[] = { | |
6361 | 'E','n','v','i','r','o','n','m','e','n','t',0 }; | |
6362 | return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table ); | |
6363 | } | |
6364 | ||
3b955150 MM |
6365 | static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package ) |
6366 | { | |
6367 | static const WCHAR table[] = { | |
6368 | 'M','s','i','A','s','s','e','m','b','l','y',0 }; | |
6369 | return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table ); | |
6370 | } | |
6371 | ||
6372 | static UINT ACTION_UnregisterFonts( MSIPACKAGE *package ) | |
6373 | { | |
6374 | static const WCHAR table[] = { 'F','o','n','t',0 }; | |
6375 | return msi_unimplemented_action_stub( package, "UnregisterFonts", table ); | |
6376 | } | |
6377 | ||
f24a9e2a MM |
6378 | static UINT ACTION_RMCCPSearch( MSIPACKAGE *package ) |
6379 | { | |
6380 | static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 }; | |
6381 | return msi_unimplemented_action_stub( package, "RMCCPSearch", table ); | |
6382 | } | |
6383 | ||
88603669 MM |
6384 | static UINT ACTION_RegisterComPlus( MSIPACKAGE *package ) |
6385 | { | |
6386 | static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 }; | |
6387 | return msi_unimplemented_action_stub( package, "RegisterComPlus", table ); | |
6388 | } | |
6389 | ||
6390 | static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package ) | |
6391 | { | |
6392 | static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 }; | |
6393 | return msi_unimplemented_action_stub( package, "UnregisterComPlus", table ); | |
6394 | } | |
6395 | ||
987c2c85 JH |
6396 | static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package ) |
6397 | { | |
6398 | static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 }; | |
6399 | return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table ); | |
6400 | } | |
6401 | ||
6402 | static UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package ) | |
6403 | { | |
6404 | static const WCHAR table[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 }; | |
6405 | return msi_unimplemented_action_stub( package, "RemoveDuplicateFiles", table ); | |
6406 | } | |
6407 | ||
6408 | static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package ) | |
6409 | { | |
6410 | static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 }; | |
6411 | return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table ); | |
6412 | } | |
6413 | ||
6414 | static UINT ACTION_RemoveFolders( MSIPACKAGE *package ) | |
6415 | { | |
6416 | static const WCHAR table[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 }; | |
6417 | return msi_unimplemented_action_stub( package, "RemoveFolders", table ); | |
6418 | } | |
6419 | ||
6420 | static UINT ACTION_RemoveODBC( MSIPACKAGE *package ) | |
6421 | { | |
6422 | static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 }; | |
6423 | return msi_unimplemented_action_stub( package, "RemoveODBC", table ); | |
6424 | } | |
6425 | ||
6426 | static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package ) | |
6427 | { | |
6428 | static const WCHAR table[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 }; | |
6429 | return msi_unimplemented_action_stub( package, "RemoveRegistryValues", table ); | |
6430 | } | |
6431 | ||
6432 | static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package ) | |
6433 | { | |
6434 | static const WCHAR table[] = { 'S','h','o','r','t','c','u','t',0 }; | |
6435 | return msi_unimplemented_action_stub( package, "RemoveShortcuts", table ); | |
6436 | } | |
6437 | ||
6438 | static UINT ACTION_UnpublishComponents( MSIPACKAGE *package ) | |
6439 | { | |
6440 | static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 }; | |
6441 | return msi_unimplemented_action_stub( package, "UnpublishComponents", table ); | |
6442 | } | |
6443 | ||
987c2c85 JH |
6444 | static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package ) |
6445 | { | |
6446 | static const WCHAR table[] = { 'A','p','p','I','d',0 }; | |
6447 | return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table ); | |
6448 | } | |
6449 | ||
6450 | static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package ) | |
6451 | { | |
6452 | static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 }; | |
6453 | return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table ); | |
6454 | } | |
6455 | ||
6456 | static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package ) | |
6457 | { | |
6458 | static const WCHAR table[] = { 'M','I','M','E',0 }; | |
6459 | return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table ); | |
6460 | } | |
6461 | ||
6462 | static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package ) | |
6463 | { | |
6464 | static const WCHAR table[] = { 'P','r','o','g','I','d',0 }; | |
6465 | return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table ); | |
6466 | } | |
6467 | ||
6468 | static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package ) | |
6469 | { | |
6470 | static const WCHAR table[] = { 'T','y','p','e','L','i','b',0 }; | |
6471 | return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table ); | |
6472 | } | |
6473 | ||
1cdf5cdd | 6474 | static const struct _actions StandardActions[] = { |
55942702 | 6475 | { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace }, |
3b955150 MM |
6476 | { szAppSearch, ACTION_AppSearch }, |
6477 | { szBindImage, ACTION_BindImage }, | |
987c2c85 | 6478 | { szCCPSearch, ACTION_CCPSearch }, |
3b955150 MM |
6479 | { szCostFinalize, ACTION_CostFinalize }, |
6480 | { szCostInitialize, ACTION_CostInitialize }, | |
6481 | { szCreateFolders, ACTION_CreateFolders }, | |
6482 | { szCreateShortcuts, ACTION_CreateShortcuts }, | |
6483 | { szDeleteServices, ACTION_DeleteServices }, | |
987c2c85 | 6484 | { szDisableRollback, NULL }, |
3b955150 MM |
6485 | { szDuplicateFiles, ACTION_DuplicateFiles }, |
6486 | { szExecuteAction, ACTION_ExecuteAction }, | |
6487 | { szFileCost, ACTION_FileCost }, | |
6488 | { szFindRelatedProducts, ACTION_FindRelatedProducts }, | |
6489 | { szForceReboot, ACTION_ForceReboot }, | |
987c2c85 | 6490 | { szInstallAdminPackage, NULL }, |
3b955150 MM |
6491 | { szInstallExecute, ACTION_InstallExecute }, |
6492 | { szInstallExecuteAgain, ACTION_InstallExecute }, | |
6493 | { szInstallFiles, ACTION_InstallFiles}, | |
6494 | { szInstallFinalize, ACTION_InstallFinalize }, | |
6495 | { szInstallInitialize, ACTION_InstallInitialize }, | |
987c2c85 | 6496 | { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile }, |
3b955150 MM |
6497 | { szInstallValidate, ACTION_InstallValidate }, |
6498 | { szIsolateComponents, ACTION_IsolateComponents }, | |
6499 | { szLaunchConditions, ACTION_LaunchConditions }, | |
6500 | { szMigrateFeatureStates, ACTION_MigrateFeatureStates }, | |
6501 | { szMoveFiles, ACTION_MoveFiles }, | |
6502 | { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies }, | |
6503 | { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies }, | |
d3bec325 | 6504 | { szInstallODBC, ACTION_InstallODBC }, |
3b955150 MM |
6505 | { szInstallServices, ACTION_InstallServices }, |
6506 | { szPatchFiles, ACTION_PatchFiles }, | |
6507 | { szProcessComponents, ACTION_ProcessComponents }, | |
6508 | { szPublishComponents, ACTION_PublishComponents }, | |
6509 | { szPublishFeatures, ACTION_PublishFeatures }, | |
6510 | { szPublishProduct, ACTION_PublishProduct }, | |
6511 | { szRegisterClassInfo, ACTION_RegisterClassInfo }, | |
88603669 | 6512 | { szRegisterComPlus, ACTION_RegisterComPlus}, |
3b955150 MM |
6513 | { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo }, |
6514 | { szRegisterFonts, ACTION_RegisterFonts }, | |
6515 | { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo }, | |
6516 | { szRegisterProduct, ACTION_RegisterProduct }, | |
6517 | { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo }, | |
6518 | { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries }, | |
987c2c85 JH |
6519 | { szRegisterUser, ACTION_RegisterUser }, |
6520 | { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles }, | |
3b955150 | 6521 | { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings }, |
987c2c85 JH |
6522 | { szRemoveExistingProducts, ACTION_RemoveExistingProducts }, |
6523 | { szRemoveFiles, ACTION_RemoveFiles }, | |
6524 | { szRemoveFolders, ACTION_RemoveFolders }, | |
3b955150 | 6525 | { szRemoveIniValues, ACTION_RemoveIniValues }, |
987c2c85 JH |
6526 | { szRemoveODBC, ACTION_RemoveODBC }, |
6527 | { szRemoveRegistryValues, ACTION_RemoveRegistryValues }, | |
6528 | { szRemoveShortcuts, ACTION_RemoveShortcuts }, | |
6529 | { szResolveSource, ACTION_ResolveSource }, | |
6530 | { szRMCCPSearch, ACTION_RMCCPSearch }, | |
6531 | { szScheduleReboot, NULL }, | |
3b955150 MM |
6532 | { szSelfRegModules, ACTION_SelfRegModules }, |
6533 | { szSelfUnregModules, ACTION_SelfUnregModules }, | |
987c2c85 | 6534 | { szSetODBCFolders, NULL }, |
3b955150 MM |
6535 | { szStartServices, ACTION_StartServices }, |
6536 | { szStopServices, ACTION_StopServices }, | |
987c2c85 JH |
6537 | { szUnpublishComponents, ACTION_UnpublishComponents }, |
6538 | { szUnpublishFeatures, ACTION_UnpublishFeatures }, | |
6539 | { szUnregisterClassInfo, ACTION_UnregisterClassInfo }, | |
6540 | { szUnregisterComPlus, ACTION_UnregisterComPlus }, | |
6541 | { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo }, | |
3b955150 | 6542 | { szUnregisterFonts, ACTION_UnregisterFonts }, |
987c2c85 JH |
6543 | { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo }, |
6544 | { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo }, | |
6545 | { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries }, | |
6546 | { szValidateProductID, ACTION_ValidateProductID }, | |
3b955150 MM |
6547 | { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings }, |
6548 | { szWriteIniValues, ACTION_WriteIniValues }, | |
987c2c85 JH |
6549 | { szWriteRegistryValues, ACTION_WriteRegistryValues }, |
6550 | { NULL, NULL }, | |
3b955150 | 6551 | }; |
9e85ec3b AT |
6552 | |
6553 | static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, | |
6554 | UINT* rc, BOOL force ) | |
6555 | { | |
6556 | BOOL ret = FALSE; | |
6557 | BOOL run = force; | |
6558 | int i; | |
6559 | ||
6560 | if (!run && !package->script->CurrentlyScripting) | |
6561 | run = TRUE; | |
6562 | ||
6563 | if (!run) | |
6564 | { | |
6565 | if (strcmpW(action,szInstallFinalize) == 0 || | |
6566 | strcmpW(action,szInstallExecute) == 0 || | |
6567 | strcmpW(action,szInstallExecuteAgain) == 0) | |
6568 | run = TRUE; | |
6569 | } | |
6570 | ||
6571 | i = 0; | |
6572 | while (StandardActions[i].action != NULL) | |
6573 | { | |
6574 | if (strcmpW(StandardActions[i].action, action)==0) | |
6575 | { | |
6576 | if (!run) | |
6577 | { | |
6578 | ui_actioninfo(package, action, TRUE, 0); | |
6579 | *rc = schedule_action(package,INSTALL_SCRIPT,action); | |
6580 | ui_actioninfo(package, action, FALSE, *rc); | |
6581 | } | |
6582 | else | |
6583 | { | |
6584 | ui_actionstart(package, action); | |
6585 | if (StandardActions[i].handler) | |
6586 | { | |
6587 | *rc = StandardActions[i].handler(package); | |
6588 | } | |
6589 | else | |
6590 | { | |
6591 | FIXME("unhandled standard action %s\n",debugstr_w(action)); | |
6592 | *rc = ERROR_SUCCESS; | |
6593 | } | |
6594 | } | |
6595 | ret = TRUE; | |
6596 | break; | |
6597 | } | |
6598 | i++; | |
6599 | } | |
6600 | return ret; | |
6601 | } |