ReactOS  0.4.13-dev-73-gcfe54aa
appsearch.c
Go to the documentation of this file.
1 /*
2  * Implementation of the AppSearch action of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2005 Juan Lang
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 #include <stdarg.h>
21 
22 #define COBJMACROS
23 
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winreg.h"
27 #include "msi.h"
28 #include "msiquery.h"
29 #include "msidefs.h"
30 #include "winver.h"
31 #include "shlwapi.h"
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
34 #include "msipriv.h"
35 
37 
38 typedef struct tagMSISIGNATURE
39 {
40  LPCWSTR Name; /* NOT owned by this structure */
52 
54 {
55  const WCHAR *ptr;
56  int x1 = 0, x2 = 0, x3 = 0, x4 = 0;
57 
58  x1 = atoiW(verStr);
59  ptr = strchrW(verStr, '.');
60  if (ptr)
61  {
62  x2 = atoiW(ptr + 1);
63  ptr = strchrW(ptr + 1, '.');
64  }
65  if (ptr)
66  {
67  x3 = atoiW(ptr + 1);
68  ptr = strchrW(ptr + 1, '.');
69  }
70  if (ptr)
71  x4 = atoiW(ptr + 1);
72  /* FIXME: byte-order dependent? */
73  *ms = x1 << 16 | x2;
74  if (ls) *ls = x3 << 16 | x4;
75 }
76 
77 /* Fills in sig with the values from the Signature table, where name is the
78  * signature to find. Upon return, sig->File will be NULL if the record is not
79  * found, and not NULL if it is found.
80  * Warning: clears all fields in sig!
81  * Returns ERROR_SUCCESS upon success (where not finding the record counts as
82  * success), something else on error.
83  */
85 {
86  static const WCHAR query[] = {
87  's','e','l','e','c','t',' ','*',' ',
88  'f','r','o','m',' ',
89  'S','i','g','n','a','t','u','r','e',' ',
90  'w','h','e','r','e',' ','S','i','g','n','a','t','u','r','e',' ','=',' ',
91  '\'','%','s','\'',0};
92  LPWSTR minVersion, maxVersion, p;
93  MSIRECORD *row;
94  DWORD time;
95 
96  TRACE("package %p, sig %p\n", package, sig);
97 
98  memset(sig, 0, sizeof(*sig));
99  sig->Name = name;
100  row = MSI_QueryGetRecord( package->db, query, name );
101  if (!row)
102  {
103  TRACE("failed to query signature for %s\n", debugstr_w(name));
104  return ERROR_SUCCESS;
105  }
106 
107  /* get properties */
108  sig->File = msi_dup_record_field(row,2);
109  if ((p = strchrW(sig->File, '|')))
110  {
111  p++;
112  memmove(sig->File, p, (strlenW(p) + 1) * sizeof(WCHAR));
113  }
114 
115  minVersion = msi_dup_record_field(row,3);
116  if (minVersion)
117  {
118  msi_parse_version_string( minVersion, &sig->MinVersionMS, &sig->MinVersionLS );
119  msi_free( minVersion );
120  }
121  maxVersion = msi_dup_record_field(row,4);
122  if (maxVersion)
123  {
124  msi_parse_version_string( maxVersion, &sig->MaxVersionMS, &sig->MaxVersionLS );
125  msi_free( maxVersion );
126  }
127  sig->MinSize = MSI_RecordGetInteger(row,5);
128  if (sig->MinSize == MSI_NULL_INTEGER)
129  sig->MinSize = 0;
130  sig->MaxSize = MSI_RecordGetInteger(row,6);
131  if (sig->MaxSize == MSI_NULL_INTEGER)
132  sig->MaxSize = 0;
135  if (time != MSI_NULL_INTEGER)
138  if (time != MSI_NULL_INTEGER)
140 
141  TRACE("Found file name %s for Signature_ %s;\n",
142  debugstr_w(sig->File), debugstr_w(name));
143  TRACE("MinVersion is %d.%d.%d.%d\n", HIWORD(sig->MinVersionMS),
144  LOWORD(sig->MinVersionMS), HIWORD(sig->MinVersionLS),
145  LOWORD(sig->MinVersionLS));
146  TRACE("MaxVersion is %d.%d.%d.%d\n", HIWORD(sig->MaxVersionMS),
147  LOWORD(sig->MaxVersionMS), HIWORD(sig->MaxVersionLS),
148  LOWORD(sig->MaxVersionLS));
149  TRACE("MinSize is %d, MaxSize is %d;\n", sig->MinSize, sig->MaxSize);
150  TRACE("Languages is %s\n", debugstr_w(sig->Languages));
151 
152  msiobj_release( &row->hdr );
153 
154  return ERROR_SUCCESS;
155 }
156 
157 /* Frees any memory allocated in sig */
159 {
160  msi_free(sig->File);
161  msi_free(sig->Languages);
162 }
163 
165 {
167  DWORD attr, handle, size;
168  LPWSTR val = NULL;
169  LPBYTE buffer;
170 
171  if (!sig->File)
172  {
175 
177  if (attr != INVALID_FILE_ATTRIBUTES &&
179  return strdupW(path);
180 
181  return NULL;
182  }
183 
185  if (attr == INVALID_FILE_ATTRIBUTES ||
187  return NULL;
188 
190  if (!size)
191  return strdupW(path);
192 
193  buffer = msi_alloc(size);
194  if (!buffer)
195  return NULL;
196 
197  if (!GetFileVersionInfoW(path, 0, size, buffer))
198  goto done;
199 
201  goto done;
202 
203  if (sig->MinVersionLS || sig->MinVersionMS)
204  {
205  if (info->dwFileVersionMS < sig->MinVersionMS)
206  goto done;
207 
208  if (info->dwFileVersionMS == sig->MinVersionMS &&
209  info->dwFileVersionLS < sig->MinVersionLS)
210  goto done;
211  }
212 
213  if (sig->MaxVersionLS || sig->MaxVersionMS)
214  {
215  if (info->dwFileVersionMS > sig->MaxVersionMS)
216  goto done;
217 
218  if (info->dwFileVersionMS == sig->MaxVersionMS &&
219  info->dwFileVersionLS > sig->MaxVersionLS)
220  goto done;
221  }
222 
223  val = strdupW(path);
224 
225 done:
226  msi_free(buffer);
227  return val;
228 }
229 
231 {
232  static const WCHAR query[] = {
233  'S','E','L','E','C','T',' ','*',' ',
234  'F','R','O','M',' ',
235  '`','C','o','m','p','L','o','c','a','t','o','r','`',' ',
236  'W','H','E','R','E',' ','`','S','i','g','n','a','t','u','r','e','_','`',' ','=',' ',
237  '\'','%','s','\'',0};
238  static const WCHAR sigquery[] = {
239  'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
240  '`','S','i','g','n','a','t','u','r','e','`',' ',
241  'W','H','E','R','E',' ','`','S','i','g','n','a','t','u','r','e','`',' ','=',' ',
242  '\'','%','s','\'',0};
243 
244  MSIRECORD *row, *rec;
245  LPCWSTR signature, guid;
246  BOOL sigpresent = TRUE;
247  BOOL isdir;
248  UINT type;
250  DWORD size = MAX_PATH;
251  LPWSTR ptr;
252  DWORD attr;
253 
254  TRACE("%s\n", debugstr_w(sig->Name));
255 
256  *appValue = NULL;
257 
258  row = MSI_QueryGetRecord(package->db, query, sig->Name);
259  if (!row)
260  {
261  TRACE("failed to query CompLocator for %s\n", debugstr_w(sig->Name));
262  return ERROR_SUCCESS;
263  }
264 
265  signature = MSI_RecordGetString(row, 1);
268 
269  rec = MSI_QueryGetRecord(package->db, sigquery, signature);
270  if (!rec)
271  sigpresent = FALSE;
272 
273  *path = '\0';
275  if (!*path)
276  goto done;
277 
280  goto done;
281 
282  isdir = (attr & FILE_ATTRIBUTE_DIRECTORY);
283 
284  if (type != msidbLocatorTypeDirectory && sigpresent && !isdir)
285  {
286  *appValue = app_search_file(path, sig);
287  }
288  else if (!sigpresent && (type != msidbLocatorTypeDirectory || isdir))
289  {
291  {
292  ptr = strrchrW(path, '\\');
293  *(ptr + 1) = '\0';
294  }
295  else
297 
298  *appValue = strdupW(path);
299  }
300  else if (sigpresent)
301  {
304 
306  if (attr != INVALID_FILE_ATTRIBUTES &&
308  *appValue = strdupW(path);
309  }
310 
311 done:
312  if (rec) msiobj_release(&rec->hdr);
313  msiobj_release(&row->hdr);
314  return ERROR_SUCCESS;
315 }
316 
317 static void ACTION_ConvertRegValue(DWORD regType, const BYTE *value, DWORD sz,
318  LPWSTR *appValue)
319 {
320  static const WCHAR dwordFmt[] = { '#','%','d','\0' };
321  static const WCHAR binPre[] = { '#','x','\0' };
322  static const WCHAR binFmt[] = { '%','0','2','X','\0' };
323  LPWSTR ptr;
324  DWORD i;
325 
326  switch (regType)
327  {
328  case REG_SZ:
329  if (*(LPCWSTR)value == '#')
330  {
331  /* escape leading pound with another */
332  *appValue = msi_alloc(sz + sizeof(WCHAR));
333  (*appValue)[0] = '#';
334  strcpyW(*appValue + 1, (LPCWSTR)value);
335  }
336  else
337  {
338  *appValue = msi_alloc(sz);
339  strcpyW(*appValue, (LPCWSTR)value);
340  }
341  break;
342  case REG_DWORD:
343  /* 7 chars for digits, 1 for NULL, 1 for #, and 1 for sign
344  * char if needed
345  */
346  *appValue = msi_alloc(10 * sizeof(WCHAR));
347  sprintfW(*appValue, dwordFmt, *(const DWORD *)value);
348  break;
349  case REG_EXPAND_SZ:
351  *appValue = msi_alloc(sz * sizeof(WCHAR));
352  ExpandEnvironmentStringsW((LPCWSTR)value, *appValue, sz);
353  break;
354  case REG_BINARY:
355  /* #x<nibbles>\0 */
356  *appValue = msi_alloc((sz * 2 + 3) * sizeof(WCHAR));
357  lstrcpyW(*appValue, binPre);
358  ptr = *appValue + lstrlenW(binPre);
359  for (i = 0; i < sz; i++, ptr += 2)
360  sprintfW(ptr, binFmt, value[i]);
361  break;
362  default:
363  WARN("unimplemented for values of type %d\n", regType);
364  *appValue = NULL;
365  }
366 }
367 
368 static UINT ACTION_SearchDirectory(MSIPACKAGE *package, MSISIGNATURE *sig,
369  LPCWSTR path, int depth, LPWSTR *appValue);
370 
371 static UINT ACTION_AppSearchReg(MSIPACKAGE *package, LPWSTR *appValue, MSISIGNATURE *sig)
372 {
373  static const WCHAR query[] = {
374  'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
375  'R','e','g','L','o','c','a','t','o','r',' ','W','H','E','R','E',' ',
376  'S','i','g','n','a','t','u','r','e','_',' ','=',' ', '\'','%','s','\'',0};
377  const WCHAR *keyPath, *valueName;
378  WCHAR *deformatted = NULL, *ptr = NULL, *end;
379  int root, type;
380  HKEY rootKey, key = NULL;
381  DWORD sz = 0, regType;
382  LPBYTE value = NULL;
383  MSIRECORD *row;
384  UINT rc;
385 
386  TRACE("%s\n", debugstr_w(sig->Name));
387 
388  *appValue = NULL;
389 
390  row = MSI_QueryGetRecord( package->db, query, sig->Name );
391  if (!row)
392  {
393  TRACE("failed to query RegLocator for %s\n", debugstr_w(sig->Name));
394  return ERROR_SUCCESS;
395  }
396 
398  keyPath = MSI_RecordGetString(row, 3);
399  valueName = MSI_RecordGetString(row, 4);
401 
402  deformat_string(package, keyPath, &deformatted);
403 
404  switch (root)
405  {
407  rootKey = HKEY_CLASSES_ROOT;
408  break;
410  rootKey = HKEY_CURRENT_USER;
411  break;
413  rootKey = HKEY_LOCAL_MACHINE;
414  break;
416  rootKey = HKEY_USERS;
417  break;
418  default:
419  WARN("Unknown root key %d\n", root);
420  goto end;
421  }
422 
423  rc = RegOpenKeyW(rootKey, deformatted, &key);
424  if (rc)
425  {
426  TRACE("RegOpenKeyW returned %d\n", rc);
427  goto end;
428  }
429 
430  msi_free(deformatted);
431  deformat_string(package, valueName, &deformatted);
432 
433  rc = RegQueryValueExW(key, deformatted, NULL, NULL, NULL, &sz);
434  if (rc)
435  {
436  TRACE("RegQueryValueExW returned %d\n", rc);
437  goto end;
438  }
439  /* FIXME: sanity-check sz before allocating (is there an upper-limit
440  * on the value of a property?)
441  */
442  value = msi_alloc( sz );
443  rc = RegQueryValueExW(key, deformatted, NULL, &regType, value, &sz);
444  if (rc)
445  {
446  TRACE("RegQueryValueExW returned %d\n", rc);
447  goto end;
448  }
449 
450  /* bail out if the registry key is empty */
451  if (sz == 0)
452  goto end;
453 
454  /* expand if needed */
455  if (regType == REG_EXPAND_SZ)
456  {
458  if (sz)
459  {
460  LPWSTR buf = msi_alloc(sz * sizeof(WCHAR));
462  msi_free(value);
463  value = (LPBYTE)buf;
464  }
465  }
466 
467  if ((regType == REG_SZ || regType == REG_EXPAND_SZ) &&
468  (ptr = strchrW((LPWSTR)value, '"')) && (end = strchrW(++ptr, '"')))
469  *end = '\0';
470  else
471  ptr = (LPWSTR)value;
472 
473  switch (type & 0x0f)
474  {
476  ACTION_SearchDirectory(package, sig, ptr, 0, appValue);
477  break;
479  *appValue = app_search_file(ptr, sig);
480  break;
482  ACTION_ConvertRegValue(regType, value, sz, appValue);
483  break;
484  default:
485  FIXME("unimplemented for type %d (key path %s, value %s)\n",
486  type, debugstr_w(keyPath), debugstr_w(valueName));
487  }
488 end:
489  msi_free( value );
490  RegCloseKey( key );
491  msi_free( deformatted );
492 
493  msiobj_release(&row->hdr);
494  return ERROR_SUCCESS;
495 }
496 
498 {
499  LPWSTR beg, end;
500  int i = 1;
501 
502  if (field == 0)
503  return strdupW(buf);
504 
505  beg = buf;
506  while ((end = strchrW(beg, ',')) && i < field)
507  {
508  beg = end + 1;
509  while (*beg == ' ')
510  beg++;
511 
512  i++;
513  }
514 
515  end = strchrW(beg, ',');
516  if (!end)
517  end = beg + lstrlenW(beg);
518 
519  *end = '\0';
520  return strdupW(beg);
521 }
522 
523 static UINT ACTION_AppSearchIni(MSIPACKAGE *package, LPWSTR *appValue,
524  MSISIGNATURE *sig)
525 {
526  static const WCHAR query[] = {
527  's','e','l','e','c','t',' ','*',' ',
528  'f','r','o','m',' ',
529  'I','n','i','L','o','c','a','t','o','r',' ',
530  'w','h','e','r','e',' ',
531  'S','i','g','n','a','t','u','r','e','_',' ','=',' ','\'','%','s','\'',0};
532  MSIRECORD *row;
533  LPWSTR fileName, section, key;
534  int field, type;
535  WCHAR buf[MAX_PATH];
536 
537  TRACE("%s\n", debugstr_w(sig->Name));
538 
539  *appValue = NULL;
540 
541  row = MSI_QueryGetRecord( package->db, query, sig->Name );
542  if (!row)
543  {
544  TRACE("failed to query IniLocator for %s\n", debugstr_w(sig->Name));
545  return ERROR_SUCCESS;
546  }
547 
548  fileName = msi_dup_record_field(row, 2);
553  if (field == MSI_NULL_INTEGER)
554  field = 0;
555  if (type == MSI_NULL_INTEGER)
556  type = 0;
557 
559  if (buf[0])
560  {
561  switch (type & 0x0f)
562  {
564  ACTION_SearchDirectory(package, sig, buf, 0, appValue);
565  break;
567  *appValue = app_search_file(buf, sig);
568  break;
570  *appValue = get_ini_field(buf, field);
571  break;
572  }
573  }
574 
575  msi_free(fileName);
576  msi_free(section);
577  msi_free(key);
578 
579  msiobj_release(&row->hdr);
580 
581  return ERROR_SUCCESS;
582 }
583 
584 /* Expands the value in src into a path without property names and only
585  * containing long path names into dst. Replaces at most len characters of dst,
586  * and always NULL-terminates dst if dst is not NULL and len >= 1.
587  * May modify src.
588  * Assumes src and dst are non-overlapping.
589  * FIXME: return code probably needed:
590  * - what does AppSearch return if the table values are invalid?
591  * - what if dst is too small?
592  */
594  size_t len)
595 {
596  WCHAR *ptr, *deformatted;
597 
598  if (!src || !dst || !len)
599  {
600  if (dst) *dst = '\0';
601  return;
602  }
603 
604  dst[0] = '\0';
605 
606  /* Ignore the short portion of the path */
607  if ((ptr = strchrW(src, '|')))
608  ptr++;
609  else
610  ptr = src;
611 
612  deformat_string(package, ptr, &deformatted);
613  if (!deformatted || strlenW(deformatted) > len - 1)
614  {
615  msi_free(deformatted);
616  return;
617  }
618 
619  lstrcpyW(dst, deformatted);
620  dst[lstrlenW(deformatted)] = '\0';
621  msi_free(deformatted);
622 }
623 
624 static LANGID *parse_languages( const WCHAR *languages, DWORD *num_ids )
625 {
626  UINT i, count = 1;
627  WCHAR *str = strdupW( languages ), *p, *q;
628  LANGID *ret;
629 
630  if (!str) return NULL;
631  for (p = q = str; (q = strchrW( q, ',' )); q++) count++;
632 
633  if (!(ret = msi_alloc( count * sizeof(LANGID) )))
634  {
635  msi_free( str );
636  return NULL;
637  }
638  i = 0;
639  while (*p)
640  {
641  q = strchrW( p, ',' );
642  if (q) *q = 0;
643  ret[i] = atoiW( p );
644  if (!q) break;
645  p = q + 1;
646  i++;
647  }
648  msi_free( str );
649  *num_ids = count;
650  return ret;
651 }
652 
653 static BOOL match_languages( const void *version, const WCHAR *languages )
654 {
655  struct lang
656  {
657  USHORT id;
659  } *lang;
660  DWORD len, num_ids, i, j;
661  BOOL found = FALSE;
662  LANGID *ids;
663 
664  if (!languages || !languages[0]) return TRUE;
665  if (!VerQueryValueW( version, szLangResource, (void **)&lang, &len )) return FALSE;
666  if (!(ids = parse_languages( languages, &num_ids ))) return FALSE;
667 
668  for (i = 0; i < num_ids; i++)
669  {
670  found = FALSE;
671  for (j = 0; j < len / sizeof(struct lang); j++)
672  {
673  if (!ids[i] || ids[i] == lang[j].id) found = TRUE;
674  }
675  if (!found) goto done;
676  }
677 
678 done:
679  msi_free( ids );
680  return found;
681 }
682 
683 /* Sets *matches to whether the file (whose path is filePath) matches the
684  * versions set in sig.
685  * Return ERROR_SUCCESS in case of success (whether or not the file matches),
686  * something else if an install-halting error occurs.
687  */
689  BOOL *matches)
690 {
691  UINT len;
692  void *version;
694  DWORD zero, size = GetFileVersionInfoSizeW( filePath, &zero );
695 
696  *matches = FALSE;
697 
698  if (!size) return ERROR_SUCCESS;
699  if (!(version = msi_alloc( size ))) return ERROR_OUTOFMEMORY;
700 
701  if (GetFileVersionInfoW( filePath, 0, size, version ))
702  VerQueryValueW( version, szBackSlash, (void **)&info, &len );
703 
704  if (info)
705  {
706  TRACE("comparing file version %d.%d.%d.%d:\n",
707  HIWORD(info->dwFileVersionMS),
708  LOWORD(info->dwFileVersionMS),
709  HIWORD(info->dwFileVersionLS),
710  LOWORD(info->dwFileVersionLS));
711  if (info->dwFileVersionMS < sig->MinVersionMS
712  || (info->dwFileVersionMS == sig->MinVersionMS &&
713  info->dwFileVersionLS < sig->MinVersionLS))
714  {
715  TRACE("less than minimum version %d.%d.%d.%d\n",
716  HIWORD(sig->MinVersionMS),
717  LOWORD(sig->MinVersionMS),
718  HIWORD(sig->MinVersionLS),
719  LOWORD(sig->MinVersionLS));
720  }
721  else if ((sig->MaxVersionMS || sig->MaxVersionLS) &&
722  (info->dwFileVersionMS > sig->MaxVersionMS ||
723  (info->dwFileVersionMS == sig->MaxVersionMS &&
724  info->dwFileVersionLS > sig->MaxVersionLS)))
725  {
726  TRACE("greater than maximum version %d.%d.%d.%d\n",
727  HIWORD(sig->MaxVersionMS),
728  LOWORD(sig->MaxVersionMS),
729  HIWORD(sig->MaxVersionLS),
730  LOWORD(sig->MaxVersionLS));
731  }
732  else if (!match_languages( version, sig->Languages ))
733  {
734  TRACE("languages %s not supported\n", debugstr_w( sig->Languages ));
735  }
736  else *matches = TRUE;
737  }
738  msi_free( version );
739  return ERROR_SUCCESS;
740 }
741 
742 /* Sets *matches to whether the file in findData matches that in sig.
743  * fullFilePath is assumed to be the full path of the file specified in
744  * findData, which may be necessary to compare the version.
745  * Return ERROR_SUCCESS in case of success (whether or not the file matches),
746  * something else if an install-halting error occurs.
747  */
749  const WIN32_FIND_DATAW *findData, LPCWSTR fullFilePath, BOOL *matches)
750 {
751  UINT rc = ERROR_SUCCESS;
752 
753  *matches = TRUE;
754  /* assumes the caller has already ensured the filenames match, so check
755  * the other fields..
756  */
757  if (sig->MinTime.dwLowDateTime || sig->MinTime.dwHighDateTime)
758  {
759  if (findData->ftCreationTime.dwHighDateTime <
760  sig->MinTime.dwHighDateTime ||
761  (findData->ftCreationTime.dwHighDateTime == sig->MinTime.dwHighDateTime
762  && findData->ftCreationTime.dwLowDateTime <
763  sig->MinTime.dwLowDateTime))
764  *matches = FALSE;
765  }
766  if (*matches && (sig->MaxTime.dwLowDateTime || sig->MaxTime.dwHighDateTime))
767  {
768  if (findData->ftCreationTime.dwHighDateTime >
769  sig->MaxTime.dwHighDateTime ||
770  (findData->ftCreationTime.dwHighDateTime == sig->MaxTime.dwHighDateTime
771  && findData->ftCreationTime.dwLowDateTime >
772  sig->MaxTime.dwLowDateTime))
773  *matches = FALSE;
774  }
775  if (*matches && sig->MinSize && findData->nFileSizeLow < sig->MinSize)
776  *matches = FALSE;
777  if (*matches && sig->MaxSize && findData->nFileSizeLow > sig->MaxSize)
778  *matches = FALSE;
779  if (*matches && (sig->MinVersionMS || sig->MinVersionLS ||
780  sig->MaxVersionMS || sig->MaxVersionLS))
781  rc = ACTION_FileVersionMatches(sig, fullFilePath, matches);
782  return rc;
783 }
784 
785 /* Recursively searches the directory dir for files that match the signature
786  * sig, up to (depth + 1) levels deep. That is, if depth is 0, it searches dir
787  * (and only dir). If depth is 1, searches dir and its immediate
788  * subdirectories.
789  * Assumes sig->File is not NULL.
790  * Returns ERROR_SUCCESS on success (which may include non-critical errors),
791  * something else on failures which should halt the install.
792  */
794  MSISIGNATURE *sig, LPCWSTR dir, int depth)
795 {
796  HANDLE hFind;
797  WIN32_FIND_DATAW findData;
798  UINT rc = ERROR_SUCCESS;
799  size_t dirLen = lstrlenW(dir), fileLen = lstrlenW(sig->File);
800  WCHAR subpath[MAX_PATH];
801  WCHAR *buf;
802  DWORD len;
803 
804  static const WCHAR starDotStarW[] = { '*','.','*',0 };
805 
806  TRACE("Searching directory %s for file %s, depth %d\n", debugstr_w(dir),
807  debugstr_w(sig->File), depth);
808 
809  if (depth < 0)
810  return ERROR_SUCCESS;
811 
812  *appValue = NULL;
813  /* We need the buffer in both paths below, so go ahead and allocate it
814  * here. Add two because we might need to add a backslash if the dir name
815  * isn't backslash-terminated.
816  */
817  len = dirLen + max(fileLen, strlenW(starDotStarW)) + 2;
818  buf = msi_alloc(len * sizeof(WCHAR));
819  if (!buf)
820  return ERROR_OUTOFMEMORY;
821 
822  lstrcpyW(buf, dir);
824  lstrcatW(buf, sig->File);
825 
826  hFind = FindFirstFileW(buf, &findData);
827  if (hFind != INVALID_HANDLE_VALUE)
828  {
829  if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
830  {
831  BOOL matches;
832 
833  rc = ACTION_FileMatchesSig(sig, &findData, buf, &matches);
834  if (rc == ERROR_SUCCESS && matches)
835  {
836  TRACE("found file, returning %s\n", debugstr_w(buf));
837  *appValue = buf;
838  }
839  }
840  FindClose(hFind);
841  }
842 
843  if (rc == ERROR_SUCCESS && !*appValue)
844  {
845  lstrcpyW(buf, dir);
847  lstrcatW(buf, starDotStarW);
848 
849  hFind = FindFirstFileW(buf, &findData);
850  if (hFind != INVALID_HANDLE_VALUE)
851  {
852  if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
853  strcmpW( findData.cFileName, szDot ) &&
854  strcmpW( findData.cFileName, szDotDot ))
855  {
856  lstrcpyW(subpath, dir);
857  PathAppendW(subpath, findData.cFileName);
858  rc = ACTION_RecurseSearchDirectory(package, appValue, sig,
859  subpath, depth - 1);
860  }
861 
862  while (rc == ERROR_SUCCESS && !*appValue &&
863  FindNextFileW(hFind, &findData) != 0)
864  {
865  if (!strcmpW( findData.cFileName, szDot ) ||
866  !strcmpW( findData.cFileName, szDotDot ))
867  continue;
868 
869  lstrcpyW(subpath, dir);
870  PathAppendW(subpath, findData.cFileName);
871  if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
872  rc = ACTION_RecurseSearchDirectory(package, appValue,
873  sig, subpath, depth - 1);
874  }
875 
876  FindClose(hFind);
877  }
878  }
879 
880  if (*appValue != buf)
881  msi_free(buf);
882 
883  return rc;
884 }
885 
887  LPWSTR *appValue)
888 {
890 
892  {
893  TRACE("directory exists, returning %s\n", debugstr_w(dir));
894  *appValue = strdupW(dir);
895  }
896 
897  return ERROR_SUCCESS;
898 }
899 
901 {
902  WCHAR first = toupperW(path[0]);
903  BOOL ret;
904 
905  if (first >= 'A' && first <= 'Z' && path[1] == ':')
906  ret = TRUE;
907  else if (path[0] == '\\' && path[1] == '\\')
908  ret = TRUE;
909  else
910  ret = FALSE;
911  return ret;
912 }
913 
915  LPCWSTR path, int depth, LPWSTR *appValue)
916 {
917  UINT rc;
918  DWORD attr;
919  LPWSTR val = NULL;
920 
921  TRACE("%p, %p, %s, %d, %p\n", package, sig, debugstr_w(path), depth,
922  appValue);
923 
924  if (ACTION_IsFullPath(path))
925  {
926  if (sig->File)
927  rc = ACTION_RecurseSearchDirectory(package, &val, sig, path, depth);
928  else
929  {
930  /* Recursively searching a directory makes no sense when the
931  * directory to search is the thing you're trying to find.
932  */
933  rc = ACTION_CheckDirectory(package, path, &val);
934  }
935  }
936  else
937  {
938  WCHAR pathWithDrive[MAX_PATH] = { 'C',':','\\',0 };
939  DWORD drives = GetLogicalDrives();
940  int i;
941 
942  rc = ERROR_SUCCESS;
943  for (i = 0; rc == ERROR_SUCCESS && !val && i < 26; i++)
944  {
945  if (!(drives & (1 << i)))
946  continue;
947 
948  pathWithDrive[0] = 'A' + i;
949  if (GetDriveTypeW(pathWithDrive) != DRIVE_FIXED)
950  continue;
951 
952  lstrcpynW(pathWithDrive + 3, path,
953  sizeof(pathWithDrive) / sizeof(pathWithDrive[0]) - 3);
954 
955  if (sig->File)
956  rc = ACTION_RecurseSearchDirectory(package, &val, sig,
957  pathWithDrive, depth);
958  else
959  rc = ACTION_CheckDirectory(package, pathWithDrive, &val);
960  }
961  }
962 
964  if (attr != INVALID_FILE_ATTRIBUTES &&
966  val && val[lstrlenW(val) - 1] != '\\')
967  {
968  val = msi_realloc(val, (lstrlenW(val) + 2) * sizeof(WCHAR));
969  if (!val)
970  rc = ERROR_OUTOFMEMORY;
971  else
973  }
974 
975  *appValue = val;
976 
977  TRACE("returning %d\n", rc);
978  return rc;
979 }
980 
981 static UINT ACTION_AppSearchSigName(MSIPACKAGE *package, LPCWSTR sigName,
982  MSISIGNATURE *sig, LPWSTR *appValue);
983 
984 static UINT ACTION_AppSearchDr(MSIPACKAGE *package, LPWSTR *appValue, MSISIGNATURE *sig)
985 {
986  static const WCHAR query[] = {
987  's','e','l','e','c','t',' ','*',' ',
988  'f','r','o','m',' ',
989  'D','r','L','o','c','a','t','o','r',' ',
990  'w','h','e','r','e',' ',
991  'S','i','g','n','a','t','u','r','e','_',' ','=',' ', '\'','%','s','\'',0};
992  LPWSTR parent = NULL;
993  LPCWSTR parentName;
995  WCHAR expanded[MAX_PATH];
996  MSIRECORD *row;
997  int depth;
998  DWORD sz, attr;
999  UINT rc;
1000 
1001  TRACE("%s\n", debugstr_w(sig->Name));
1002 
1003  *appValue = NULL;
1004 
1005  row = MSI_QueryGetRecord( package->db, query, sig->Name );
1006  if (!row)
1007  {
1008  TRACE("failed to query DrLocator for %s\n", debugstr_w(sig->Name));
1009  return ERROR_SUCCESS;
1010  }
1011 
1012  /* check whether parent is set */
1013  parentName = MSI_RecordGetString(row, 2);
1014  if (parentName)
1015  {
1016  MSISIGNATURE parentSig;
1017 
1018  ACTION_AppSearchSigName(package, parentName, &parentSig, &parent);
1019  ACTION_FreeSignature(&parentSig);
1020  if (!parent)
1021  {
1022  msiobj_release(&row->hdr);
1023  return ERROR_SUCCESS;
1024  }
1025  }
1026 
1027  sz = MAX_PATH;
1028  MSI_RecordGetStringW(row, 3, path, &sz);
1029 
1030  if (MSI_RecordIsNull(row,4))
1031  depth = 0;
1032  else
1034 
1035  if (sz)
1036  ACTION_ExpandAnyPath(package, path, expanded, MAX_PATH);
1037  else
1038  strcpyW(expanded, path);
1039 
1040  if (parent)
1041  {
1043  if (attr != INVALID_FILE_ATTRIBUTES &&
1045  {
1048  }
1049 
1050  strcpyW(path, parent);
1051  strcatW(path, expanded);
1052  }
1053  else if (sz)
1054  strcpyW(path, expanded);
1055 
1057 
1058  rc = ACTION_SearchDirectory(package, sig, path, depth, appValue);
1059 
1060  msi_free(parent);
1061  msiobj_release(&row->hdr);
1062 
1063  TRACE("returning %d\n", rc);
1064  return rc;
1065 }
1066 
1068  MSISIGNATURE *sig, LPWSTR *appValue)
1069 {
1070  UINT rc;
1071 
1072  *appValue = NULL;
1073  rc = ACTION_AppSearchGetSignature(package, sig, sigName);
1074  if (rc == ERROR_SUCCESS)
1075  {
1076  rc = ACTION_AppSearchComponents(package, appValue, sig);
1077  if (rc == ERROR_SUCCESS && !*appValue)
1078  {
1079  rc = ACTION_AppSearchReg(package, appValue, sig);
1080  if (rc == ERROR_SUCCESS && !*appValue)
1081  {
1082  rc = ACTION_AppSearchIni(package, appValue, sig);
1083  if (rc == ERROR_SUCCESS && !*appValue)
1084  rc = ACTION_AppSearchDr(package, appValue, sig);
1085  }
1086  }
1087  }
1088  return rc;
1089 }
1090 
1092 {
1093  MSIPACKAGE *package = param;
1094  LPCWSTR propName, sigName;
1095  LPWSTR value = NULL;
1096  MSISIGNATURE sig;
1097  MSIRECORD *uirow;
1098  UINT r;
1099 
1100  /* get property and signature */
1101  propName = MSI_RecordGetString(row, 1);
1102  sigName = MSI_RecordGetString(row, 2);
1103 
1104  TRACE("%s %s\n", debugstr_w(propName), debugstr_w(sigName));
1105 
1106  r = ACTION_AppSearchSigName(package, sigName, &sig, &value);
1107  if (value)
1108  {
1109  r = msi_set_property( package->db, propName, value, -1 );
1110  if (r == ERROR_SUCCESS && !strcmpW( propName, szSourceDir ))
1111  msi_reset_folders( package, TRUE );
1112 
1113  msi_free(value);
1114  }
1115  ACTION_FreeSignature(&sig);
1116 
1117  uirow = MSI_CreateRecord( 2 );
1118  MSI_RecordSetStringW( uirow, 1, propName );
1119  MSI_RecordSetStringW( uirow, 2, sigName );
1121  msiobj_release( &uirow->hdr );
1122 
1123  return r;
1124 }
1125 
1127 {
1128  static const WCHAR query[] = {
1129  'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1130  'A','p','p','S','e','a','r','c','h',0};
1131  MSIQUERY *view;
1132  UINT r;
1133 
1134  if (msi_action_is_unique(package, szAppSearch))
1135  {
1136  TRACE("Skipping AppSearch action: already done in UI sequence\n");
1137  return ERROR_SUCCESS;
1138  }
1139  else
1141 
1142  r = MSI_OpenQuery( package->db, &view, query );
1143  if (r != ERROR_SUCCESS)
1144  return ERROR_SUCCESS;
1145 
1147  msiobj_release( &view->hdr );
1148  return r;
1149 }
1150 
1152 {
1153  MSIPACKAGE *package = param;
1154  LPCWSTR signature;
1155  LPWSTR value = NULL;
1156  MSISIGNATURE sig;
1157  UINT r = ERROR_SUCCESS;
1158 
1159  static const WCHAR success[] = {'C','C','P','_','S','u','c','c','e','s','s',0};
1160 
1161  signature = MSI_RecordGetString(row, 1);
1162 
1163  TRACE("%s\n", debugstr_w(signature));
1164 
1165  ACTION_AppSearchSigName(package, signature, &sig, &value);
1166  if (value)
1167  {
1168  TRACE("Found signature %s\n", debugstr_w(signature));
1169  msi_set_property( package->db, success, szOne, -1 );
1170  msi_free(value);
1172  }
1173 
1174  ACTION_FreeSignature(&sig);
1175 
1176  return r;
1177 }
1178 
1180 {
1181  static const WCHAR query[] = {
1182  'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1183  'C','C','P','S','e','a','r','c','h',0};
1184  MSIQUERY *view;
1185  UINT r;
1186 
1187  if (msi_action_is_unique(package, szCCPSearch))
1188  {
1189  TRACE("Skipping AppSearch action: already done in UI sequence\n");
1190  return ERROR_SUCCESS;
1191  }
1192  else
1194 
1195  r = MSI_OpenQuery(package->db, &view, query);
1196  if (r != ERROR_SUCCESS)
1197  return ERROR_SUCCESS;
1198 
1200  msiobj_release(&view->hdr);
1201  return r;
1202 }
#define HKEY_USERS
Definition: winreg.h:13
BOOL WINAPI FindNextFileW(IN HANDLE hFindFile, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:382
FILETIME MaxTime
Definition: appsearch.c:49
struct tagMSISIGNATURE MSISIGNATURE
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
#define max(a, b)
Definition: svc.c:63
BOOL WINAPI PathRemoveFileSpecW(LPWSTR lpszPath)
Definition: path.c:624
namespace GUID const ADDRINFOEXW ADDRINFOEXW struct timeval OVERLAPPED LPLOOKUPSERVICE_COMPLETION_ROUTINE HANDLE * handle
Definition: sock.c:82
INT WINAPI GetPrivateProfileStringW(LPCWSTR section, LPCWSTR entry, LPCWSTR def_val, LPWSTR buffer, UINT len, LPCWSTR filename)
Definition: profile.c:1142
#define TRUE
Definition: types.h:120
UINT MSI_RecordSetStringW(MSIRECORD *, UINT, LPCWSTR) DECLSPEC_HIDDEN
Definition: record.c:649
#define matches(FN)
Definition: match.h:70
static UINT ACTION_AppSearchGetSignature(MSIPACKAGE *package, MSISIGNATURE *sig, LPCWSTR name)
Definition: appsearch.c:84
WINE_UNICODE_INLINE unsigned int strlenW(const WCHAR *str)
Definition: unicode.h:212
#define ERROR_SUCCESS
Definition: deptool.c:10
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
static UINT ACTION_FileMatchesSig(const MSISIGNATURE *sig, const WIN32_FIND_DATAW *findData, LPCWSTR fullFilePath, BOOL *matches)
Definition: appsearch.c:748
#define ERROR_NO_MORE_ITEMS
Definition: compat.h:95
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
#define REG_BINARY
Definition: nt_native.h:1496
static WCHAR * strdupW(const WCHAR *src)
Definition: main.c:92
MSIOBJECTHDR hdr
Definition: msipriv.h:141
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
WINE_UNICODE_INLINE WCHAR * strchrW(const WCHAR *str, WCHAR ch)
Definition: unicode.h:248
GLuint GLuint GLsizei count
Definition: gl.h:1545
#define HKEY_CURRENT_USER
Definition: winreg.h:11
struct _root root
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG x1
Definition: winddi.h:3706
const GLint * first
Definition: glext.h:5794
#define WARN(fmt,...)
Definition: debug.h:111
UINT MSI_RecordGetStringW(MSIRECORD *, UINT, LPWSTR, LPDWORD) DECLSPEC_HIDDEN
Definition: record.c:487
UINT ACTION_AppSearch(MSIPACKAGE *package)
Definition: appsearch.c:1126
LPWSTR Languages
Definition: appsearch.c:50
BOOL msi_action_is_unique(const MSIPACKAGE *package, const WCHAR *action)
Definition: custom.c:112
static UINT ACTION_AppSearchDr(MSIPACKAGE *package, LPWSTR *appValue, MSISIGNATURE *sig)
Definition: appsearch.c:984
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
GLuint buffer
Definition: glext.h:5915
#define MSI_NULL_INTEGER
Definition: msiquery.h:32
GLuint GLuint end
Definition: gl.h:1545
WORD LANGID
Definition: typedefs.h:79
__u16 time
Definition: mkdosfs.c:366
Definition: parser.c:55
static BOOL match_languages(const void *version, const WCHAR *languages)
Definition: appsearch.c:653
static UINT ACTION_AppSearchComponents(MSIPACKAGE *package, LPWSTR *appValue, MSISIGNATURE *sig)
Definition: appsearch.c:230
#define lstrlenW
Definition: compat.h:407
static void * msi_realloc(void *mem, size_t len) __WINE_ALLOC_SIZE(2)
Definition: msipriv.h:1216
static IMAGE_SECTION_HEADER section
Definition: loader.c:152
#define lstrcpynW
Definition: compat.h:397
BOOL WINAPI PathAppendW(LPWSTR lpszPath, LPCWSTR lpszAppend)
Definition: path.c:121
static UINT ACTION_CheckDirectory(MSIPACKAGE *package, LPCWSTR dir, LPWSTR *appValue)
Definition: appsearch.c:886
struct _test_info info[]
Definition: SetCursorPos.c:19
static UINT ACTION_AppSearchSigName(MSIPACKAGE *package, LPCWSTR sigName, MSISIGNATURE *sig, LPWSTR *appValue)
Definition: appsearch.c:1067
void ls(int argc, const char *argv[])
Definition: cmds.c:1136
static void ACTION_ExpandAnyPath(MSIPACKAGE *package, WCHAR *src, WCHAR *dst, size_t len)
Definition: appsearch.c:593
UINT MSI_OpenQuery(MSIDATABASE *, MSIQUERY **, LPCWSTR,...) DECLSPEC_HIDDEN
Definition: msiquery.c:143
GLuint * ids
Definition: glext.h:5907
DWORD dwHighDateTime
Definition: mapidefs.h:66
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
const GUID * guid
static void ACTION_FreeSignature(MSISIGNATURE *sig)
Definition: appsearch.c:158
LONG WINAPI RegCloseKey(HKEY hKey)
Definition: reg.c:423
unsigned char * LPBYTE
Definition: typedefs.h:52
LPWSTR WINAPI PathAddBackslashW(LPWSTR lpszPath)
Definition: path.c:289
unsigned int BOOL
Definition: ntddk_ex.h:94
static UINT ACTION_AppSearchIni(MSIPACKAGE *package, LPWSTR *appValue, MSISIGNATURE *sig)
Definition: appsearch.c:523
BOOL MSI_RecordIsNull(MSIRECORD *, UINT) DECLSPEC_HIDDEN
Definition: record.c:369
DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName)
Definition: fileinfo.c:802
LONG WINAPI RegOpenKeyW(HKEY hKey, LPCWSTR lpSubKey, PHKEY phkResult)
Definition: reg.c:3311
#define debugstr_w
Definition: kernel32.h:32
INT MSI_ProcessMessage(MSIPACKAGE *, INSTALLMESSAGE, MSIRECORD *) DECLSPEC_HIDDEN
Definition: package.c:1946
static void ACTION_ConvertRegValue(DWORD regType, const BYTE *value, DWORD sz, LPWSTR *appValue)
Definition: appsearch.c:317
#define FIXME(fmt,...)
Definition: debug.h:110
static PVOID ptr
Definition: dispmode.c:27
int codepage
Definition: win_iconv.c:156
const WCHAR * str
WINE_DEFAULT_DEBUG_CHANNEL(msi)
smooth NULL
Definition: ftsmooth.c:416
static const WCHAR version[]
Definition: asmname.c:64
void msi_reset_folders(MSIPACKAGE *package, BOOL source) DECLSPEC_HIDDEN
Definition: package.c:2130
const WCHAR * MSI_RecordGetString(const MSIRECORD *, UINT) DECLSPEC_HIDDEN
Definition: record.c:482
unsigned int dir
Definition: maze.c:112
void msi_parse_version_string(LPCWSTR verStr, PDWORD ms, PDWORD ls)
Definition: appsearch.c:53
static UINT ACTION_FileVersionMatches(const MSISIGNATURE *sig, LPCWSTR filePath, BOOL *matches)
Definition: appsearch.c:688
GLuint GLfloat * val
Definition: glext.h:7180
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
WINE_UNICODE_INLINE WCHAR toupperW(WCHAR ch)
Definition: unicode.h:141
static const WCHAR lang[]
Definition: wbemdisp.c:287
DWORD deformat_string(MSIPACKAGE *package, const WCHAR *fmt, WCHAR **data)
Definition: format.c:1016
#define TRACE(s)
Definition: solgame.cpp:4
GLsizeiptr size
Definition: glext.h:5919
static const WCHAR szLangResource[]
Definition: msipriv.h:1196
INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf, LPDWORD pcchBuf)
Definition: msi.c:2471
LPCWSTR Name
Definition: appsearch.c:40
LONG WINAPI RegQueryValueExW(_In_ HKEY hkeyorg, _In_ LPCWSTR name, _In_ LPDWORD reserved, _In_ LPDWORD type, _In_ LPBYTE data, _In_ LPDWORD count)
Definition: reg.c:4134
r parent
Definition: btrfs.c:2659
__wchar_t WCHAR
Definition: xmlstorage.h:180
MSIRECORD * MSI_QueryGetRecord(MSIDATABASE *db, LPCWSTR query,...) DECLSPEC_HIDDEN
Definition: msiquery.c:206
BOOL WINAPI DosDateTimeToFileTime(IN WORD wFatDate, IN WORD wFatTime, OUT LPFILETIME lpFileTime)
Definition: time.c:75
Definition: parser.c:43
UINT ACTION_CCPSearch(MSIPACKAGE *package)
Definition: appsearch.c:1179
GLfloat param
Definition: glext.h:5796
#define MAX_PATH
Definition: compat.h:26
static UINT ACTION_RecurseSearchDirectory(MSIPACKAGE *package, LPWSTR *appValue, MSISIGNATURE *sig, LPCWSTR dir, int depth)
Definition: appsearch.c:793
unsigned long DWORD
Definition: ntddk_ex.h:95
MSIDATABASE * db
Definition: msipriv.h:386
#define success(from, fromstr, to, tostr)
Definition: cookie.c:170
GLdouble GLdouble GLdouble GLdouble q
Definition: gl.h:2063
#define INVALID_FILE_ATTRIBUTES
Definition: vfdcmd.c:23
int msiobj_release(MSIOBJECTHDR *info)
Definition: handle.c:242
static const WCHAR szSourceDir[]
Definition: msipriv.h:1100
static UINT ACTION_AppSearchReg(MSIPACKAGE *package, LPWSTR *appValue, MSISIGNATURE *sig)
Definition: appsearch.c:371
GLint GLint GLsizei GLsizei GLsizei depth
Definition: gl.h:1546
static double zero
Definition: j0_y0.c:96
int ret
MSIRECORD * MSI_CreateRecord(UINT) DECLSPEC_HIDDEN
Definition: record.c:79
static const WCHAR szAppSearch[]
Definition: msipriv.h:1151
__u8 attr
Definition: mkdosfs.c:359
DWORD WINAPI GetFileVersionInfoSizeW(LPCWSTR filename, LPDWORD handle)
Definition: version.c:616
HKEY key
Definition: reg.c:42
static const WCHAR szDot[]
Definition: msipriv.h:1113
GLenum GLsizei len
Definition: glext.h:6722
unsigned char BYTE
Definition: mem.h:68
GLenum src
Definition: glext.h:6340
UINT WINAPI GetDriveTypeW(IN LPCWSTR lpRootPathName)
Definition: disk.c:497
static BOOL ACTION_IsFullPath(LPCWSTR path)
Definition: appsearch.c:900
DWORD MinVersionMS
Definition: appsearch.c:42
#define DRIVE_FIXED
Definition: winbase.h:249
static UINT iterate_appsearch(MSIRECORD *row, LPVOID param)
Definition: appsearch.c:1091
WINE_UNICODE_INLINE WCHAR * strrchrW(const WCHAR *str, WCHAR ch)
Definition: unicode.h:254
DWORD WINAPI GetLogicalDrives(VOID)
Definition: disk.c:110
int MSI_RecordGetInteger(MSIRECORD *, UINT) DECLSPEC_HIDDEN
Definition: record.c:245
WINE_UNICODE_INLINE WCHAR * strcpyW(WCHAR *dst, const WCHAR *src)
Definition: unicode.h:219
#define lstrcpyW
Definition: compat.h:406
unsigned short USHORT
Definition: pedump.c:61
static LANGID * parse_languages(const WCHAR *languages, DWORD *num_ids)
Definition: appsearch.c:624
WCHAR * msi_dup_record_field(MSIRECORD *row, INT index) DECLSPEC_HIDDEN
Definition: record.c:1055
#define REG_EXPAND_SZ
Definition: nt_native.h:1494
static LPWSTR app_search_file(LPWSTR path, MSISIGNATURE *sig)
Definition: appsearch.c:164
Definition: services.c:325
GLenum GLenum dst
Definition: glext.h:6340
#define sprintfW
Definition: unicode.h:58
WINE_UNICODE_INLINE WCHAR * strcatW(WCHAR *dst, const WCHAR *src)
Definition: unicode.h:242
static const WCHAR szOne[]
Definition: msipriv.h:1108
FILETIME MinTime
Definition: appsearch.c:48
DWORD MaxVersionLS
Definition: appsearch.c:45
unsigned int UINT
Definition: ndis.h:50
static const WCHAR szBackSlash[]
Definition: msipriv.h:1111
DWORD WINAPI ExpandEnvironmentStringsW(IN LPCWSTR lpSrc, IN LPWSTR lpDst, IN DWORD nSize)
Definition: environ.c:519
UINT msi_set_property(MSIDATABASE *, const WCHAR *, const WCHAR *, int) DECLSPEC_HIDDEN
Definition: package.c:2149
DWORD * PDWORD
Definition: pedump.c:68
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG _In_ LONG _In_ LONG x2
Definition: winddi.h:3706
BOOL WINAPI GetFileVersionInfoW(LPCWSTR filename, DWORD handle, DWORD datasize, LPVOID data)
Definition: version.c:850
DWORD MinVersionLS
Definition: appsearch.c:43
static const WCHAR szCCPSearch[]
Definition: msipriv.h:1153
static BOOL msi_free(void *mem)
Definition: msipriv.h:1227
Definition: name.c:36
WINE_UNICODE_INLINE int strcmpW(const WCHAR *str1, const WCHAR *str2)
Definition: unicode.h:229
static LPWSTR get_ini_field(LPWSTR buf, int field)
Definition: appsearch.c:497
static UINT ITERATE_CCPSearch(MSIRECORD *row, LPVOID param)
Definition: appsearch.c:1151
static void * msi_alloc(size_t len) __WINE_ALLOC_SIZE(1)
Definition: msipriv.h:1204
#define HIWORD(l)
Definition: typedefs.h:246
GLenum GLuint id
Definition: glext.h:5579
static IOleDocumentView * view
Definition: activex.c:1749
static UINT ACTION_SearchDirectory(MSIPACKAGE *package, MSISIGNATURE *sig, LPCWSTR path, int depth, LPWSTR *appValue)
Definition: appsearch.c:914
#define HKEY_CLASSES_ROOT
Definition: winreg.h:10
LPWSTR WINAPI lstrcatW(LPWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:274
GLfloat GLfloat p
Definition: glext.h:8902
WCHAR * LPWSTR
Definition: xmlstorage.h:184
static const WCHAR szDotDot[]
Definition: msipriv.h:1114
UINT MSI_IterateRecords(MSIQUERY *, LPDWORD, record_func, LPVOID) DECLSPEC_HIDDEN
Definition: msiquery.c:168
#define memset(x, y, z)
Definition: compat.h:39
#define REG_DWORD
Definition: sdbapi.c:596
#define LOWORD(l)
Definition: pedump.c:82
DWORD MaxVersionMS
Definition: appsearch.c:44
DWORD dwLowDateTime
Definition: mapidefs.h:65
#define ERROR_OUTOFMEMORY
Definition: deptool.c:13
WINE_UNICODE_INLINE int atoiW(const WCHAR *str)
Definition: unicode.h:315
struct png_info_def *typedef unsigned char **typedef struct png_info_def *typedef struct png_info_def *typedef struct png_info_def *typedef unsigned char ** row
Definition: typeof.h:78
Definition: path.c:42
HANDLE WINAPI FindFirstFileW(IN LPCWSTR lpFileName, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:320
UINT msi_register_unique_action(MSIPACKAGE *package, const WCHAR *action)
Definition: custom.c:94
BOOL WINAPI VerQueryValueW(LPCVOID pBlock, LPCWSTR lpSubBlock, LPVOID *lplpBuffer, PUINT puLen)
Definition: version.c:1054
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
#define REG_SZ
Definition: layer.c:22
BOOL WINAPI FindClose(HANDLE hFindFile)
Definition: find.c:502
GLuint const GLchar * name
Definition: glext.h:6031