main
cpp 336 lines 9.94 KB
Raw
1 // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3 #include "precomp.h"
4
5 enum class NETCORESEARCHTYPE
6 {
7 None,
8 Runtime,
9 Sdk,
10 SdkFeatureBand,
11 };
12
13 struct NETCORESEARCH_STATE
14 {
15 NETCORESEARCHTYPE type;
16 HRESULT hrSearch;
17 VERUTIL_VERSION* pVersion;
18
19 struct
20 {
21 LPCWSTR wzTargetName;
22 DWORD dwMajorVersion;
23 } Runtime;
24 struct
25 {
26 DWORD dwMajorVersion;
27 } Sdk;
28 struct
29 {
30 DWORD dwMajorVersion;
31 DWORD dwMinorVersion;
32 DWORD dwPatchVersion;
33 } SdkFeatureBand;
34 };
35
36 static HRESULT GetSearchStateFromArguments(
37 __in int argc,
38 __in LPWSTR argv[],
39 __in NETCORESEARCH_STATE* pSearchState
40 );
41 static HRESULT GetDotnetEnvironmentInfo(
42 __in NETCORESEARCH_STATE* pSearchState
43 );
44 static void HOSTFXR_CALLTYPE GetDotnetEnvironmentInfoResult(
45 __in const hostfxr_dotnet_environment_info* pInfo,
46 __in LPVOID pvContext
47 );
48
49 int __cdecl wmain(int argc, LPWSTR argv[])
50 {
51 HRESULT hr = S_OK;
52 NETCORESEARCH_STATE searchState = { };
53
54 ConsoleInitialize();
55
56 hr = GetSearchStateFromArguments(argc, argv, &searchState);
57 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to parse arguments.");
58
59 hr = GetDotnetEnvironmentInfo(&searchState);
60 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to search.");
61
62 if (searchState.pVersion)
63 {
64 ConsoleWriteW(CONSOLE_COLOR_NORMAL, searchState.pVersion->sczVersion);
65 }
66
67 LExit:
68 ReleaseVerutilVersion(searchState.pVersion);
69 ConsoleUninitialize();
70 return hr;
71 }
72
73 HRESULT GetSearchStateFromArguments(
74 __in int argc,
75 __in LPWSTR argv[],
76 __in NETCORESEARCH_STATE* pSearchState
77 )
78 {
79 HRESULT hr = S_OK;
80 LPCWSTR wzSearchKind = NULL;
81
82 if (argc < 2)
83 {
84 ExitFunction1(hr = E_INVALIDARG);
85 }
86
87 wzSearchKind = argv[1];
88
89 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, wzSearchKind, -1, L"runtime", -1))
90 {
91 if (argc != 4)
92 {
93 ExitFunction1(hr = E_INVALIDARG);
94 }
95
96 LPCWSTR wzMajorVersion = argv[2];
97 LPCWSTR wzTargetName = argv[3];
98
99 pSearchState->type = NETCORESEARCHTYPE::Runtime;
100
101 hr = StrStringToUInt32(wzMajorVersion, 0, reinterpret_cast<UINT*>(&pSearchState->Runtime.dwMajorVersion));
102 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to get target version from: %ls", wzMajorVersion);
103
104 pSearchState->Runtime.wzTargetName = wzTargetName;
105 }
106 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, wzSearchKind, -1, L"sdk", -1))
107 {
108 if (argc != 3)
109 {
110 ExitFunction1(hr = E_INVALIDARG);
111 }
112
113 LPCWSTR wzMajorVersion = argv[2];
114
115 pSearchState->type = NETCORESEARCHTYPE::Sdk;
116
117 hr = StrStringToUInt32(wzMajorVersion, 0, reinterpret_cast<UINT*>(&pSearchState->Sdk.dwMajorVersion));
118 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to get sdk major version from: %ls", wzMajorVersion);
119 }
120 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, wzSearchKind, -1, L"sdkfeatureband", -1))
121 {
122 if (argc != 5)
123 {
124 ExitFunction1(hr = E_INVALIDARG);
125 }
126
127 LPCWSTR wzMajorVersion = argv[2];
128 LPCWSTR wzMinorVersion = argv[3];
129 LPCWSTR wzPatchVersion = argv[4];
130
131 pSearchState->type = NETCORESEARCHTYPE::SdkFeatureBand;
132
133 hr = StrStringToUInt32(wzMajorVersion, 0, reinterpret_cast<UINT*>(&pSearchState->SdkFeatureBand.dwMajorVersion));
134 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to get major version from: %ls", wzMajorVersion);
135
136 hr = StrStringToUInt32(wzMinorVersion, 0, reinterpret_cast<UINT*>(&pSearchState->SdkFeatureBand.dwMinorVersion));
137 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to get minor version from: %ls", wzMinorVersion);
138
139 hr = StrStringToUInt32(wzPatchVersion, 0, reinterpret_cast<UINT*>(&pSearchState->SdkFeatureBand.dwPatchVersion));
140 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to get patch version from: %ls", wzPatchVersion);
141 }
142 else
143 {
144 pSearchState->type = NETCORESEARCHTYPE::None;
145 ExitFunction1(hr = E_INVALIDARG);
146 }
147
148 LExit:
149 return hr;
150 }
151
152 static HRESULT GetDotnetEnvironmentInfo(
153 __in NETCORESEARCH_STATE* pState
154 )
155 {
156 HRESULT hr = S_OK;
157 LPWSTR sczProcessPath = NULL;
158 LPWSTR sczHostfxrPath = NULL;
159 HMODULE hModule = NULL;
160 hostfxr_get_dotnet_environment_info_fn pfnGetDotnetEnvironmentInfo = NULL;
161
162 hr = PathForCurrentProcess(&sczProcessPath, NULL);
163 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to get process path.");
164
165 hr = PathGetDirectory(sczProcessPath, &sczHostfxrPath);
166 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to get process directory.");
167
168 hr = StrAllocConcat(&sczHostfxrPath, L"hostfxr.dll", 0);
169 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to build hostfxr path.");
170
171 hModule = ::LoadLibraryExW(sczHostfxrPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
172 ConsoleExitOnNullWithLastError(hModule, hr, CONSOLE_COLOR_RED, "Failed to load hostfxr.");
173
174 pfnGetDotnetEnvironmentInfo = (hostfxr_get_dotnet_environment_info_fn)::GetProcAddress(hModule, "hostfxr_get_dotnet_environment_info");
175 ConsoleExitOnNullWithLastError(pfnGetDotnetEnvironmentInfo, hr, CONSOLE_COLOR_RED, "Failed to get address for hostfxr_get_dotnet_environment_info.");
176
177 hr = pfnGetDotnetEnvironmentInfo(NULL, NULL, GetDotnetEnvironmentInfoResult, pState);
178 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to get .NET Core environment info.");
179
180 hr = pState->hrSearch;
181 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to process .NET Core environment info.");
182
183 LExit:
184 ReleaseStr(sczHostfxrPath);
185 ReleaseStr(sczProcessPath);
186
187 if (hModule)
188 {
189 ::FreeLibrary(hModule);
190 }
191
192 return hr;
193 }
194
195 static HRESULT PerformRuntimeSearch(
196 __in const hostfxr_dotnet_environment_info* pInfo,
197 __in DWORD dwMajorVersion,
198 __in LPCWSTR wzTargetName,
199 __inout VERUTIL_VERSION** ppVersion
200 )
201 {
202 HRESULT hr = S_OK;
203 VERUTIL_VERSION* pFrameworkVersion = NULL;
204 int nCompare = 0;
205
206 for (size_t i = 0; i < pInfo->framework_count; ++i)
207 {
208 const hostfxr_dotnet_environment_framework_info* pFrameworkInfo = pInfo->frameworks + i;
209 ReleaseVerutilVersion(pFrameworkVersion);
210
211 if (CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, wzTargetName, -1, pFrameworkInfo->name, -1))
212 {
213 continue;
214 }
215
216 hr = VerParseVersion(pFrameworkInfo->version, 0, FALSE, &pFrameworkVersion);
217 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to parse framework version: %ls", pFrameworkInfo->version);
218
219 if (pFrameworkVersion->dwMajor != dwMajorVersion)
220 {
221 continue;
222 }
223
224 if (*ppVersion)
225 {
226 hr = VerCompareParsedVersions(*ppVersion, pFrameworkVersion, &nCompare);
227 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to compare versions.");
228
229 if (nCompare > -1)
230 {
231 continue;
232 }
233 }
234
235 ReleaseVerutilVersion(*ppVersion);
236 *ppVersion = pFrameworkVersion;
237 pFrameworkVersion = NULL;
238 }
239
240 LExit:
241 ReleaseVerutilVersion(pFrameworkVersion);
242
243 return hr;
244 }
245
246 static HRESULT PerformSdkSearch(
247 __in const hostfxr_dotnet_environment_info* pInfo,
248 __in BOOL fFeatureBand,
249 __in DWORD dwMajorVersion,
250 __in DWORD dwMinorVersion,
251 __in DWORD dwPatchVersion,
252 __inout VERUTIL_VERSION** ppVersion
253 )
254 {
255 HRESULT hr = S_OK;
256 VERUTIL_VERSION* pSdkVersion = NULL;
257 int nCompare = 0;
258 DWORD dwRequestedBand = dwPatchVersion / 100;
259
260 for (size_t i = 0; i < pInfo->sdk_count; ++i)
261 {
262 const hostfxr_dotnet_environment_sdk_info* pSdkInfo = pInfo->sdks + i;
263 ReleaseVerutilVersion(pSdkVersion);
264
265 hr = VerParseVersion(pSdkInfo->version, 0, FALSE, &pSdkVersion);
266 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to parse sdk version: %ls", pSdkInfo->version);
267
268 if (pSdkVersion->dwMajor != dwMajorVersion)
269 {
270 continue;
271 }
272
273 if (fFeatureBand)
274 {
275 if (pSdkVersion->dwMinor != dwMinorVersion)
276 {
277 continue;
278 }
279
280 if ((pSdkVersion->dwPatch / 100) != dwRequestedBand)
281 {
282 continue;
283 }
284 }
285
286 if (*ppVersion)
287 {
288 hr = VerCompareParsedVersions(*ppVersion, pSdkVersion, &nCompare);
289 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to compare versions.");
290
291 if (nCompare > -1)
292 {
293 continue;
294 }
295 }
296
297 ReleaseVerutilVersion(*ppVersion);
298 *ppVersion = pSdkVersion;
299 pSdkVersion = NULL;
300 }
301
302 LExit:
303 ReleaseVerutilVersion(pSdkVersion);
304
305 return hr;
306 }
307
308 static void HOSTFXR_CALLTYPE GetDotnetEnvironmentInfoResult(
309 __in const hostfxr_dotnet_environment_info* pInfo,
310 __in LPVOID pvContext
311 )
312 {
313 NETCORESEARCH_STATE* pState = static_cast<NETCORESEARCH_STATE*>(pvContext);
314 HRESULT hr = S_OK;
315
316 if (pState->type == NETCORESEARCHTYPE::Sdk)
317 {
318 hr = PerformSdkSearch(pInfo, FALSE, pState->Sdk.dwMajorVersion, 0, 0, &pState->pVersion);
319 }
320 else if (pState->type == NETCORESEARCHTYPE::SdkFeatureBand)
321 {
322 hr = PerformSdkSearch(pInfo, TRUE, pState->SdkFeatureBand.dwMajorVersion, pState->SdkFeatureBand.dwMinorVersion, pState->SdkFeatureBand.dwPatchVersion, &pState->pVersion);
323 }
324 else if (pState->type == NETCORESEARCHTYPE::Runtime)
325 {
326 hr = PerformRuntimeSearch(pInfo, pState->Runtime.dwMajorVersion, pState->Runtime.wzTargetName, &pState->pVersion);
327 }
328 else
329 {
330 hr = E_INVALIDARG;
331 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Invalid NETCORESEARCHTYPE.");
332 }
333
334 LExit:
335 pState->hrSearch = hr;
336 }