2 * PROJECT: ReactOS Setup Library
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: NT Version Resource Management API
5 * COPYRIGHT: Copyright 2017-2018 Hermes Belusca-Maito
7 * NOTE 1: Adapted from Wine-synced dll/win32/version DLL.
8 * NOTE 2: We only deal with 32-bit PE executables.
11 /* INCLUDES *****************************************************************/
14 #include <ndk/ldrtypes.h>
15 #include <ndk/ldrfuncs.h>
17 #include "ntverrsrc.h"
23 /* FUNCTIONS ****************************************************************/
29 OUT PULONG ResourceSize OPTIONAL
)
31 // #define RT_VERSION MAKEINTRESOURCE(16) // See winuser.h
32 #define VS_VERSION_INFO 1 // See psdk/verrsrc.h
33 #define VS_FILE_INFO RT_VERSION
36 LDR_RESOURCE_INFO ResourceInfo
;
37 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry
;
41 /* Try to find the resource */
42 ResourceInfo
.Type
= 16; // RT_VERSION;
43 ResourceInfo
.Name
= VS_VERSION_INFO
; // MAKEINTRESOURCEW(VS_VERSION_INFO);
44 ResourceInfo
.Language
= 0; // Don't care about the language
46 Status
= LdrFindResource_U(BaseAddress
,
50 if (!NT_SUCCESS(Status
))
52 DPRINT1("NtGetVersionResource: Version resource not found, Status 0x%08lx\n", Status
);
56 /* Access the resource */
57 Status
= LdrAccessResource(BaseAddress
,
61 if (!NT_SUCCESS(Status
))
63 DPRINT1("NtGetVersionResource: Cannot access Version resource, Status 0x%08lx\n", Status
);
68 if (ResourceSize
) *ResourceSize
= Size
;
70 return STATUS_SUCCESS
;
73 /* NOTE: the xxx_STRUCT16 version differs by storing strings in ANSI, not in UNICODE */
74 typedef struct _VS_VERSION_INFO_STRUCT32
78 WORD wType
; /* 1:Text, 0:Binary */
80 #if 0 /* variable length structure */
84 VS_VERSION_INFO_STRUCT32 Children
[];
86 } VS_VERSION_INFO_STRUCT32
, *PVS_VERSION_INFO_STRUCT32
;
87 typedef const VS_VERSION_INFO_STRUCT32
*PCVS_VERSION_INFO_STRUCT32
;
89 #define DWORD_ALIGN( base, ptr ) \
90 ( (ULONG_PTR)(base) + ((((ULONG_PTR)(ptr) - (ULONG_PTR)(base)) + 3) & ~3) )
92 #define VersionInfo32_Value( ver ) \
93 DWORD_ALIGN( (ver), (ver)->szKey + wcslen((ver)->szKey) + 1 )
95 #define VersionInfo32_Children( ver ) \
96 (PCVS_VERSION_INFO_STRUCT32)( VersionInfo32_Value( ver ) + \
97 ( ( (ver)->wValueLength * \
98 ((ver)->wType? 2 : 1) + 3 ) & ~3 ) )
100 #define VersionInfo32_Next( ver ) \
101 (PVS_VERSION_INFO_STRUCT32)( (ULONG_PTR)ver + (((ver)->wLength + 3) & ~3) )
103 static PCVS_VERSION_INFO_STRUCT32
104 VersionInfo32_FindChild(
105 IN PCVS_VERSION_INFO_STRUCT32 info
,
109 PCVS_VERSION_INFO_STRUCT32 child
= VersionInfo32_Children(info
);
111 while ((ULONG_PTR
)child
< (ULONG_PTR
)info
+ info
->wLength
)
113 if (!_wcsnicmp(child
->szKey
, szKey
, cbKey
) && !child
->szKey
[cbKey
])
116 if (child
->wLength
== 0) return NULL
;
117 child
= VersionInfo32_Next(child
);
124 VersionInfo32_QueryValue(
125 IN PCVS_VERSION_INFO_STRUCT32 info
,
126 IN PCWSTR lpSubBlock
,
127 OUT PVOID
* lplpBuffer
,
128 OUT PUINT puLen OPTIONAL
,
129 OUT BOOL
* pbText OPTIONAL
)
133 DPRINT("lpSubBlock : (%S)\n", lpSubBlock
);
137 /* Find next path component */
138 for (lpNextSlash
= lpSubBlock
; *lpNextSlash
; lpNextSlash
++)
140 if (*lpNextSlash
== '\\')
144 /* Skip empty components */
145 if (lpNextSlash
== lpSubBlock
)
151 /* We have a non-empty component: search info for key */
152 info
= VersionInfo32_FindChild(info
, lpSubBlock
, lpNextSlash
- lpSubBlock
);
155 if (puLen
) *puLen
= 0;
156 return STATUS_RESOURCE_TYPE_NOT_FOUND
;
159 /* Skip path component */
160 lpSubBlock
= lpNextSlash
;
164 *lplpBuffer
= (PVOID
)VersionInfo32_Value(info
);
166 *puLen
= info
->wValueLength
;
168 *pbText
= info
->wType
;
170 return STATUS_SUCCESS
;
175 IN
const VOID
* pBlock
,
176 IN PCWSTR lpSubBlock
,
177 OUT PVOID
* lplpBuffer
,
180 PCVS_VERSION_INFO_STRUCT32 info
= pBlock
;
182 DPRINT("%s (%p, %S, %p, %p)\n", __FUNCTION__
, pBlock
, lpSubBlock
, lplpBuffer
, puLen
);
187 if (!lpSubBlock
|| !*lpSubBlock
)
190 return VersionInfo32_QueryValue(info
, lpSubBlock
, lplpBuffer
, puLen
, NULL
);