2 * PROJECT: ReactOS Application compatibility module
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Shim matching / data (un)packing
5 * COPYRIGHT: Copyright 2011 André Hentschel
6 * Copyright 2013 Mislav Blaževic
7 * Copyright 2015-2019 Mark Jansen (mark.jansen@reactos.org)
10 #define WIN32_NO_STATUS
15 #include "compat_undoc.h"
17 #define MAX_LAYER_LENGTH 256
19 #define GPLK_MACHINE 2
21 typedef struct _ShimData
23 WCHAR szModule
[MAX_PATH
];
27 WCHAR szLayer
[MAX_LAYER_LENGTH
];
28 DWORD dwRosProcessCompatVersion
; // ReactOS specific
31 #define SHIMDATA_MAGIC 0xAC0DEDAB
32 #define REACTOS_COMPATVERSION_IGNOREMANIFEST 0xffffffff
34 C_ASSERT(SHIMDATA_MAGIC
== REACTOS_SHIMDATA_MAGIC
);
35 C_ASSERT(sizeof(ShimData
) == sizeof(ReactOS_ShimData
));
36 C_ASSERT(offsetof(ShimData
, dwMagic
) == offsetof(ReactOS_ShimData
, dwMagic
));
37 C_ASSERT(offsetof(ShimData
, dwRosProcessCompatVersion
) == offsetof(ReactOS_ShimData
, dwRosProcessCompatVersion
));
40 static BOOL WINAPI
SdbpFileExists(LPCWSTR path
)
42 DWORD attr
= GetFileAttributesW(path
);
43 return (attr
!= INVALID_FILE_ATTRIBUTES
&& !(attr
& FILE_ATTRIBUTE_DIRECTORY
));
46 /* Given a 'MATCHING_FILE' tag and an ATTRINFO array,
47 check all tags defined in the MATCHING_FILE against the ATTRINFO */
48 static BOOL
SdbpMatchFileAttributes(PDB pdb
, TAGID matching_file
, PATTRINFO attribs
, DWORD attr_count
)
52 for (child
= SdbGetFirstChild(pdb
, matching_file
);
53 child
!= TAGID_NULL
; child
= SdbGetNextChild(pdb
, matching_file
, child
))
55 TAG tag
= SdbGetTagFromTagID(pdb
, child
);
58 /* Already handled! */
62 if (tag
== TAG_UPTO_BIN_FILE_VERSION
||
63 tag
== TAG_UPTO_BIN_PRODUCT_VERSION
||
64 tag
== TAG_UPTO_LINK_DATE
)
66 SHIM_WARN("Unimplemented TAG_UPTO_XXXXX\n");
70 for (n
= 0; n
< attr_count
; ++n
)
72 PATTRINFO attr
= attribs
+ n
;
73 if (attr
->flags
== ATTRIBUTE_AVAILABLE
&& attr
->type
== tag
)
78 switch (tag
& TAG_TYPE_MASK
)
81 dwval
= SdbReadDWORDTag(pdb
, child
, 0);
82 if (dwval
!= attr
->dwattr
)
85 case TAG_TYPE_STRINGREF
:
86 lpval
= SdbGetStringTagPtr(pdb
, child
);
87 if (!lpval
|| wcsicmp(attr
->lpattr
, lpval
))
91 qwval
= SdbReadQWORDTag(pdb
, child
, 0);
92 if (qwval
!= attr
->qwattr
)
96 SHIM_WARN("Unhandled type 0x%x MATCHING_FILE\n", (tag
& TAG_TYPE_MASK
));
102 SHIM_WARN("Unhandled tag %ws in MATCHING_FILE\n", SdbTagToString(tag
));
107 /* Given an 'exe' tag and an ATTRINFO array (for the main file),
108 verify that the main file and any additional files match */
109 static BOOL WINAPI
SdbpMatchExe(PDB pdb
, TAGID exe
, const WCHAR
* dir
, PATTRINFO main_attribs
, DWORD main_attr_count
)
111 RTL_UNICODE_STRING_BUFFER FullPathName
= { { 0 } };
112 WCHAR FullPathBuffer
[MAX_PATH
];
113 UNICODE_STRING UnicodeDir
;
115 PATTRINFO attribs
= NULL
;
117 BOOL IsMatch
= FALSE
;
119 RtlInitUnicodeString(&UnicodeDir
, dir
);
120 RtlInitBuffer(&FullPathName
.ByteBuffer
, (PUCHAR
)FullPathBuffer
, sizeof(FullPathBuffer
));
122 for (matching_file
= SdbFindFirstTag(pdb
, exe
, TAG_MATCHING_FILE
);
123 matching_file
!= TAGID_NULL
; matching_file
= SdbFindNextTag(pdb
, exe
, matching_file
))
125 TAGID tagName
= SdbFindFirstTag(pdb
, matching_file
, TAG_NAME
);
129 RtlInitUnicodeString(&Name
, SdbGetStringTagPtr(pdb
, tagName
));
134 /* An '*' here means use the main executable' */
135 if (!wcscmp(Name
.Buffer
, L
"*"))
137 /* We already have these attributes, so we do not need to retrieve them */
138 if (!SdbpMatchFileAttributes(pdb
, matching_file
, main_attribs
, main_attr_count
))
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
)))
148 if (Len
> FullPathName
.ByteBuffer
.Size
)
151 RtlInitEmptyUnicodeString(&FullPathName
.String
, (PWCHAR
)FullPathName
.ByteBuffer
.Buffer
, FullPathName
.ByteBuffer
.Size
);
153 RtlCopyUnicodeString(&FullPathName
.String
, &UnicodeDir
);
154 RtlAppendUnicodeToString(&FullPathName
.String
, L
"\\");
155 RtlAppendUnicodeStringToString(&FullPathName
.String
, &Name
);
157 /* If the file does not exist, do not bother trying to read it's attributes */
158 if (!SdbpFileExists(FullPathName
.String
.Buffer
))
161 /* Do we have some attributes from the previous iteration? */
163 SdbFreeFileAttributes(attribs
);
165 if (!SdbGetFileAttributes(FullPathName
.String
.Buffer
, &attribs
, &attr_count
))
168 if (!SdbpMatchFileAttributes(pdb
, matching_file
, attribs
, attr_count
))
175 RtlFreeBuffer(&FullPathName
.ByteBuffer
);
177 SdbFreeFileAttributes(attribs
);
182 /* Add a database guid to the query result */
183 static void SdbpAddDatabaseGuid(PDB pdb
, PSDBQUERYRESULT result
)
187 for (n
= 0; n
< _countof(result
->rgGuidDB
); ++n
)
189 if (!memcmp(&result
->rgGuidDB
[n
], &pdb
->database_id
, sizeof(pdb
->database_id
)))
192 if (result
->dwCustomSDBMap
& (1<<n
))
195 memcpy(&result
->rgGuidDB
[n
], &pdb
->database_id
, sizeof(result
->rgGuidDB
[n
]));
196 result
->dwCustomSDBMap
|= (1<<n
);
201 /* Add one layer to the query result */
202 static BOOL
SdbpAddSingleLayerMatch(TAGREF layer
, PSDBQUERYRESULT result
)
206 for (n
= 0; n
< result
->dwLayerCount
; ++n
)
208 if (result
->atrLayers
[n
] == layer
)
212 if (n
>= _countof(result
->atrLayers
))
215 result
->atrLayers
[n
] = layer
;
216 result
->dwLayerCount
++;
221 /* Translate a layer name to a tagref + add it to the query result */
222 static BOOL
SdbpAddNamedLayerMatch(HSDB hsdb
, PCWSTR layerName
, PSDBQUERYRESULT result
)
224 TAGID database
, layer
;
228 database
= SdbFindFirstTag(pdb
, TAGID_ROOT
, TAG_DATABASE
);
229 if (database
== TAGID_NULL
)
232 layer
= SdbFindFirstNamedTag(pdb
, database
, TAG_LAYER
, TAG_NAME
, layerName
);
233 if (layer
== TAGID_NULL
)
236 if (!SdbTagIDToTagRef(hsdb
, pdb
, layer
, &tr
))
239 if (!SdbpAddSingleLayerMatch(tr
, result
))
242 SdbpAddDatabaseGuid(pdb
, result
);
246 /* Add all layers for the exe tag to the query result */
247 static void SdbpAddExeLayers(HSDB hsdb
, PDB pdb
, TAGID tagExe
, PSDBQUERYRESULT result
)
249 TAGID layer
= SdbFindFirstTag(pdb
, tagExe
, TAG_LAYER
);
251 while (layer
!= TAGID_NULL
)
254 TAGID layerIdTag
= SdbFindFirstTag(pdb
, layer
, TAG_LAYER_TAGID
);
255 DWORD tagId
= SdbReadDWORDTag(pdb
, layerIdTag
, TAGID_NULL
);
257 if (layerIdTag
!= TAGID_NULL
&&
258 tagId
!= TAGID_NULL
&&
259 SdbTagIDToTagRef(hsdb
, pdb
, tagId
, &tr
))
261 SdbpAddSingleLayerMatch(tr
, result
);
265 /* Try a name lookup */
266 TAGID layerTag
= SdbFindFirstTag(pdb
, layer
, TAG_NAME
);
267 if (layerTag
!= TAGID_NULL
)
269 LPCWSTR layerName
= SdbGetStringTagPtr(pdb
, layerTag
);
272 SdbpAddNamedLayerMatch(hsdb
, layerName
, result
);
277 layer
= SdbFindNextTag(pdb
, tagExe
, layer
);
281 /* Add an exe tag to the query result */
282 static void SdbpAddExeMatch(HSDB hsdb
, PDB pdb
, TAGID tagExe
, PSDBQUERYRESULT result
)
287 if (!SdbTagIDToTagRef(hsdb
, pdb
, tagExe
, &tr
))
290 for (n
= 0; n
< result
->dwExeCount
; ++n
)
292 if (result
->atrExes
[n
] == tr
)
296 if (n
>= _countof(result
->atrExes
))
299 result
->atrExes
[n
] = tr
;
300 result
->dwExeCount
++;
302 SdbpAddExeLayers(hsdb
, pdb
, tagExe
, result
);
304 SdbpAddDatabaseGuid(pdb
, result
);
307 /* Add all named layers to the query result */
308 static ULONG
SdbpAddLayerMatches(HSDB hsdb
, PWSTR pwszLayers
, DWORD pdwBytes
, PSDBQUERYRESULT result
)
310 PWSTR start
= pwszLayers
, p
;
313 const PWSTR end
= pwszLayers
+ (pdwBytes
/ sizeof(WCHAR
));
314 while (start
< end
&& (*start
== L
'!' || *start
== L
'#' || *start
== L
' ' || *start
== L
'\t'))
322 while (*start
== L
' ' || *start
== L
'\t')
325 if (*start
== UNICODE_NULL
)
327 p
= wcspbrk(start
, L
" \t");
332 if (SdbpAddNamedLayerMatch(hsdb
, start
, result
))
336 } while (start
< end
&& p
);
341 static BOOL
SdbpPropagateEnvLayers(HSDB hsdb
, LPWSTR Environment
, PSDBQUERYRESULT Result
)
343 static const UNICODE_STRING EnvKey
= RTL_CONSTANT_STRING(L
"__COMPAT_LAYER");
344 UNICODE_STRING EnvValue
;
346 WCHAR Buffer
[MAX_LAYER_LENGTH
];
348 RtlInitEmptyUnicodeString(&EnvValue
, Buffer
, sizeof(Buffer
));
350 Status
= RtlQueryEnvironmentVariable_U(Environment
, &EnvKey
, &EnvValue
);
352 if (!NT_SUCCESS(Status
))
355 return SdbpAddLayerMatches(hsdb
, Buffer
, EnvValue
.Length
, Result
) > 0;
361 * Opens specified shim database file. Handle returned by this function may only be used by
362 * functions which take HSDB param thus differing it from SdbOpenDatabase.
364 * @param [in] flags Specifies type of path or predefined database.
365 * @param [in] path Path to the shim database file.
367 * @return Success: Handle to the opened shim database, NULL otherwise.
369 HSDB WINAPI
SdbInitDatabase(DWORD flags
, LPCWSTR path
)
371 static const WCHAR shim
[] = {'\\','s','y','s','m','a','i','n','.','s','d','b',0};
372 static const WCHAR msi
[] = {'\\','m','s','i','m','a','i','n','.','s','d','b',0};
373 static const WCHAR drivers
[] = {'\\','d','r','v','m','a','i','n','.','s','d','b',0};
378 hsdb
= SdbAlloc(sizeof(SDB
));
381 hsdb
->auto_loaded
= 0;
383 /* Check for predefined databases */
384 if ((flags
& HID_DATABASE_TYPE_MASK
) && path
== NULL
)
386 switch (flags
& HID_DATABASE_TYPE_MASK
)
388 case SDB_DATABASE_MAIN_SHIM
: name
= shim
; break;
389 case SDB_DATABASE_MAIN_MSI
: name
= msi
; break;
390 case SDB_DATABASE_MAIN_DRIVERS
: name
= drivers
; break;
392 SdbReleaseDatabase(hsdb
);
395 SdbGetAppPatchDir(NULL
, buffer
, _countof(buffer
));
396 StringCchCatW(buffer
, _countof(buffer
), name
);
397 flags
= HID_DOS_PATHS
;
400 hsdb
->pdb
= SdbOpenDatabase(path
? path
: buffer
, (flags
& 0xF) - 1);
402 /* If database could not be loaded, a handle doesn't make sense either */
405 SdbReleaseDatabase(hsdb
);
413 * Closes shim database opened by SdbInitDatabase.
415 * @param [in] hsdb Handle to the shim database.
417 void WINAPI
SdbReleaseDatabase(HSDB hsdb
)
421 SdbCloseDatabase(hsdb
->pdb
);
427 * Queries database for a specified exe If hsdb is NULL default database shall be loaded and
430 * @param [in] hsdb Handle to the shim database.
431 * @param [in] path Path to executable for which we query database.
432 * @param [in] module_name Unused.
433 * @param [in] env The environment block to use
434 * @param [in] flags 0 or SDBGMEF_IGNORE_ENVIRONMENT.
435 * @param [out] result Pointer to structure in which query result shall be stored.
437 * @return TRUE if it succeeds, FALSE if it fails.
439 BOOL WINAPI
SdbGetMatchingExe(HSDB hsdb
, LPCWSTR path
, LPCWSTR module_name
,
440 LPCWSTR env
, DWORD flags
, PSDBQUERYRESULT result
)
443 TAGID database
, iter
, name
;
444 PATTRINFO attribs
= NULL
;
446 RTL_UNICODE_STRING_BUFFER DosApplicationName
= { { 0 } };
447 WCHAR DosPathBuffer
[MAX_PATH
];
450 WCHAR wszLayers
[MAX_LAYER_LENGTH
];
454 /* Load default database if one is not specified */
457 /* To reproduce windows behaviour HID_DOS_PATHS needs
458 * to be specified when loading default database */
459 hsdb
= SdbInitDatabase(HID_DOS_PATHS
| SDB_DATABASE_MAIN_SHIM
, NULL
);
461 hsdb
->auto_loaded
= TRUE
;
464 ZeroMemory(result
, sizeof(*result
));
466 /* No database could be loaded */
470 /* We do not support multiple db's yet! */
473 RtlInitUnicodeString(&DosApplicationName
.String
, path
);
474 RtlInitBuffer(&DosApplicationName
.ByteBuffer
, (PUCHAR
)DosPathBuffer
, sizeof(DosPathBuffer
));
475 if (!NT_SUCCESS(RtlEnsureBufferSize(RTL_SKIP_BUFFER_COPY
, &DosApplicationName
.ByteBuffer
, DosApplicationName
.String
.MaximumLength
)))
477 SHIM_ERR("Failed to convert allocate buffer.\n");
480 /* Update the internal buffer to contain the string */
481 memcpy(DosApplicationName
.ByteBuffer
.Buffer
, path
, DosApplicationName
.String
.MaximumLength
);
482 /* Make sure the string uses our internal buffer (we want to modify the buffer,
483 and RtlNtPathNameToDosPathName does not always modify the String to point to the Buffer)! */
484 DosApplicationName
.String
.Buffer
= (PWSTR
)DosApplicationName
.ByteBuffer
.Buffer
;
486 if (!NT_SUCCESS(RtlNtPathNameToDosPathName(0, &DosApplicationName
, &PathType
, NULL
)))
488 SHIM_ERR("Failed to convert %S to DOS Path.\n", path
);
493 /* Extract file name */
494 file_name
= wcsrchr(DosApplicationName
.String
.Buffer
, '\\');
497 SHIM_ERR("Failed to find Exe name in %wZ.\n", &DosApplicationName
.String
);
501 /* We will use the buffer for exe name and directory. */
502 *(file_name
++) = UNICODE_NULL
;
504 /* DATABASE is list TAG which contains all executables */
505 database
= SdbFindFirstTag(pdb
, TAGID_ROOT
, TAG_DATABASE
);
506 if (database
== TAGID_NULL
)
511 /* EXE is list TAG which contains data required to match executable */
512 iter
= SdbFindFirstTag(pdb
, database
, TAG_EXE
);
514 /* Search for entry in database, we should look into indexing tags! */
515 while (iter
!= TAGID_NULL
)
518 /* Check if exe name matches */
519 name
= SdbFindFirstTag(pdb
, iter
, TAG_NAME
);
520 /* If this is a malformed DB, (no TAG_NAME), we should not crash. */
521 foundName
= SdbGetStringTagPtr(pdb
, name
);
522 if (foundName
&& !wcsicmp(foundName
, file_name
))
524 /* Get information about executable required to match it with database entry */
527 if (!SdbGetFileAttributes(path
, &attribs
, &attr_count
))
532 /* We have a null terminator before the application name, so DosApplicationName only contains the path. */
533 if (SdbpMatchExe(pdb
, iter
, DosApplicationName
.String
.Buffer
, attribs
, attr_count
))
536 SdbpAddExeMatch(hsdb
, pdb
, iter
, result
);
540 /* Continue iterating */
541 iter
= SdbFindNextTag(pdb
, database
, iter
);
544 /* Restore the full path. */
545 *(--file_name
) = L
'\\';
547 dwSize
= sizeof(wszLayers
);
548 if (SdbGetPermLayerKeys(DosApplicationName
.String
.Buffer
, wszLayers
, &dwSize
, GPLK_MACHINE
| GPLK_USER
))
550 SdbpAddLayerMatches(hsdb
, wszLayers
, dwSize
, result
);
554 if (!(flags
& SDBGMEF_IGNORE_ENVIRONMENT
))
556 if (SdbpPropagateEnvLayers(hsdb
, (LPWSTR
)env
, result
))
559 result
->dwFlags
|= SHIMREG_HAS_ENVIRONMENT
;
564 RtlFreeBuffer(&DosApplicationName
.ByteBuffer
);
566 SdbFreeFileAttributes(attribs
);
567 if (hsdb
->auto_loaded
)
568 SdbReleaseDatabase(hsdb
);
573 * Retrieves AppPatch directory.
575 * @param [in] pdb Handle to the shim database.
576 * @param [out] path Pointer to memory in which path shall be written.
577 * @param [in] size Size of the buffer in characters.
579 HRESULT WINAPI
SdbGetAppPatchDir(HSDB hsdb
, LPWSTR path
, DWORD size
)
581 static WCHAR
* default_dir
= NULL
;
582 static CONST WCHAR szAppPatch
[] = {'\\','A','p','p','P','a','t','c','h',0};
584 /* In case function fails, path holds empty string */
592 UINT len
= GetSystemWindowsDirectoryW(NULL
, 0) + SdbpStrlen(szAppPatch
);
593 tmp
= SdbAlloc((len
+ 1)* sizeof(WCHAR
));
596 UINT r
= GetSystemWindowsDirectoryW(tmp
, len
+1);
599 hr
= StringCchCatW(tmp
, len
+1, szAppPatch
);
602 if (InterlockedCompareExchangePointer((void**)&default_dir
, tmp
, NULL
) == NULL
)
611 SHIM_ERR("Unable to obtain default AppPatch directory (0x%x)\n", hr
);
618 return StringCchCopyW(path
, size
, default_dir
);
622 SHIM_ERR("Unimplemented for hsdb != NULL\n");
629 * Translates the given trWhich to a specific database / tagid
631 * @param [in] hsdb Handle to the database.
632 * @param [in] trWhich Tagref to find
633 * @param [out,opt] ppdb The Shim database that trWhich belongs to.
634 * @param [out,opt] ptiWhich The tagid that trWhich corresponds to.
636 * @return TRUE if it succeeds, FALSE if it fails.
638 BOOL WINAPI
SdbTagRefToTagID(HSDB hsdb
, TAGREF trWhich
, PDB
* ppdb
, TAGID
* ptiWhich
)
640 if (trWhich
& 0xf0000000)
642 SHIM_ERR("Multiple shim databases not yet implemented!\n");
646 *ptiWhich
= TAG_NULL
;
650 /* There seems to be no range checking on trWhich.. */
654 *ptiWhich
= trWhich
& 0x0fffffff;
660 * Translates the given trWhich to a specific database / tagid
662 * @param [in] hsdb Handle to the database.
663 * @param [in] pdb The Shim database that tiWhich belongs to.
664 * @param [in] tiWhich Path to executable for which we query database.
665 * @param [out,opt] ptrWhich The tagid that tiWhich corresponds to.
667 * @return TRUE if it succeeds, FALSE if it fails.
669 BOOL WINAPI
SdbTagIDToTagRef(HSDB hsdb
, PDB pdb
, TAGID tiWhich
, TAGREF
* ptrWhich
)
671 if (pdb
!= hsdb
->pdb
)
673 SHIM_ERR("Multiple shim databases not yet implemented!\n");
675 *ptrWhich
= TAGREF_NULL
;
680 *ptrWhich
= tiWhich
& 0x0fffffff;
686 /* Convert a query result to shim data that will be loaded in the child process */
687 BOOL WINAPI
SdbPackAppCompatData(HSDB hsdb
, PSDBQUERYRESULT pQueryResult
, PVOID
* ppData
, DWORD
*pdwSize
)
692 BOOL bCloseDatabase
= FALSE
;
694 if (!pQueryResult
|| !ppData
|| !pdwSize
)
696 SHIM_WARN("Invalid params: %p, %p, %p\n", pQueryResult
, ppData
, pdwSize
);
700 pData
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ShimData
));
703 SHIM_WARN("Unable to allocate %d bytes\n", sizeof(ShimData
));
707 GetSystemWindowsDirectoryW(pData
->szModule
, _countof(pData
->szModule
));
708 hr
= StringCchCatW(pData
->szModule
, _countof(pData
->szModule
), L
"\\system32\\apphelp.dll");
711 SHIM_ERR("Unable to append module name (0x%x)\n", hr
);
712 RtlFreeHeap(RtlGetProcessHeap(), 0, pData
);
716 pData
->dwSize
= sizeof(*pData
);
717 pData
->dwMagic
= SHIMDATA_MAGIC
;
718 pData
->Query
= *pQueryResult
;
719 pData
->dwRosProcessCompatVersion
= 0;
720 pData
->szLayer
[0] = UNICODE_NULL
; /* TODO */
722 SHIM_INFO("\ndwFlags 0x%x\ndwMagic 0x%x\ntrExe 0x%x\ntrLayer 0x%x\n",
723 pData
->Query
.dwFlags
, pData
->dwMagic
, pData
->Query
.atrExes
[0], pData
->Query
.atrLayers
[0]);
726 /* 0x0 {GUID} NAME: Use to open HSDB */
729 hsdb
= SdbInitDatabase(HID_DOS_PATHS
| SDB_DATABASE_MAIN_SHIM
, NULL
);
730 bCloseDatabase
= TRUE
;
733 for (n
= 0; n
< pQueryResult
->dwLayerCount
; ++n
)
735 DWORD dwValue
= 0, dwType
;
736 DWORD dwValueSize
= sizeof(dwValue
);
737 SHIM_INFO("Layer 0x%x\n", pQueryResult
->atrLayers
[n
]);
739 if (SdbQueryData(hsdb
, pQueryResult
->atrLayers
[n
], L
"SHIMVERSIONNT", &dwType
, &dwValue
, &dwValueSize
) == ERROR_SUCCESS
&&
740 dwType
== REG_DWORD
&& dwValueSize
== sizeof(dwValue
))
742 if (dwValue
!= REACTOS_COMPATVERSION_IGNOREMANIFEST
)
743 dwValue
= (dwValue
% 100) | ((dwValue
/ 100) << 8);
744 if (dwValue
> pData
->dwRosProcessCompatVersion
)
745 pData
->dwRosProcessCompatVersion
= dwValue
;
749 if (pData
->dwRosProcessCompatVersion
)
750 SHIM_INFO("Setting ProcessCompatVersion 0x%x\n", pData
->dwRosProcessCompatVersion
);
753 SdbReleaseDatabase(hsdb
);
756 *pdwSize
= pData
->dwSize
;
761 BOOL WINAPI
SdbUnpackAppCompatData(HSDB hsdb
, LPCWSTR pszImageName
, PVOID pData
, PSDBQUERYRESULT pQueryResult
)
763 ShimData
* pShimData
= pData
;
765 if (!pShimData
|| pShimData
->dwMagic
!= SHIMDATA_MAGIC
|| pShimData
->dwSize
< sizeof(ShimData
))
773 *pQueryResult
= pShimData
->Query
;
777 DWORD WINAPI
SdbGetAppCompatDataSize(ShimData
* pData
)
779 if (!pData
|| pData
->dwMagic
!= SHIMDATA_MAGIC
)
782 return pData
->dwSize
;
787 * Retrieve a Data entry
789 * @param [in] hsdb The multi-database.
790 * @param [in] trExe The tagRef to start at
791 * @param [in,opt] lpszDataName The name of the Data entry to find, or NULL to return all.
792 * @param [out,opt] lpdwDataType Any of REG_SZ, REG_QWORD, REG_DWORD, ...
793 * @param [out] lpBuffer The output buffer
794 * @param [in,out,opt] lpcbBufferSize The size of lpBuffer in bytes
795 * @param [out,opt] ptrData The tagRef of the data
797 * @return ERROR_SUCCESS
799 DWORD WINAPI
SdbQueryDataEx(HSDB hsdb
, TAGREF trWhich
, LPCWSTR lpszDataName
, LPDWORD lpdwDataType
, LPVOID lpBuffer
, LPDWORD lpcbBufferSize
, TAGREF
*ptrData
)
802 TAGID tiWhich
, tiData
;
805 if (!SdbTagRefToTagID(hsdb
, trWhich
, &pdb
, &tiWhich
))
807 SHIM_WARN("Unable to translate trWhich=0x%x\n", trWhich
);
808 return ERROR_NOT_FOUND
;
811 dwResult
= SdbQueryDataExTagID(pdb
, tiWhich
, lpszDataName
, lpdwDataType
, lpBuffer
, lpcbBufferSize
, &tiData
);
813 if (dwResult
== ERROR_SUCCESS
&& ptrData
)
814 SdbTagIDToTagRef(hsdb
, pdb
, tiData
, ptrData
);
821 * Retrieve a Data entry
823 * @param [in] hsdb The multi-database.
824 * @param [in] trExe The tagRef to start at
825 * @param [in,opt] lpszDataName The name of the Data entry to find, or NULL to return all.
826 * @param [out,opt] lpdwDataType Any of REG_SZ, REG_QWORD, REG_DWORD, ...
827 * @param [out] lpBuffer The output buffer
828 * @param [in,out,opt] lpcbBufferSize The size of lpBuffer in bytes
830 * @return ERROR_SUCCESS
832 DWORD WINAPI
SdbQueryData(HSDB hsdb
, TAGREF trWhich
, LPCWSTR lpszDataName
, LPDWORD lpdwDataType
, LPVOID lpBuffer
, LPDWORD lpcbBufferSize
)
834 return SdbQueryDataEx(hsdb
, trWhich
, lpszDataName
, lpdwDataType
, lpBuffer
, lpcbBufferSize
, NULL
);