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//*****************************************************************************
5// SafeWrap.h
6//
7
8//
9// This file contains wrapper functions for Win32 API's that take SStrings
10// and use CLR-safe holders.
11//*****************************************************************************
12
13
14/*
15 Guidelines for SafeWrapper APIs:
16Most of these are 'common-sense', plus a few arbitrary decisions thrown in for
17consistency's sake.
18
19- THROWING: Throw on oom, but return all other failure codes.
20 The rationale here is that SString operations already throw, so to make these APIs
21 non-throwing would require an extra EX_TRY/EX_CATCH. Most callees will want to throw
22 on OOM anyways. So making these APIs non-throwing would mean an extra try/catch in
23 the caller + an extra check at the callee. We can eliminate that overhead and just make
24 it throwing.
25
26 Return non-oom failure codes because callees actually freqeuntly expect an API to fail.
27 For example, the callee will have special handling for file-not-found.
28
29 For convenience, you could add a no-throwing wrapper version of the API:
30 ClrGetEnvironmentVariable <-- default throws on oom.
31 ClrGetEnvironmentVariableNoThrow <-- never throws.
32
33- NAMING: Prefix the name with 'Clr', just like we do for win32 APIs going through hosting.
34
35- DON'T FORGET CONTRACTS: Most of these APIs will likely be Throws/GC_Notrigger.
36 Also use PRECONDITIONs + POSTCONDITIONS when possible.
37
38- SIGNATURES: Keep the method signture as close the the original win32 API as possible.
39 - Preserve the return type + value. (except allow it to throw on oom). If the return value
40 should be a holder, then use that as an out-parameter at the end of the argument list.
41 We don't want to return holders because that will cause the dtors to be called.
42 - For input strings use 'const SString &' instead of 'LPCWSTR'.
43 - Change ('out' string, length) pairs to 'SString &' (this is the convention the rest of the CLR uses for SStrings)
44 - Use Holders where appropriate.
45 - Preserve other parameters.
46
47- USE SSTRINGS TO AVOID BUFFER OVERRUN ISSUES: Repeated here for emphasis. Use SStrings when
48 applicable to make it very easy to verify the code does not have buffer overruns.
49 This will also simplify callsites from having to figure out the length of the output string.
50
51- USE YOUR BEST JUDGEMENT: The primary goal of these API wrappers is to embrace 'security-safe' practices.
52 Certainly take any additional steps to that goal. For example, it may make sense to eliminate
53 corner case inputs for a given API or to break a single confusing API up into several discrete and
54 move obvious APIs.
55
56*/
57#ifndef _safewrap_h_
58#define _safewrap_h_
59
60#include "holder.h"
61
62class SString;
63bool ClrGetEnvironmentVariable(LPCSTR szEnvVarName, SString & value);
64bool ClrGetEnvironmentVariableNoThrow(LPCSTR szEnvVarName, SString & value);
65void ClrGetModuleFileName(HMODULE hModule, SString & value);
66bool ClrGetModuleFileNameNoThrow(HMODULE hModule, SString & value);
67
68void ClrGetCurrentDirectory(SString & value);
69bool ClrGetCurrentDirectoryNoThrow(SString & value);
70
71
72/* --------------------------------------------------------------------------- *
73 * Simple wrapper around WszFindFirstFile/WszFindNextFile
74 * --------------------------------------------------------------------------- */
75class ClrDirectoryEnumerator
76{
77 WIN32_FIND_DATAW data;
78 FindHandleHolder dirHandle;
79 BOOL fFindNext; // Skip FindNextFile first time around
80
81public:
82 ClrDirectoryEnumerator(LPCWSTR pBaseDirectory, LPCWSTR pMask = W("*"));
83 bool Next();
84
85 LPCWSTR GetFileName()
86 {
87 return data.cFileName;
88 }
89
90 DWORD GetFileAttributes()
91 {
92 return data.dwFileAttributes;
93 }
94
95 void Close()
96 {
97 dirHandle.Clear();
98 }
99};
100
101// Read a REG_SZ (null-terminated string) value from the registry. Throws.
102void ClrRegReadString(HKEY hKey, const SString & szValueName, SString & value);
103
104/* --------------------------------------------------------------------------- *
105 * Simple wrapper around RegisterEventSource/ReportEvent/DeregisterEventSource
106 * --------------------------------------------------------------------------- */
107// Returns ERROR_SUCCESS if succeessful in reporting to event log, or
108// Windows error code to indicate the specific error.
109DWORD ClrReportEvent(
110 LPCWSTR pEventSource,
111 WORD wType,
112 WORD wCategory,
113 DWORD dwEventID,
114 PSID lpUserSid,
115 WORD wNumStrings,
116 LPCWSTR *lpStrings,
117 DWORD dwDataSize = 0,
118 LPVOID lpRawData = NULL);
119
120DWORD ClrReportEvent(
121 LPCWSTR pEventSource,
122 WORD wType,
123 WORD wCategory,
124 DWORD dwEventID,
125 PSID lpUserSid,
126 LPCWSTR pMessage);
127
128//*****************************************************************************
129// This provides a wrapper around GetFileSize() that forces it to fail
130// if the file is >4g and pdwHigh is NULL. Other than that, it acts like
131// the genuine GetFileSize().
132//
133//
134//*****************************************************************************
135DWORD inline SafeGetFileSize(HANDLE hFile, DWORD *pdwHigh)
136{
137 if (pdwHigh != NULL)
138 {
139 return ::GetFileSize(hFile, pdwHigh);
140 }
141 else
142 {
143 DWORD hi;
144 DWORD lo = ::GetFileSize(hFile, &hi);
145 if (lo == 0xffffffff && GetLastError() != NO_ERROR)
146 {
147 return lo;
148 }
149 // api succeeded. is the file too large?
150 if (hi != 0)
151 {
152 // there isn't really a good error to set here...
153 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
154 return 0xffffffff;
155 }
156
157 if (lo == 0xffffffff)
158 {
159 // note that a success return of (hi=0,lo=0xffffffff) will be
160 // treated as an error by the caller. Again, that's part of the
161 // price of being a slacker and not handling the high dword.
162 // We'll set a lasterror for him to pick up.
163 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
164 }
165
166 return lo;
167 }
168
169}
170
171#endif // _safewrap_h_
172