twain_32: Renamed the dlls/twain directory to dlls/twain_32.
[wine/wine-kai.git] / dlls / msi / source.c
blob779bbc48810bee846bbd2d7ffb5bd5321600af3a
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2005 Aric Stewart for CodeWeavers
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.
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.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <stdarg.h>
23 #define COBJMACROS
24 #define NONAMELESSUNION
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "winnls.h"
30 #include "shlwapi.h"
31 #include "wine/debug.h"
32 #include "msi.h"
33 #include "msiquery.h"
34 #include "msipriv.h"
35 #include "wincrypt.h"
36 #include "winver.h"
37 #include "winuser.h"
38 #include "wine/unicode.h"
39 #include "action.h"
40 #include "sddl.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(msi);
45 * These apis are defined in MSI 3.0
48 typedef struct tagMediaInfo
50 LPWSTR path;
51 WCHAR szIndex[10];
52 WCHAR type;
53 } media_info;
55 static UINT OpenSourceKey(LPCWSTR szProduct, HKEY* key, BOOL user, BOOL create)
57 HKEY rootkey = 0;
58 UINT rc;
59 static const WCHAR szSourceList[] = {'S','o','u','r','c','e','L','i','s','t',0};
61 if (user)
62 rc = MSIREG_OpenUserProductsKey(szProduct, &rootkey, create);
63 else
64 rc = MSIREG_OpenProductsKey(szProduct, &rootkey, create);
66 if (rc)
67 return rc;
69 if (create)
70 rc = RegCreateKeyW(rootkey, szSourceList, key);
71 else
72 rc = RegOpenKeyW(rootkey,szSourceList, key);
74 return rc;
77 static UINT OpenMediaSubkey(HKEY rootkey, HKEY *key, BOOL create)
79 UINT rc;
80 static const WCHAR media[] = {'M','e','d','i','a',0};
82 if (create)
83 rc = RegCreateKeyW(rootkey, media, key);
84 else
85 rc = RegOpenKeyW(rootkey,media, key);
87 return rc;
90 static UINT OpenNetworkSubkey(HKEY rootkey, HKEY *key, BOOL create)
92 UINT rc;
93 static const WCHAR net[] = {'N','e','t',0};
95 if (create)
96 rc = RegCreateKeyW(rootkey, net, key);
97 else
98 rc = RegOpenKeyW(rootkey, net, key);
100 return rc;
103 static UINT OpenURLSubkey(HKEY rootkey, HKEY *key, BOOL create)
105 UINT rc;
106 static const WCHAR URL[] = {'U','R','L',0};
108 if (create)
109 rc = RegCreateKeyW(rootkey, URL, key);
110 else
111 rc = RegOpenKeyW(rootkey, URL, key);
113 return rc;
117 static UINT find_given_source(HKEY key, LPCWSTR szSource, media_info *ss)
119 DWORD index = 0;
120 WCHAR szIndex[10];
121 DWORD size;
122 DWORD val_size;
123 LPWSTR val;
124 UINT rc = ERROR_SUCCESS;
126 while (rc == ERROR_SUCCESS)
128 val = NULL;
129 val_size = 0;
130 size = sizeof(szIndex)/sizeof(szIndex[0]);
131 rc = RegEnumValueW(key, index, szIndex, &size, NULL, NULL, NULL, &val_size);
132 if (rc != ERROR_NO_MORE_ITEMS)
134 val = msi_alloc(val_size);
135 RegEnumValueW(key, index, szIndex, &size, NULL, NULL, (LPBYTE)val,
136 &val_size);
137 if (lstrcmpiW(szSource,val)==0)
139 ss->path = val;
140 strcpyW(ss->szIndex,szIndex);
141 break;
143 else
144 strcpyW(ss->szIndex,szIndex);
146 msi_free(val);
147 index ++;
150 return rc;
153 /******************************************************************
154 * MsiSourceListGetInfoW (MSI.@)
156 UINT WINAPI MsiSourceListGetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
157 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
158 LPCWSTR szProperty, LPWSTR szValue,
159 LPDWORD pcchValue)
161 HKEY sourcekey;
162 UINT rc;
164 TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szProperty));
166 if (!szProduct || lstrlenW(szProduct) > 39)
167 return ERROR_INVALID_PARAMETER;
169 if (szValue && !pcchValue)
170 return ERROR_INVALID_PARAMETER;
172 if (dwOptions == MSICODE_PATCH)
174 FIXME("Unhandled options MSICODE_PATCH\n");
175 return ERROR_FUNCTION_FAILED;
178 if (szUserSid)
179 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
181 if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
182 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
184 if (dwContext == MSIINSTALLCONTEXT_MACHINE)
185 rc = OpenSourceKey(szProduct, &sourcekey, FALSE, FALSE);
186 else
187 rc = OpenSourceKey(szProduct, &sourcekey, TRUE, FALSE);
189 if (rc != ERROR_SUCCESS)
190 return ERROR_UNKNOWN_PRODUCT;
192 if (strcmpW(szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW) == 0)
194 HKEY key;
195 rc = OpenMediaSubkey(sourcekey, &key, FALSE);
196 if (rc == ERROR_SUCCESS)
197 rc = RegQueryValueExW(key, INSTALLPROPERTY_MEDIAPACKAGEPATHW,
198 0, 0, (LPBYTE)szValue, pcchValue);
199 if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
200 rc = ERROR_UNKNOWN_PROPERTY;
201 RegCloseKey(key);
203 else if (strcmpW(szProperty, INSTALLPROPERTY_DISKPROMPTW) ==0)
205 HKEY key;
206 rc = OpenMediaSubkey(sourcekey, &key, FALSE);
207 if (rc == ERROR_SUCCESS)
208 rc = RegQueryValueExW(key, INSTALLPROPERTY_DISKPROMPTW, 0, 0,
209 (LPBYTE)szValue, pcchValue);
210 if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
211 rc = ERROR_UNKNOWN_PROPERTY;
212 RegCloseKey(key);
214 else if (strcmpW(szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW)==0)
216 LPWSTR buffer;
217 DWORD size = 0;
219 RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0, 0,
220 NULL, &size);
221 if (size == 0)
222 rc = ERROR_UNKNOWN_PROPERTY;
223 else
225 LPWSTR ptr;
226 buffer = msi_alloc(size);
227 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
228 0, 0, (LPBYTE)buffer,&size);
229 ptr = strchrW(buffer,';');
230 if (ptr) ptr = strchrW(ptr+1,';');
231 if (!ptr)
232 rc = ERROR_UNKNOWN_PROPERTY;
233 else
235 ptr ++;
236 lstrcpynW(szValue, ptr, *pcchValue);
237 if (lstrlenW(ptr) > *pcchValue)
239 *pcchValue = lstrlenW(ptr)+1;
240 rc = ERROR_MORE_DATA;
242 else
243 rc = ERROR_SUCCESS;
245 msi_free(buffer);
248 else if (strcmpW(INSTALLPROPERTY_LASTUSEDTYPEW, szProperty)==0)
250 LPWSTR buffer;
251 DWORD size = 0;
253 RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0, 0,
254 NULL, &size);
255 if (size == 0)
256 rc = ERROR_UNKNOWN_PROPERTY;
257 else
259 buffer = msi_alloc(size);
260 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
261 0, 0, (LPBYTE)buffer,&size);
262 if (*pcchValue < 1)
264 rc = ERROR_MORE_DATA;
265 *pcchValue = 1;
267 else
269 szValue[0] = buffer[0];
270 rc = ERROR_SUCCESS;
272 msi_free(buffer);
275 else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW, szProperty)==0)
277 rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0, 0,
278 (LPBYTE)szValue, pcchValue);
279 if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
280 rc = ERROR_UNKNOWN_PROPERTY;
282 else
284 FIXME("Unknown property %s\n",debugstr_w(szProperty));
285 rc = ERROR_UNKNOWN_PROPERTY;
288 RegCloseKey(sourcekey);
289 return rc;
292 /******************************************************************
293 * MsiSourceListSetInfoW (MSI.@)
295 UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
296 MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
297 LPCWSTR szProperty, LPCWSTR szValue)
299 HKEY sourcekey;
300 UINT rc;
302 TRACE("%s %s %x %lx %s %s\n", debugstr_w(szProduct), debugstr_w(szUserSid),
303 dwContext, dwOptions, debugstr_w(szProperty), debugstr_w(szValue));
305 if (!szProduct || lstrlenW(szProduct) > 39)
306 return ERROR_INVALID_PARAMETER;
308 if (dwOptions & MSICODE_PATCH)
310 FIXME("Unhandled options MSICODE_PATCH\n");
311 return ERROR_FUNCTION_FAILED;
314 if (szUserSid)
315 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
317 if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
318 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
320 if (dwContext == MSIINSTALLCONTEXT_MACHINE)
321 rc = OpenSourceKey(szProduct, &sourcekey, FALSE, TRUE);
322 else
323 rc = OpenSourceKey(szProduct, &sourcekey, TRUE, TRUE);
325 if (rc != ERROR_SUCCESS)
326 return ERROR_UNKNOWN_PRODUCT;
329 if (strcmpW(szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW) == 0)
331 HKEY key;
332 DWORD size = lstrlenW(szValue)*sizeof(WCHAR);
333 rc = OpenMediaSubkey(sourcekey, &key, FALSE);
334 if (rc == ERROR_SUCCESS)
335 rc = RegSetValueExW(key, INSTALLPROPERTY_MEDIAPACKAGEPATHW, 0,
336 REG_SZ, (LPBYTE)szValue, size);
337 if (rc != ERROR_SUCCESS)
338 rc = ERROR_UNKNOWN_PROPERTY;
339 RegCloseKey(key);
341 else if (strcmpW(szProperty, INSTALLPROPERTY_DISKPROMPTW) == 0)
343 HKEY key;
344 DWORD size = lstrlenW(szValue)*sizeof(WCHAR);
345 rc = OpenMediaSubkey(sourcekey, &key, FALSE);
346 if (rc == ERROR_SUCCESS)
347 rc = RegSetValueExW(key, INSTALLPROPERTY_DISKPROMPTW, 0,
348 REG_SZ, (LPBYTE)szValue, size);
349 if (rc != ERROR_SUCCESS)
350 rc = ERROR_UNKNOWN_PROPERTY;
351 RegCloseKey(key);
353 else if (strcmpW(szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW)==0)
355 LPWSTR buffer = NULL;
356 DWORD size;
357 WCHAR typechar = 'n';
358 static const WCHAR LastUsedSource_Fmt[] = {'%','c',';','%','i',';','%','s',0};
360 /* make sure the source is registered */
361 MsiSourceListAddSourceExW(szProduct, szUserSid, dwContext,
362 dwOptions, szValue, 0);
364 if (dwOptions & MSISOURCETYPE_NETWORK)
365 typechar = 'n';
366 else if (dwOptions & MSISOURCETYPE_URL)
367 typechar = 'u';
368 else if (dwOptions & MSISOURCETYPE_MEDIA)
369 typechar = 'm';
370 else
371 ERR("Unknown source type! 0x%lx\n",dwOptions);
373 size = (lstrlenW(szValue)+5)*sizeof(WCHAR);
374 buffer = msi_alloc(size);
375 sprintfW(buffer, LastUsedSource_Fmt, typechar, 1, szValue);
376 rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0,
377 REG_EXPAND_SZ, (LPBYTE)buffer, size);
378 if (rc != ERROR_SUCCESS)
379 rc = ERROR_UNKNOWN_PROPERTY;
380 msi_free( buffer );
382 else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW, szProperty)==0)
384 DWORD size = lstrlenW(szValue)*sizeof(WCHAR);
385 rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0,
386 REG_SZ, (LPBYTE)szValue, size);
387 if (rc != ERROR_SUCCESS)
388 rc = ERROR_UNKNOWN_PROPERTY;
390 else
392 FIXME("Unknown property %s\n",debugstr_w(szProperty));
393 rc = ERROR_UNKNOWN_PROPERTY;
396 RegCloseKey(sourcekey);
397 return rc;
401 /******************************************************************
402 * MsiSourceListAddSourceW (MSI.@)
404 UINT WINAPI MsiSourceListAddSourceW( LPCWSTR szProduct, LPCWSTR szUserName,
405 DWORD dwReserved, LPCWSTR szSource)
407 INT ret;
408 LPWSTR sidstr = NULL;
409 DWORD sidsize = 0;
411 TRACE("%s %s %s\n", debugstr_w(szProduct), debugstr_w(szUserName), debugstr_w(szSource));
413 if (LookupAccountNameW(NULL, szUserName, NULL, &sidsize, NULL, NULL, NULL))
415 PSID psid = msi_alloc(sidsize);
417 if (LookupAccountNameW(NULL, szUserName, psid, &sidsize, NULL, NULL, NULL))
418 ConvertSidToStringSidW(psid, &sidstr);
420 msi_free(psid);
423 ret = MsiSourceListAddSourceExW(szProduct, sidstr,
424 MSIINSTALLCONTEXT_USERMANAGED, MSISOURCETYPE_NETWORK, szSource, 0);
426 if (sidstr)
427 LocalFree(sidstr);
429 return ret;
432 /******************************************************************
433 * MsiSourceListAddSourceA (MSI.@)
435 UINT WINAPI MsiSourceListAddSourceA( LPCSTR szProduct, LPCSTR szUserName,
436 DWORD dwReserved, LPCSTR szSource)
438 INT ret;
439 LPWSTR szwproduct;
440 LPWSTR szwusername;
441 LPWSTR szwsource;
443 szwproduct = strdupAtoW( szProduct );
444 szwusername = strdupAtoW( szUserName );
445 szwsource = strdupAtoW( szSource );
447 ret = MsiSourceListAddSourceW(szwproduct, szwusername, 0, szwsource);
449 msi_free(szwproduct);
450 msi_free(szwusername);
451 msi_free(szwsource);
453 return ret;
456 /******************************************************************
457 * MsiSourceListAddSourceExW (MSI.@)
459 UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid,
460 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szSource,
461 DWORD dwIndex)
463 HKEY sourcekey;
464 HKEY typekey;
465 UINT rc;
466 media_info source_struct;
468 TRACE("%s, %s, %x, %lx, %s, %li\n", debugstr_w(szProduct),
469 debugstr_w(szUserSid), dwContext, dwOptions, debugstr_w(szSource),
470 dwIndex);
472 if (!szProduct)
473 return ERROR_INVALID_PARAMETER;
475 if (!szSource)
476 return ERROR_INVALID_PARAMETER;
478 if (dwOptions & MSICODE_PATCH)
480 FIXME("Unhandled options MSICODE_PATCH\n");
481 return ERROR_FUNCTION_FAILED;
484 if (szUserSid)
485 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
487 if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
488 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
490 if (dwContext == MSIINSTALLCONTEXT_MACHINE)
491 rc = OpenSourceKey(szProduct, &sourcekey, FALSE, TRUE);
492 else
493 rc = OpenSourceKey(szProduct, &sourcekey, TRUE, TRUE);
495 if (rc != ERROR_SUCCESS)
496 return ERROR_UNKNOWN_PRODUCT;
498 if (dwOptions & MSISOURCETYPE_NETWORK)
499 rc = OpenNetworkSubkey(sourcekey, &typekey, TRUE);
500 else if (dwOptions & MSISOURCETYPE_URL)
501 rc = OpenURLSubkey(sourcekey, &typekey, TRUE);
502 else
504 ERR("unknown media type: %08lx\n", dwOptions);
505 RegCloseKey(sourcekey);
506 return ERROR_FUNCTION_FAILED;
509 source_struct.szIndex[0] = 0;
510 if (find_given_source(typekey, szSource, &source_struct)==ERROR_SUCCESS)
512 DWORD current_index = atoiW(source_struct.szIndex);
513 /* found the source */
514 if (dwIndex > 0 && current_index != dwIndex)
515 FIXME("Need to reorder the sources!\n");
517 else
519 DWORD current_index = 0;
520 static const WCHAR fmt[] = {'%','i',0};
521 DWORD size = lstrlenW(szSource)*sizeof(WCHAR);
523 if (source_struct.szIndex[0])
524 current_index = atoiW(source_struct.szIndex);
525 /* new source */
526 if (dwIndex > 0 && dwIndex < current_index)
527 FIXME("Need to reorder the sources!\n");
529 current_index ++;
530 sprintfW(source_struct.szIndex,fmt,current_index);
531 rc = RegSetValueExW(typekey, source_struct.szIndex, 0, REG_EXPAND_SZ,
532 (LPBYTE)szSource, size);
535 RegCloseKey(typekey);
536 RegCloseKey(sourcekey);
537 return rc;
540 /******************************************************************
541 * MsiSourceListAddMediaDisk(MSI.@)
543 UINT WINAPI MsiSourceListAddMediaDiskW(LPCWSTR szProduct, LPCWSTR szUserSid,
544 MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId,
545 LPCWSTR szVolumeLabel, LPCWSTR szDiskPrompt)
547 HKEY sourcekey;
548 HKEY mediakey;
549 UINT rc;
550 WCHAR szIndex[10];
551 static const WCHAR fmt[] = {'%','i',0};
552 static const WCHAR disk_fmt[] = {'%','s',';','%','s',0};
553 static const WCHAR empty[1] = {0};
554 LPCWSTR pt1,pt2;
555 LPWSTR buffer;
556 DWORD size;
558 TRACE("%s %s %x %lx %li %s %s\n", debugstr_w(szProduct),
559 debugstr_w(szUserSid), dwContext, dwOptions, dwDiskId,
560 debugstr_w(szVolumeLabel), debugstr_w(szDiskPrompt));
562 if (!szProduct || lstrlenW(szProduct) > 39)
563 return ERROR_INVALID_PARAMETER;
565 if (dwOptions & MSICODE_PATCH)
567 FIXME("Unhandled options MSICODE_PATCH\n");
568 return ERROR_FUNCTION_FAILED;
571 if (szUserSid)
572 FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
574 if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
575 FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
577 if (dwContext == MSIINSTALLCONTEXT_MACHINE)
578 rc = OpenSourceKey(szProduct, &sourcekey, FALSE, TRUE);
579 else
580 rc = OpenSourceKey(szProduct, &sourcekey, TRUE, TRUE);
582 if (rc != ERROR_SUCCESS)
583 return ERROR_UNKNOWN_PRODUCT;
585 OpenMediaSubkey(sourcekey,&mediakey,TRUE);
587 sprintfW(szIndex,fmt,dwDiskId);
589 size = 2;
590 if (szVolumeLabel)
592 size +=lstrlenW(szVolumeLabel);
593 pt1 = szVolumeLabel;
595 else
596 pt1 = empty;
597 if (szDiskPrompt)
599 size +=lstrlenW(szDiskPrompt);
600 pt2 = szDiskPrompt;
602 else
603 pt2 = empty;
605 size *=sizeof(WCHAR);
607 buffer = msi_alloc(size);
608 sprintfW(buffer,disk_fmt,pt1,pt2);
610 RegSetValueExW(mediakey, szIndex, 0, REG_SZ, (LPBYTE)buffer, size);
611 msi_free( buffer );
613 RegCloseKey(sourcekey);
614 RegCloseKey(mediakey);
616 return ERROR_SUCCESS;