1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 //*****************************************************************************
9 // This file contains wrapper functions for Win32 API's that take SStrings
10 // and use CLR-safe holders.
12 // See guidelines in SafeWrap.h for writing these APIs.
13 //*****************************************************************************
15 #include "stdafx.h" // Precompiled header key.
17 #include "winwrap.h" // Header for macros and functions.
23 //-----------------------------------------------------------------------------
24 // Get the current directory.
25 // On success, returns true and sets 'Value' to unicode version of cur dir.
26 // Throws on all failures. This should mainly be oom.
27 //-----------------------------------------------------------------------------
28 void ClrGetCurrentDirectory(SString & value)
38 DWORD len = WszGetCurrentDirectory(value);
41 // An actual API failure in GetCurrentDirectory failure should be very rare, so we'll throw on those.
48 // Nothrowing wrapper.
49 bool ClrGetCurrentDirectoryNoThrow(SString & value)
61 ClrGetCurrentDirectory(value);
67 EX_END_CATCH(SwallowAllExceptions)
70 //-----------------------------------------------------------------------------
71 // Reads an environment variable into the given SString.
72 // Returns true on success, false on failure (includes if the var does not exist).
74 //-----------------------------------------------------------------------------
75 bool ClrGetEnvironmentVariable(LPCSTR szEnvVarName, SString & value)
82 PRECONDITION(szEnvVarName != NULL);
86 // First read it to get the needed length.
87 DWORD lenWithNull = GetEnvironmentVariableA(szEnvVarName, NULL, 0);
93 // Now read it for content.
94 char * pCharBuf = value.OpenANSIBuffer(lenWithNull);
95 DWORD lenWithoutNull = GetEnvironmentVariableA(szEnvVarName, pCharBuf, lenWithNull);
96 value.CloseBuffer(lenWithoutNull);
98 if (lenWithoutNull != (lenWithNull - 1))
100 // Env var must have changed underneath us.
106 // Nothrowing wrapper.
107 bool ClrGetEnvironmentVariableNoThrow(LPCSTR szEnvVarName, SString & value)
120 fOk = ClrGetEnvironmentVariable(szEnvVarName, value);
126 EX_END_CATCH(SwallowAllExceptions)
130 void ClrGetModuleFileName(HMODULE hModule, SString & value)
139 WCHAR * pCharBuf = value.OpenUnicodeBuffer(_MAX_PATH);
140 DWORD numChars = GetModuleFileNameW(hModule, pCharBuf, _MAX_PATH);
141 value.CloseBuffer(numChars);
144 bool ClrGetModuleFileNameNoThrow(HMODULE hModule, SString & value)
156 ClrGetModuleFileName(hModule, value);
162 EX_END_CATCH(SwallowAllExceptions)
166 ClrDirectoryEnumerator::ClrDirectoryEnumerator(LPCWSTR pBaseDirectory, LPCWSTR pMask /*= W("*")*/)
175 StackSString strMask(pBaseDirectory);
176 SString s(SString::Literal, DIRECTORY_SEPARATOR_STR_W);
177 if (!strMask.EndsWith(s))
181 strMask.Append(pMask);
182 dirHandle = WszFindFirstFile(strMask, &data);
184 if (dirHandle == INVALID_HANDLE_VALUE)
186 DWORD dwLastError = GetLastError();
188 // We either ran out of files, or didnt encounter even a single file matching the
189 // search mask. If it is neither of these conditions, then convert the error to an exception
191 if ((dwLastError != ERROR_FILE_NOT_FOUND) && (dwLastError != ERROR_NO_MORE_FILES))
198 bool ClrDirectoryEnumerator::Next()
207 if (dirHandle == INVALID_HANDLE_VALUE)
214 if (!WszFindNextFile(dirHandle, &data))
216 if (GetLastError() != ERROR_NO_MORE_FILES)
228 if (wcscmp(data.cFileName, W(".")) != 0 && wcscmp(data.cFileName, W("..")) != 0)
233 DWORD ClrReportEvent(
234 LPCWSTR pEventSource,
241 DWORD dwDataSize /*=0*/,
242 LPVOID lpRawData /*=NULL*/)
252 HANDLE h = ::RegisterEventSourceW(
253 NULL, // uses local computer
257 // Return the error code to the caller so that
258 // appropriate asserts/logging can be done
259 // incase of errors like event log being full
260 return GetLastError();
263 // Every event id should have matching description in dlls\shim\eventmsg.mc. This allows
264 // event view to know how to display message.
265 _ASSERTE (dwEventID != 0);
267 // Attempt to report the event to the event log. Note that if the operation fails
268 // (for example because of low memory conditions) it isn't fatal so we can safely ignore
269 // the return code from ReportEventW.
270 BOOL ret = ::ReportEventW(
271 h, // event log handle
281 DWORD dwRetStatus = GetLastError();
283 ::DeregisterEventSource(h);
285 return (ret == TRUE)?ERROR_SUCCESS:dwRetStatus;
287 // UNIXTODO: Report the event somewhere?
288 return ERROR_SUCCESS;
289 #endif // FEATURE_PAL
292 // Returns ERROR_SUCCESS if succeessful in reporting to event log, or
293 // Windows error code to indicate the specific error.
294 DWORD ClrReportEvent(
295 LPCWSTR pEventSource,
302 return ClrReportEvent(pEventSource, wType, wCategory, dwEventID, lpUserSid, 1, &pMessage);
306 // Read a REG_SZ (null-terminated string) value from the registry. Throws.
309 // hKey - key to registry hive.
310 // szValueName - null-terminated string for value name to lookup.
311 // If this is empty, this gets the (default) value in the registry hive.
312 // value - out parameter to hold registry value string contents.
315 // value is set on success. Throws on any failure, including if the value doesn't exist
316 // or if the value exists but is not a REG_SZ.
319 // REG_SZ is a single null-terminated string in the registry.
320 // This is only support on Windows because the registry is windows specific.
321 void ClrRegReadString(HKEY hKey, const SString & szValueName, SString & value)
333 // Preemptively clear the string such that it's empty in any failure case.
337 // Step 1: First call to find size of buffer and ensure data type is correct
339 LONG ret = WszRegQueryValueEx(
341 szValueName.GetUnicode(), // NULL or "\0" represents the (default) key.
343 &type, // should be REG_SZ
344 NULL, // not requesting data yet
348 if (ret != ERROR_SUCCESS)
355 // The registry value is not a string.
356 ThrowHR(E_INVALIDARG);
359 // REG_SZ includes the null terminator.
360 DWORD numCharsIncludingNull = numBytesData / sizeof(WCHAR);
363 // Step 2: Allocate buffer to hold final result
365 WCHAR * pData = value.OpenUnicodeBuffer(numCharsIncludingNull);
366 DWORD numBytesData2 = numBytesData;
370 // Step 3: Requery to get actual contents
372 ret = WszRegQueryValueEx(
374 szValueName.GetUnicode(),
376 &type, // should still be REG_SZ
381 // This check should only fail if the registry was changed inbetween the first query
382 // and the second. In practice, that should never actually happen.
383 if ((numBytesData2 != numBytesData) || (type != REG_SZ))
385 // On error, leave string empty.
386 value.CloseBuffer(0);
391 if (ret != ERROR_SUCCESS)
393 // On error, leave string empty.
394 value.CloseBuffer(0);
400 // Step 4: Close the string buffer
402 COUNT_T numCharsNoNull = numCharsIncludingNull - 1;
403 value.CloseBuffer(numCharsNoNull);
405 #endif // FEATURE_PAL