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-2018 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 HRESULT 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 HRESULT hr = E_FAIL; 583 UINT len = GetSystemWindowsDirectoryW(NULL, 0) + SdbpStrlen(szAppPatch); 584 tmp = SdbAlloc((len + 1)* sizeof(WCHAR)); 585 if (tmp) 586 { 587 UINT r = GetSystemWindowsDirectoryW(tmp, len+1); 588 if (r && r < len) 589 { 590 hr = StringCchCatW(tmp, len+1, szAppPatch); 591 if (SUCCEEDED(hr)) 592 { 593 if (InterlockedCompareExchangePointer((void**)&default_dir, tmp, NULL) == NULL) 594 tmp = NULL; 595 } 596 } 597 if (tmp) 598 SdbFree(tmp); 599 } 600 if (!default_dir) 601 { 602 SHIM_ERR("Unable to obtain default AppPatch directory (0x%x)\n", hr); 603 return hr; 604 } 605 } 606 607 if (!hsdb) 608 { 609 return StringCchCopyW(path, size, default_dir); 610 } 611 else 612 { 613 SHIM_ERR("Unimplemented for hsdb != NULL\n"); 614 return E_NOTIMPL; 615 } 616 } 617 618 619 /** 620 * Translates the given trWhich to a specific database / tagid 621 * 622 * @param [in] hsdb Handle to the database. 623 * @param [in] trWhich Tagref to find 624 * @param [out,opt] ppdb The Shim database that trWhich belongs to. 625 * @param [out,opt] ptiWhich The tagid that trWhich corresponds to. 626 * 627 * @return TRUE if it succeeds, FALSE if it fails. 628 */ 629 BOOL WINAPI SdbTagRefToTagID(HSDB hsdb, TAGREF trWhich, PDB* ppdb, TAGID* ptiWhich) 630 { 631 if (trWhich & 0xf0000000) 632 { 633 SHIM_ERR("Multiple shim databases not yet implemented!\n"); 634 if (ppdb) 635 *ppdb = NULL; 636 if (ptiWhich) 637 *ptiWhich = TAG_NULL; 638 return FALSE; 639 } 640 641 /* There seems to be no range checking on trWhich.. */ 642 if (ppdb) 643 *ppdb = hsdb->pdb; 644 if (ptiWhich) 645 *ptiWhich = trWhich & 0x0fffffff; 646 647 return TRUE; 648 } 649 650 /** 651 * Translates the given trWhich to a specific database / tagid 652 * 653 * @param [in] hsdb Handle to the database. 654 * @param [in] pdb The Shim database that tiWhich belongs to. 655 * @param [in] tiWhich Path to executable for which we query database. 656 * @param [out,opt] ptrWhich The tagid that tiWhich corresponds to. 657 * 658 * @return TRUE if it succeeds, FALSE if it fails. 659 */ 660 BOOL WINAPI SdbTagIDToTagRef(HSDB hsdb, PDB pdb, TAGID tiWhich, TAGREF* ptrWhich) 661 { 662 if (pdb != hsdb->pdb) 663 { 664 SHIM_ERR("Multiple shim databases not yet implemented!\n"); 665 if (ptrWhich) 666 *ptrWhich = TAGREF_NULL; 667 return FALSE; 668 } 669 670 if (ptrWhich) 671 *ptrWhich = tiWhich & 0x0fffffff; 672 673 return TRUE; 674 } 675 676 677 /* Convert a query result to shim data that will be loaded in the child process */ 678 BOOL WINAPI SdbPackAppCompatData(HSDB hsdb, PSDBQUERYRESULT pQueryResult, PVOID* ppData, DWORD *pdwSize) 679 { 680 ShimData* pData; 681 HRESULT hr; 682 DWORD n; 683 684 if (!pQueryResult || !ppData || !pdwSize) 685 { 686 SHIM_WARN("Invalid params: %p, %p, %p\n", pQueryResult, ppData, pdwSize); 687 return FALSE; 688 } 689 690 pData = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ShimData)); 691 if (!pData) 692 { 693 SHIM_WARN("Unable to allocate %d bytes\n", sizeof(ShimData)); 694 return FALSE; 695 } 696 697 GetSystemWindowsDirectoryW(pData->szModule, _countof(pData->szModule)); 698 hr = StringCchCatW(pData->szModule, _countof(pData->szModule), L"\\system32\\apphelp.dll"); 699 if (!SUCCEEDED(hr)) 700 { 701 SHIM_ERR("Unable to append module name (0x%x)\n", hr); 702 RtlFreeHeap(RtlGetProcessHeap(), 0, pData); 703 return FALSE; 704 } 705 706 pData->dwSize = sizeof(*pData); 707 pData->dwMagic = SHIMDATA_MAGIC; 708 pData->Query = *pQueryResult; 709 pData->unknown = 0; 710 pData->szLayer[0] = UNICODE_NULL; /* TODO */ 711 712 SHIM_INFO("\ndwFlags 0x%x\ndwMagic 0x%x\ntrExe 0x%x\ntrLayer 0x%x\n", 713 pData->Query.dwFlags, pData->dwMagic, pData->Query.atrExes[0], pData->Query.atrLayers[0]); 714 715 /* Database List */ 716 /* 0x0 {GUID} NAME */ 717 718 for (n = 0; n < pQueryResult->dwLayerCount; ++n) 719 { 720 SHIM_INFO("Layer 0x%x\n", pQueryResult->atrLayers[n]); 721 } 722 723 *ppData = pData; 724 *pdwSize = pData->dwSize; 725 726 return TRUE; 727 } 728 729 BOOL WINAPI SdbUnpackAppCompatData(HSDB hsdb, LPCWSTR pszImageName, PVOID pData, PSDBQUERYRESULT pQueryResult) 730 { 731 ShimData* pShimData = pData; 732 733 if (!pShimData || pShimData->dwMagic != SHIMDATA_MAGIC || pShimData->dwSize < sizeof(ShimData)) 734 return FALSE; 735 736 if (!pQueryResult) 737 return FALSE; 738 739 /* szLayer? */ 740 741 *pQueryResult = pShimData->Query; 742 return TRUE; 743 } 744 745 DWORD WINAPI SdbGetAppCompatDataSize(ShimData* pData) 746 { 747 if (!pData || pData->dwMagic != SHIMDATA_MAGIC) 748 return 0; 749 750 751 return pData->dwSize; 752 } 753 754