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