ea61555539861c81732fc2f041b8ff10dfd5be83
[reactos.git] / dll / appcompat / apphelp / hsdb.c
1 /*
2 * PROJECT: ReactOS Application compatibility module
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Shim matching / data (un)packing
5 * COPYRIGHT: Copyright 2011 André Hentschel
6 * Copyright 2013 Mislav Blaževic
7 * Copyright 2015-2017 Mark Jansen (mark.jansen@reactos.org)
8 */
9
10 #define WIN32_NO_STATUS
11 #include "windows.h"
12 #include "ntndk.h"
13 #include "strsafe.h"
14 #include "apphelp.h"
15
16
17 #define MAX_LAYER_LENGTH 256
18 #define GPLK_USER 1
19 #define GPLK_MACHINE 2
20
21 typedef struct _ShimData
22 {
23 WCHAR szModule[MAX_PATH];
24 DWORD dwSize;
25 DWORD dwMagic;
26 SDBQUERYRESULT Query;
27 WCHAR szLayer[MAX_LAYER_LENGTH];
28 DWORD unknown; // 0x14c
29 } ShimData;
30
31 #define SHIMDATA_MAGIC 0xAC0DEDAB
32
33
34 static BOOL WINAPI SdbpFileExists(LPCWSTR path)
35 {
36 DWORD attr = GetFileAttributesW(path);
37 return (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY));
38 }
39
40 /* Given a 'MATCHING_FILE' tag and an ATTRINFO array,
41 check all tags defined in the MATCHING_FILE against the ATTRINFO */
42 static BOOL SdbpMatchFileAttributes(PDB pdb, TAGID matching_file, PATTRINFO attribs, DWORD attr_count)
43 {
44 TAGID child;
45
46 for (child = SdbGetFirstChild(pdb, matching_file);
47 child != TAGID_NULL; child = SdbGetNextChild(pdb, matching_file, child))
48 {
49 TAG tag = SdbGetTagFromTagID(pdb, child);
50 DWORD n;
51
52 /* Already handled! */
53 if (tag == TAG_NAME)
54 continue;
55
56 if (tag == TAG_UPTO_BIN_FILE_VERSION ||
57 tag == TAG_UPTO_BIN_PRODUCT_VERSION ||
58 tag == TAG_UPTO_LINK_DATE)
59 {
60 SHIM_WARN("Unimplemented TAG_UPTO_XXXXX\n");
61 continue;
62 }
63
64 for (n = 0; n < attr_count; ++n)
65 {
66 PATTRINFO attr = attribs + n;
67 if (attr->flags == ATTRIBUTE_AVAILABLE && attr->type == tag)
68 {
69 DWORD dwval;
70 WCHAR* lpval;
71 QWORD qwval;
72 switch (tag & TAG_TYPE_MASK)
73 {
74 case TAG_TYPE_DWORD:
75 dwval = SdbReadDWORDTag(pdb, child, 0);
76 if (dwval != attr->dwattr)
77 return FALSE;
78 break;
79 case TAG_TYPE_STRINGREF:
80 lpval = SdbGetStringTagPtr(pdb, child);
81 if (!lpval || wcsicmp(attr->lpattr, lpval))
82 return FALSE;
83 break;
84 case TAG_TYPE_QWORD:
85 qwval = SdbReadQWORDTag(pdb, child, 0);
86 if (qwval != attr->qwattr)
87 return FALSE;
88 break;
89 default:
90 SHIM_WARN("Unhandled type 0x%x MATCHING_FILE\n", (tag & TAG_TYPE_MASK));
91 return FALSE;
92 }
93 }
94 }
95 if (n == attr_count)
96 SHIM_WARN("Unhandled tag %ws in MACHING_FILE\n", SdbTagToString(tag));
97 }
98 return TRUE;
99 }
100
101 /* Given an 'exe' tag and an ATTRINFO array (for the main file),
102 verify that the main file and any additional files match */
103 static BOOL WINAPI SdbpMatchExe(PDB pdb, TAGID exe, const WCHAR* dir, PATTRINFO main_attribs, DWORD main_attr_count)
104 {
105 RTL_UNICODE_STRING_BUFFER FullPathName = { { 0 } };
106 WCHAR FullPathBuffer[MAX_PATH];
107 UNICODE_STRING UnicodeDir;
108 TAGID matching_file;
109 PATTRINFO attribs = NULL;
110 DWORD attr_count;
111 BOOL IsMatch = FALSE;
112
113 RtlInitUnicodeString(&UnicodeDir, dir);
114 RtlInitBuffer(&FullPathName.ByteBuffer, (PUCHAR)FullPathBuffer, sizeof(FullPathBuffer));
115
116 for (matching_file = SdbFindFirstTag(pdb, exe, TAG_MATCHING_FILE);
117 matching_file != TAGID_NULL; matching_file = SdbFindNextTag(pdb, exe, matching_file))
118 {
119 TAGID tagName = SdbFindFirstTag(pdb, matching_file, TAG_NAME);
120 UNICODE_STRING Name;
121 USHORT Len;
122
123 RtlInitUnicodeString(&Name, SdbGetStringTagPtr(pdb, tagName));
124
125 if (!Name.Buffer)
126 goto Cleanup;
127
128 /* An '*' here means use the main executable' */
129 if (!wcscmp(Name.Buffer, L"*"))
130 {
131 /* We already have these attributes, so we do not need to retrieve them */
132 if (!SdbpMatchFileAttributes(pdb, matching_file, main_attribs, main_attr_count))
133 goto Cleanup;
134 continue;
135 }
136
137 /* Technically, one UNICODE_NULL and one path separator. */
138 Len = UnicodeDir.Length + Name.Length + sizeof(UNICODE_NULL) + sizeof(UNICODE_NULL);
139 if (!NT_SUCCESS(RtlEnsureBufferSize(RTL_SKIP_BUFFER_COPY, &FullPathName.ByteBuffer, Len)))
140 goto Cleanup;
141
142 if (Len > FullPathName.ByteBuffer.Size)
143 goto Cleanup;
144
145 RtlInitEmptyUnicodeString(&FullPathName.String, (PWCHAR)FullPathName.ByteBuffer.Buffer, FullPathName.ByteBuffer.Size);
146
147 RtlCopyUnicodeString(&FullPathName.String, &UnicodeDir);
148 RtlAppendUnicodeToString(&FullPathName.String, L"\\");
149 RtlAppendUnicodeStringToString(&FullPathName.String, &Name);
150
151 /* If the file does not exist, do not bother trying to read it's attributes */
152 if (!SdbpFileExists(FullPathName.String.Buffer))
153 goto Cleanup;
154
155 /* Do we have some attributes from the previous iteration? */
156 if (attribs)
157 SdbFreeFileAttributes(attribs);
158
159 if (!SdbGetFileAttributes(FullPathName.String.Buffer, &attribs, &attr_count))
160 goto Cleanup;
161
162 if (!SdbpMatchFileAttributes(pdb, matching_file, attribs, attr_count))
163 goto Cleanup;
164 }
165
166 IsMatch = TRUE;
167
168 Cleanup:
169 RtlFreeBuffer(&FullPathName.ByteBuffer);
170 if (attribs)
171 SdbFreeFileAttributes(attribs);
172
173 return IsMatch;
174 }
175
176 /* Add a database guid to the query result */
177 static void SdbpAddDatabaseGuid(PDB pdb, PSDBQUERYRESULT result)
178 {
179 size_t n;
180
181 for (n = 0; n < _countof(result->rgGuidDB); ++n)
182 {
183 if (!memcmp(&result->rgGuidDB[n], &pdb->database_id, sizeof(pdb->database_id)))
184 return;
185
186 if (result->dwCustomSDBMap & (1<<n))
187 continue;
188
189 memcpy(&result->rgGuidDB[n], &pdb->database_id, sizeof(result->rgGuidDB[n]));
190 result->dwCustomSDBMap |= (1<<n);
191 return;
192 }
193 }
194
195 /* Add one layer to the query result */
196 static BOOL SdbpAddSingleLayerMatch(TAGREF layer, PSDBQUERYRESULT result)
197 {
198 size_t n;
199
200 for (n = 0; n < result->dwLayerCount; ++n)
201 {
202 if (result->atrLayers[n] == layer)
203 return FALSE;
204 }
205
206 if (n >= _countof(result->atrLayers))
207 return FALSE;
208
209 result->atrLayers[n] = layer;
210 result->dwLayerCount++;
211
212 return TRUE;
213 }
214
215 /* Translate a layer name to a tagref + add it to the query result */
216 static BOOL SdbpAddNamedLayerMatch(HSDB hsdb, PCWSTR layerName, PSDBQUERYRESULT result)
217 {
218 TAGID database, layer;
219 TAGREF tr;
220 PDB pdb = hsdb->pdb;
221
222 database = SdbFindFirstTag(pdb, TAGID_ROOT, TAG_DATABASE);
223 if (database == TAGID_NULL)
224 return FALSE;
225
226 layer = SdbFindFirstNamedTag(pdb, database, TAG_LAYER, TAG_NAME, layerName);
227 if (layer == TAGID_NULL)
228 return FALSE;
229
230 if (!SdbTagIDToTagRef(hsdb, pdb, layer, &tr))
231 return FALSE;
232
233 if (!SdbpAddSingleLayerMatch(tr, result))
234 return FALSE;
235
236 SdbpAddDatabaseGuid(pdb, result);
237 return TRUE;
238 }
239
240 /* Add all layers for the exe tag to the query result */
241 static void SdbpAddExeLayers(HSDB hsdb, PDB pdb, TAGID tagExe, PSDBQUERYRESULT result)
242 {
243 TAGID layer = SdbFindFirstTag(pdb, tagExe, TAG_LAYER);
244
245 while (layer != TAGID_NULL)
246 {
247 TAGREF tr;
248 TAGID layerIdTag = SdbFindFirstTag(pdb, layer, TAG_LAYER_TAGID);
249 DWORD tagId = SdbReadDWORDTag(pdb, layerIdTag, TAGID_NULL);
250
251 if (layerIdTag != TAGID_NULL &&
252 tagId != TAGID_NULL &&
253 SdbTagIDToTagRef(hsdb, pdb, tagId, &tr))
254 {
255 SdbpAddSingleLayerMatch(tr, result);
256 }
257 else
258 {
259 /* Try a name lookup */
260 TAGID layerTag = SdbFindFirstTag(pdb, layer, TAG_NAME);
261 if (layerTag != TAGID_NULL)
262 {
263 LPCWSTR layerName = SdbGetStringTagPtr(pdb, layerTag);
264 if (layerName)
265 {
266 SdbpAddNamedLayerMatch(hsdb, layerName, result);
267 }
268 }
269 }
270
271 layer = SdbFindNextTag(pdb, tagExe, layer);
272 }
273 }
274
275 /* Add an exe tag to the query result */
276 static void SdbpAddExeMatch(HSDB hsdb, PDB pdb, TAGID tagExe, PSDBQUERYRESULT result)
277 {
278 size_t n;
279 TAGREF tr;
280
281 if (!SdbTagIDToTagRef(hsdb, pdb, tagExe, &tr))
282 return;
283
284 for (n = 0; n < result->dwExeCount; ++n)
285 {
286 if (result->atrExes[n] == tr)
287 return;
288 }
289
290 if (n >= _countof(result->atrExes))
291 return;
292
293 result->atrExes[n] = tr;
294 result->dwExeCount++;
295
296 SdbpAddExeLayers(hsdb, pdb, tagExe, result);
297
298 SdbpAddDatabaseGuid(pdb, result);
299 }
300
301 /* Add all named layers to the query result */
302 static ULONG SdbpAddLayerMatches(HSDB hsdb, PWSTR pwszLayers, DWORD pdwBytes, PSDBQUERYRESULT result)
303 {
304 PWSTR start = pwszLayers, p;
305 ULONG Added = 0;
306
307 const PWSTR end = pwszLayers + (pdwBytes / sizeof(WCHAR));
308 while (start < end && (*start == L'!' || *start == L'#' || *start == L' ' || *start == L'\t'))
309 start++;
310
311 if (start == end)
312 return 0;
313
314 do
315 {
316 while (*start == L' ' || *start == L'\t')
317 ++start;
318
319 if (*start == UNICODE_NULL)
320 break;
321 p = wcspbrk(start, L" \t");
322
323 if (p)
324 *p = UNICODE_NULL;
325
326 if (SdbpAddNamedLayerMatch(hsdb, start, result))
327 Added++;
328
329 start = p + 1;
330 } while (start < end && p);
331
332 return Added;
333 }
334
335 static BOOL SdbpPropagateEnvLayers(HSDB hsdb, LPWSTR Environment, PSDBQUERYRESULT Result)
336 {
337 static const UNICODE_STRING EnvKey = RTL_CONSTANT_STRING(L"__COMPAT_LAYER");
338 UNICODE_STRING EnvValue;
339 NTSTATUS Status;
340 WCHAR Buffer[MAX_LAYER_LENGTH];
341
342 RtlInitEmptyUnicodeString(&EnvValue, Buffer, sizeof(Buffer));
343
344 Status = RtlQueryEnvironmentVariable_U(Environment, &EnvKey, &EnvValue);
345
346 if (!NT_SUCCESS(Status))
347 return FALSE;
348
349 return SdbpAddLayerMatches(hsdb, Buffer, EnvValue.Length, Result) > 0;
350 }
351
352
353
354 /**
355 * Opens specified shim database file. Handle returned by this function may only be used by
356 * functions which take HSDB param thus differing it from SdbOpenDatabase.
357 *
358 * @param [in] flags Specifies type of path or predefined database.
359 * @param [in] path Path to the shim database file.
360 *
361 * @return Success: Handle to the opened shim database, NULL otherwise.
362 */
363 HSDB WINAPI SdbInitDatabase(DWORD flags, LPCWSTR path)
364 {
365 static const WCHAR shim[] = {'\\','s','y','s','m','a','i','n','.','s','d','b',0};
366 static const WCHAR msi[] = {'\\','m','s','i','m','a','i','n','.','s','d','b',0};
367 static const WCHAR drivers[] = {'\\','d','r','v','m','a','i','n','.','s','d','b',0};
368 LPCWSTR name;
369 WCHAR buffer[128];
370 HSDB hsdb;
371
372 hsdb = SdbAlloc(sizeof(SDB));
373 if (!hsdb)
374 return NULL;
375 hsdb->auto_loaded = 0;
376
377 /* Check for predefined databases */
378 if ((flags & HID_DATABASE_TYPE_MASK) && path == NULL)
379 {
380 switch (flags & HID_DATABASE_TYPE_MASK)
381 {
382 case SDB_DATABASE_MAIN_SHIM: name = shim; break;
383 case SDB_DATABASE_MAIN_MSI: name = msi; break;
384 case SDB_DATABASE_MAIN_DRIVERS: name = drivers; break;
385 default:
386 SdbReleaseDatabase(hsdb);
387 return NULL;
388 }
389 SdbGetAppPatchDir(NULL, buffer, _countof(buffer));
390 StringCchCatW(buffer, _countof(buffer), name);
391 flags = HID_DOS_PATHS;
392 }
393
394 hsdb->pdb = SdbOpenDatabase(path ? path : buffer, (flags & 0xF) - 1);
395
396 /* If database could not be loaded, a handle doesn't make sense either */
397 if (!hsdb->pdb)
398 {
399 SdbReleaseDatabase(hsdb);
400 return NULL;
401 }
402
403 return hsdb;
404 }
405
406 /**
407 * Closes shim database opened by SdbInitDatabase.
408 *
409 * @param [in] hsdb Handle to the shim database.
410 */
411 void WINAPI SdbReleaseDatabase(HSDB hsdb)
412 {
413 SdbCloseDatabase(hsdb->pdb);
414 SdbFree(hsdb);
415 }
416
417 /**
418 * Queries database for a specified exe If hsdb is NULL default database shall be loaded and
419 * searched.
420 *
421 * @param [in] hsdb Handle to the shim database.
422 * @param [in] path Path to executable for which we query database.
423 * @param [in] module_name Unused.
424 * @param [in] env The environment block to use
425 * @param [in] flags 0 or SDBGMEF_IGNORE_ENVIRONMENT.
426 * @param [out] result Pointer to structure in which query result shall be stored.
427 *
428 * @return TRUE if it succeeds, FALSE if it fails.
429 */
430 BOOL WINAPI SdbGetMatchingExe(HSDB hsdb, LPCWSTR path, LPCWSTR module_name,
431 LPCWSTR env, DWORD flags, PSDBQUERYRESULT result)
432 {
433 BOOL ret = FALSE;
434 TAGID database, iter, name;
435 PATTRINFO attribs = NULL;
436 DWORD attr_count;
437 RTL_UNICODE_STRING_BUFFER DosApplicationName = { { 0 } };
438 WCHAR DosPathBuffer[MAX_PATH];
439 ULONG PathType = 0;
440 LPWSTR file_name;
441 WCHAR wszLayers[MAX_LAYER_LENGTH];
442 DWORD dwSize;
443 PDB pdb;
444
445 /* Load default database if one is not specified */
446 if (!hsdb)
447 {
448 /* To reproduce windows behaviour HID_DOS_PATHS needs
449 * to be specified when loading default database */
450 hsdb = SdbInitDatabase(HID_DOS_PATHS | SDB_DATABASE_MAIN_SHIM, NULL);
451 if (hsdb)
452 hsdb->auto_loaded = TRUE;
453 }
454
455 ZeroMemory(result, sizeof(*result));
456
457 /* No database could be loaded */
458 if (!hsdb || !path)
459 return FALSE;
460
461 /* We do not support multiple db's yet! */
462 pdb = hsdb->pdb;
463
464 RtlInitUnicodeString(&DosApplicationName.String, path);
465 RtlInitBuffer(&DosApplicationName.ByteBuffer, (PUCHAR)DosPathBuffer, sizeof(DosPathBuffer));
466 if (!NT_SUCCESS(RtlEnsureBufferSize(RTL_SKIP_BUFFER_COPY, &DosApplicationName.ByteBuffer, DosApplicationName.String.MaximumLength)))
467 {
468 SHIM_ERR("Failed to convert allocate buffer.");
469 goto Cleanup;
470 }
471 /* Update the internal buffer to contain the string */
472 memcpy(DosApplicationName.ByteBuffer.Buffer, path, DosApplicationName.String.MaximumLength);
473 /* Make sure the string uses our internal buffer (we want to modify the buffer,
474 and RtlNtPathNameToDosPathName does not always modify the String to point to the Buffer)! */
475 DosApplicationName.String.Buffer = (PWSTR)DosApplicationName.ByteBuffer.Buffer;
476
477 if (!NT_SUCCESS(RtlNtPathNameToDosPathName(0, &DosApplicationName, &PathType, NULL)))
478 {
479 SHIM_ERR("Failed to convert %S to DOS Path.", path);
480 goto Cleanup;
481 }
482
483
484 /* Extract file name */
485 file_name = wcsrchr(DosApplicationName.String.Buffer, '\\');
486 if (!file_name)
487 {
488 SHIM_ERR("Failed to find Exe name in %wZ.", &DosApplicationName.String);
489 goto Cleanup;
490 }
491
492 /* We will use the buffer for exe name and directory. */
493 *(file_name++) = UNICODE_NULL;
494
495 /* DATABASE is list TAG which contains all executables */
496 database = SdbFindFirstTag(pdb, TAGID_ROOT, TAG_DATABASE);
497 if (database == TAGID_NULL)
498 {
499 goto Cleanup;
500 }
501
502 /* EXE is list TAG which contains data required to match executable */
503 iter = SdbFindFirstTag(pdb, database, TAG_EXE);
504
505 /* Search for entry in database, we should look into indexing tags! */
506 while (iter != TAGID_NULL)
507 {
508 LPWSTR foundName;
509 /* Check if exe name matches */
510 name = SdbFindFirstTag(pdb, iter, TAG_NAME);
511 /* If this is a malformed DB, (no TAG_NAME), we should not crash. */
512 foundName = SdbGetStringTagPtr(pdb, name);
513 if (foundName && !wcsicmp(foundName, file_name))
514 {
515 /* Get information about executable required to match it with database entry */
516 if (!attribs)
517 {
518 if (!SdbGetFileAttributes(path, &attribs, &attr_count))
519 goto Cleanup;
520 }
521
522
523 /* We have a null terminator before the application name, so DosApplicationName only contains the path. */
524 if (SdbpMatchExe(pdb, iter, DosApplicationName.String.Buffer, attribs, attr_count))
525 {
526 ret = TRUE;
527 SdbpAddExeMatch(hsdb, pdb, iter, result);
528 }
529 }
530
531 /* Continue iterating */
532 iter = SdbFindNextTag(pdb, database, iter);
533 }
534
535 /* Restore the full path. */
536 *(--file_name) = L'\\';
537
538 dwSize = sizeof(wszLayers);
539 if (SdbGetPermLayerKeys(DosApplicationName.String.Buffer, wszLayers, &dwSize, GPLK_MACHINE | GPLK_USER))
540 {
541 SdbpAddLayerMatches(hsdb, wszLayers, dwSize, result);
542 ret = TRUE;
543 }
544
545 if (!(flags & SDBGMEF_IGNORE_ENVIRONMENT))
546 {
547 if (SdbpPropagateEnvLayers(hsdb, (LPWSTR)env, result))
548 {
549 ret = TRUE;
550 result->dwFlags |= SHIMREG_HAS_ENVIRONMENT;
551 }
552 }
553
554 Cleanup:
555 RtlFreeBuffer(&DosApplicationName.ByteBuffer);
556 if (attribs)
557 SdbFreeFileAttributes(attribs);
558 if (hsdb->auto_loaded)
559 SdbReleaseDatabase(hsdb);
560 return ret;
561 }
562
563 /**
564 * Retrieves AppPatch directory.
565 *
566 * @param [in] pdb Handle to the shim database.
567 * @param [out] path Pointer to memory in which path shall be written.
568 * @param [in] size Size of the buffer in characters.
569 */
570 BOOL WINAPI SdbGetAppPatchDir(HSDB hsdb, LPWSTR path, DWORD size)
571 {
572 static WCHAR* default_dir = NULL;
573 static CONST WCHAR szAppPatch[] = {'\\','A','p','p','P','a','t','c','h',0};
574
575 /* In case function fails, path holds empty string */
576 if (size > 0)
577 *path = 0;
578
579 if (!default_dir)
580 {
581 WCHAR* tmp;
582 UINT len = GetSystemWindowsDirectoryW(NULL, 0) + SdbpStrlen(szAppPatch);
583 tmp = SdbAlloc((len + 1)* sizeof(WCHAR));
584 if (tmp)
585 {
586 UINT r = GetSystemWindowsDirectoryW(tmp, len+1);
587 if (r && r < len)
588 {
589 if (SUCCEEDED(StringCchCatW(tmp, len+1, szAppPatch)))
590 {
591 if (InterlockedCompareExchangePointer((void**)&default_dir, tmp, NULL) == NULL)
592 tmp = NULL;
593 }
594 }
595 if (tmp)
596 SdbFree(tmp);
597 }
598 if (!default_dir)
599 {
600 SHIM_ERR("Unable to obtain default AppPatch directory\n");
601 return FALSE;
602 }
603 }
604
605 if (!hsdb)
606 {
607 return SUCCEEDED(StringCchCopyW(path, size, default_dir));
608 }
609 else
610 {
611 SHIM_ERR("Unimplemented for hsdb != NULL\n");
612 return FALSE;
613 }
614 }
615
616
617 /**
618 * Translates the given trWhich to a specific database / tagid
619 *
620 * @param [in] hsdb Handle to the database.
621 * @param [in] trWhich Tagref to find
622 * @param [out,opt] ppdb The Shim database that trWhich belongs to.
623 * @param [out,opt] ptiWhich The tagid that trWhich corresponds to.
624 *
625 * @return TRUE if it succeeds, FALSE if it fails.
626 */
627 BOOL WINAPI SdbTagRefToTagID(HSDB hsdb, TAGREF trWhich, PDB* ppdb, TAGID* ptiWhich)
628 {
629 if (trWhich & 0xf0000000)
630 {
631 SHIM_ERR("Multiple shim databases not yet implemented!\n");
632 if (ppdb)
633 *ppdb = NULL;
634 if (ptiWhich)
635 *ptiWhich = TAG_NULL;
636 return FALSE;
637 }
638
639 /* There seems to be no range checking on trWhich.. */
640 if (ppdb)
641 *ppdb = hsdb->pdb;
642 if (ptiWhich)
643 *ptiWhich = trWhich & 0x0fffffff;
644
645 return TRUE;
646 }
647
648 /**
649 * Translates the given trWhich to a specific database / tagid
650 *
651 * @param [in] hsdb Handle to the database.
652 * @param [in] pdb The Shim database that tiWhich belongs to.
653 * @param [in] tiWhich Path to executable for which we query database.
654 * @param [out,opt] ptrWhich The tagid that tiWhich corresponds to.
655 *
656 * @return TRUE if it succeeds, FALSE if it fails.
657 */
658 BOOL WINAPI SdbTagIDToTagRef(HSDB hsdb, PDB pdb, TAGID tiWhich, TAGREF* ptrWhich)
659 {
660 if (pdb != hsdb->pdb)
661 {
662 SHIM_ERR("Multiple shim databases not yet implemented!\n");
663 if (ptrWhich)
664 *ptrWhich = TAGREF_NULL;
665 return FALSE;
666 }
667
668 if (ptrWhich)
669 *ptrWhich = tiWhich & 0x0fffffff;
670
671 return TRUE;
672 }
673
674
675 /* Convert a query result to shim data that will be loaded in the child process */
676 BOOL WINAPI SdbPackAppCompatData(HSDB hsdb, PSDBQUERYRESULT pQueryResult, PVOID* ppData, DWORD *pdwSize)
677 {
678 ShimData* pData;
679 HRESULT hr;
680 DWORD n;
681
682 if (!pQueryResult || !ppData || !pdwSize)
683 {
684 SHIM_WARN("Invalid params: %p, %p, %p\n", pQueryResult, ppData, pdwSize);
685 return FALSE;
686 }
687
688 pData = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ShimData));
689 if (!pData)
690 {
691 SHIM_WARN("Unable to allocate %d bytes\n", sizeof(ShimData));
692 return FALSE;
693 }
694
695 GetSystemWindowsDirectoryW(pData->szModule, _countof(pData->szModule));
696 hr = StringCchCatW(pData->szModule, _countof(pData->szModule), L"\\system32\\apphelp.dll");
697 if (!SUCCEEDED(hr))
698 {
699 SHIM_ERR("Unable to append module name (0x%x)\n", hr);
700 RtlFreeHeap(RtlGetProcessHeap(), 0, pData);
701 return FALSE;
702 }
703
704 pData->dwSize = sizeof(*pData);
705 pData->dwMagic = SHIMDATA_MAGIC;
706 pData->Query = *pQueryResult;
707 pData->unknown = 0;
708 pData->szLayer[0] = UNICODE_NULL; /* TODO */
709
710 SHIM_INFO("\ndwFlags 0x%x\ndwMagic 0x%x\ntrExe 0x%x\ntrLayer 0x%x\n",
711 pData->Query.dwFlags, pData->dwMagic, pData->Query.atrExes[0], pData->Query.atrLayers[0]);
712
713 /* Database List */
714 /* 0x0 {GUID} NAME */
715
716 for (n = 0; n < pQueryResult->dwLayerCount; ++n)
717 {
718 SHIM_INFO("Layer 0x%x\n", pQueryResult->atrLayers[n]);
719 }
720
721 *ppData = pData;
722 *pdwSize = pData->dwSize;
723
724 return TRUE;
725 }
726
727 BOOL WINAPI SdbUnpackAppCompatData(HSDB hsdb, LPCWSTR pszImageName, PVOID pData, PSDBQUERYRESULT pQueryResult)
728 {
729 ShimData* pShimData = pData;
730
731 if (!pShimData || pShimData->dwMagic != SHIMDATA_MAGIC || pShimData->dwSize < sizeof(ShimData))
732 return FALSE;
733
734 if (!pQueryResult)
735 return FALSE;
736
737 /* szLayer? */
738
739 *pQueryResult = pShimData->Query;
740 return TRUE;
741 }
742
743 DWORD WINAPI SdbGetAppCompatDataSize(ShimData* pData)
744 {
745 if (!pData || pData->dwMagic != SHIMDATA_MAGIC)
746 return 0;
747
748
749 return pData->dwSize;
750 }
751