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 | // MSCoree.cpp |
6 | //***************************************************************************** |
7 | #include "stdafx.h" // Standard header. |
8 | |
9 | #include <utilcode.h> // Utility helpers. |
10 | #include <posterror.h> // Error handlers |
11 | #define INIT_GUIDS |
12 | #include <corpriv.h> |
13 | #include <winwrap.h> |
14 | #include <mscoree.h> |
15 | #include "shimload.h" |
16 | #include "metadataexports.h" |
17 | #include "ex.h" |
18 | |
19 | #include "product_version.h" |
20 | |
21 | #ifdef FEATURE_COMINTEROP |
22 | #include "ComCallUnmarshal.h" |
23 | #endif // FEATURE_COMINTEROP |
24 | |
25 | #include "clrprivhosting.h" |
26 | |
27 | #ifdef FEATURE_PROFAPI_ATTACH_DETACH |
28 | #include "../../vm/profattach.h" |
29 | #endif // FEATURE_PROFAPI_ATTACH_DETACH |
30 | |
31 | #include <dbgenginemetrics.h> |
32 | |
33 | // Locals. |
34 | BOOL STDMETHODCALLTYPE EEDllMain( // TRUE on success, FALSE on error. |
35 | HINSTANCE hInst, // Instance handle of the loaded module. |
36 | DWORD dwReason, // Reason for loading. |
37 | LPVOID lpReserved); // Unused. |
38 | |
39 | // Globals. |
40 | HINSTANCE g_hThisInst; // This library. |
41 | |
42 | #ifndef CROSSGEN_COMPILE |
43 | //***************************************************************************** |
44 | // Handle lifetime of loaded library. |
45 | //***************************************************************************** |
46 | |
47 | #include <shlwapi.h> |
48 | |
49 | #include <process.h> // for __security_init_cookie() |
50 | |
51 | extern "C" IExecutionEngine* IEE(); |
52 | |
53 | #ifdef NO_CRT_INIT |
54 | #define _CRT_INIT(hInstance, dwReason, lpReserved) (TRUE) |
55 | #else |
56 | extern "C" BOOL WINAPI _CRT_INIT(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved); |
57 | #endif |
58 | |
59 | extern "C" BOOL WINAPI DllMain(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved); |
60 | |
61 | // For the CoreClr, this is the real DLL entrypoint. We make ourselves the first entrypoint as |
62 | // we need to capture coreclr's hInstance before the C runtime initializes. This function |
63 | // will capture hInstance, let the C runtime initialize and then invoke the "classic" |
64 | // DllMain that initializes everything else. |
65 | extern "C" BOOL WINAPI CoreDllMain(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved) |
66 | { |
67 | STATIC_CONTRACT_NOTHROW; |
68 | |
69 | BOOL result; |
70 | switch (dwReason) |
71 | { |
72 | case DLL_PROCESS_ATTACH: |
73 | #ifndef FEATURE_PAL |
74 | // Make sure the /GS security cookie is initialized before we call anything else. |
75 | // BinScope detects the call to __security_init_cookie in its "Has Non-GS-friendly |
76 | // Initialization" check and makes it pass. |
77 | __security_init_cookie(); |
78 | #endif // FEATURE_PAL |
79 | |
80 | // It's critical that we invoke InitUtilCode() before the CRT initializes. |
81 | // We have a lot of global ctors that will break if we let the CRT initialize without |
82 | // this step having been done. |
83 | |
84 | CoreClrCallbacks cccallbacks; |
85 | cccallbacks.m_hmodCoreCLR = (HINSTANCE)hInstance; |
86 | cccallbacks.m_pfnIEE = IEE; |
87 | cccallbacks.m_pfnGetCORSystemDirectory = GetCORSystemDirectoryInternaL; |
88 | cccallbacks.m_pfnGetCLRFunction = GetCLRFunction; |
89 | InitUtilcode(cccallbacks); |
90 | |
91 | if (!(result = _CRT_INIT(hInstance, dwReason, lpReserved))) |
92 | { |
93 | // CRT_INIT may fail to initialize the CRT heap. Make sure we don't continue |
94 | // down a path that would trigger an AV and tear down the host process |
95 | break; |
96 | } |
97 | result = DllMain(hInstance, dwReason, lpReserved); |
98 | break; |
99 | |
100 | case DLL_THREAD_ATTACH: |
101 | _CRT_INIT(hInstance, dwReason, lpReserved); |
102 | result = DllMain(hInstance, dwReason, lpReserved); |
103 | break; |
104 | |
105 | case DLL_PROCESS_DETACH: // intentional fallthru |
106 | case DLL_THREAD_DETACH: |
107 | result = DllMain(hInstance, dwReason, lpReserved); |
108 | _CRT_INIT(hInstance, dwReason, lpReserved); |
109 | break; |
110 | |
111 | default: |
112 | result = FALSE; // it'd be an OS bug if we got here - not much we can do. |
113 | break; |
114 | } |
115 | return result; |
116 | } |
117 | |
118 | extern "C" |
119 | BOOL WINAPI DllMain(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved) |
120 | { |
121 | STATIC_CONTRACT_NOTHROW; |
122 | |
123 | switch (dwReason) |
124 | { |
125 | case DLL_PROCESS_ATTACH: |
126 | { |
127 | // Save the module handle. |
128 | g_hThisInst = (HINSTANCE)hInstance; |
129 | |
130 | // Prevent buffer-overruns |
131 | // If buffer is overrun, it is possible the saved callback has been trashed. |
132 | // The callback is unsafe. |
133 | //SetBufferOverrunHandler(); |
134 | if (!EEDllMain((HINSTANCE)hInstance, dwReason, lpReserved)) |
135 | { |
136 | return FALSE; |
137 | } |
138 | } |
139 | break; |
140 | |
141 | case DLL_PROCESS_DETACH: |
142 | { |
143 | EEDllMain((HINSTANCE)hInstance, dwReason, lpReserved); |
144 | } |
145 | break; |
146 | |
147 | case DLL_THREAD_DETACH: |
148 | { |
149 | EEDllMain((HINSTANCE)hInstance, dwReason, lpReserved); |
150 | } |
151 | break; |
152 | } |
153 | |
154 | return TRUE; |
155 | } |
156 | |
157 | #ifdef FEATURE_COMINTEROP |
158 | // --------------------------------------------------------------------------- |
159 | // %%Function: DllCanUnloadNowInternal |
160 | // |
161 | // Returns: |
162 | // S_FALSE - Indicating that COR, once loaded, may not be |
163 | // unloaded. |
164 | // --------------------------------------------------------------------------- |
165 | STDAPI DllCanUnloadNowInternal(void) |
166 | { |
167 | STATIC_CONTRACT_NOTHROW; |
168 | STATIC_CONTRACT_ENTRY_POINT; |
169 | |
170 | //we should never unload unless the process is dying |
171 | return S_FALSE; |
172 | } // DllCanUnloadNowInternal |
173 | |
174 | // --------------------------------------------------------------------------- |
175 | // %%Function: DllRegisterServerInternal |
176 | // |
177 | // Description: |
178 | // Registers |
179 | // --------------------------------------------------------------------------- |
180 | STDAPI DllRegisterServerInternal(HINSTANCE hMod, LPCWSTR version) |
181 | { |
182 | |
183 | CONTRACTL{ |
184 | NOTHROW; |
185 | GC_NOTRIGGER; |
186 | ENTRY_POINT; |
187 | PRECONDITION(CheckPointer(version)); |
188 | } CONTRACTL_END; |
189 | |
190 | return S_OK; |
191 | } // DllRegisterServerInternal |
192 | |
193 | // --------------------------------------------------------------------------- |
194 | // %%Function: DllUnregisterServerInternal |
195 | // --------------------------------------------------------------------------- |
196 | STDAPI DllUnregisterServerInternal(void) |
197 | { |
198 | |
199 | CONTRACTL |
200 | { |
201 | GC_NOTRIGGER; |
202 | NOTHROW; |
203 | ENTRY_POINT; |
204 | } |
205 | CONTRACTL_END; |
206 | |
207 | return S_OK; |
208 | |
209 | } // DllUnregisterServerInternal |
210 | #endif // FEATURE_COMINTEROP |
211 | |
212 | #endif // CROSSGEN_COMPILE |
213 | |
214 | HINSTANCE GetModuleInst() |
215 | { |
216 | LIMITED_METHOD_CONTRACT; |
217 | return (g_hThisInst); |
218 | } |
219 | |
220 | // --------------------------------------------------------------------------- |
221 | // %%Function: MetaDataGetDispenser |
222 | // This function gets the Dispenser interface given the CLSID and REFIID. |
223 | // --------------------------------------------------------------------------- |
224 | STDAPI MetaDataGetDispenser( // Return HRESULT |
225 | REFCLSID rclsid, // The class to desired. |
226 | REFIID riid, // Interface wanted on class factory. |
227 | LPVOID FAR *ppv) // Return interface pointer here. |
228 | { |
229 | |
230 | CONTRACTL { |
231 | NOTHROW; |
232 | GC_NOTRIGGER; |
233 | ENTRY_POINT; |
234 | PRECONDITION(CheckPointer(ppv)); |
235 | } CONTRACTL_END; |
236 | |
237 | NonVMComHolder<IClassFactory> pcf(NULL); |
238 | HRESULT hr; |
239 | BEGIN_ENTRYPOINT_NOTHROW; |
240 | |
241 | IfFailGo(MetaDataDllGetClassObject(rclsid, IID_IClassFactory, (void **) &pcf)); |
242 | hr = pcf->CreateInstance(NULL, riid, ppv); |
243 | |
244 | ErrExit: |
245 | END_ENTRYPOINT_NOTHROW; |
246 | |
247 | return (hr); |
248 | } |
249 | |
250 | // --------------------------------------------------------------------------- |
251 | // %%Function: GetMetaDataInternalInterface |
252 | // This function gets the IMDInternalImport given the metadata on memory. |
253 | // --------------------------------------------------------------------------- |
254 | STDAPI GetMetaDataInternalInterface( |
255 | LPVOID pData, // [IN] in memory metadata section |
256 | ULONG cbData, // [IN] size of the metadata section |
257 | DWORD flags, // [IN] MDInternal_OpenForRead or MDInternal_OpenForENC |
258 | REFIID riid, // [IN] desired interface |
259 | void **ppv) // [OUT] returned interface |
260 | { |
261 | CONTRACTL{ |
262 | NOTHROW; |
263 | GC_NOTRIGGER; |
264 | ENTRY_POINT; |
265 | PRECONDITION(CheckPointer(pData)); |
266 | PRECONDITION(CheckPointer(ppv)); |
267 | } CONTRACTL_END; |
268 | |
269 | HRESULT hr = S_OK; |
270 | BEGIN_ENTRYPOINT_NOTHROW; |
271 | |
272 | hr = GetMDInternalInterface(pData, cbData, flags, riid, ppv); |
273 | |
274 | END_ENTRYPOINT_NOTHROW; |
275 | return hr; |
276 | } |
277 | |
278 | // --------------------------------------------------------------------------- |
279 | // %%Function: GetMetaDataInternalInterfaceFromPublic |
280 | // This function gets the internal scopeless interface given the public |
281 | // scopeless interface. |
282 | // --------------------------------------------------------------------------- |
283 | STDAPI GetMetaDataInternalInterfaceFromPublic( |
284 | IUnknown *pv, // [IN] Given interface. |
285 | REFIID riid, // [IN] desired interface |
286 | void **ppv) // [OUT] returned interface |
287 | { |
288 | CONTRACTL{ |
289 | NOTHROW; |
290 | GC_NOTRIGGER; |
291 | ENTRY_POINT; |
292 | PRECONDITION(CheckPointer(pv)); |
293 | PRECONDITION(CheckPointer(ppv)); |
294 | } CONTRACTL_END; |
295 | |
296 | HRESULT hr = S_OK; |
297 | BEGIN_ENTRYPOINT_NOTHROW; |
298 | |
299 | hr = GetMDInternalInterfaceFromPublic(pv, riid, ppv); |
300 | |
301 | END_ENTRYPOINT_NOTHROW; |
302 | return hr; |
303 | } |
304 | |
305 | // --------------------------------------------------------------------------- |
306 | // %%Function: GetMetaDataPublicInterfaceFromInternal |
307 | // This function gets the public scopeless interface given the internal |
308 | // scopeless interface. |
309 | // --------------------------------------------------------------------------- |
310 | STDAPI GetMetaDataPublicInterfaceFromInternal( |
311 | void *pv, // [IN] Given interface. |
312 | REFIID riid, // [IN] desired interface. |
313 | void **ppv) // [OUT] returned interface |
314 | { |
315 | CONTRACTL{ |
316 | NOTHROW; |
317 | GC_NOTRIGGER; |
318 | PRECONDITION(CheckPointer(pv)); |
319 | PRECONDITION(CheckPointer(ppv)); |
320 | ENTRY_POINT; |
321 | } CONTRACTL_END; |
322 | |
323 | HRESULT hr = S_OK; |
324 | BEGIN_ENTRYPOINT_NOTHROW; |
325 | |
326 | hr = GetMDPublicInterfaceFromInternal(pv, riid, ppv); |
327 | |
328 | END_ENTRYPOINT_NOTHROW; |
329 | return hr; |
330 | } |
331 | |
332 | |
333 | // --------------------------------------------------------------------------- |
334 | // %%Function: ReopenMetaDataWithMemory |
335 | // This function gets the public scopeless interface given the internal |
336 | // scopeless interface. |
337 | // --------------------------------------------------------------------------- |
338 | STDAPI ReOpenMetaDataWithMemory( |
339 | void *pUnk, // [IN] Given scope. public interfaces |
340 | LPCVOID pData, // [in] Location of scope data. |
341 | ULONG cbData) // [in] Size of the data pointed to by pData. |
342 | { |
343 | CONTRACTL{ |
344 | NOTHROW; |
345 | GC_NOTRIGGER; |
346 | ENTRY_POINT; |
347 | PRECONDITION(CheckPointer(pUnk)); |
348 | PRECONDITION(CheckPointer(pData)); |
349 | } CONTRACTL_END; |
350 | |
351 | HRESULT hr = S_OK; |
352 | |
353 | BEGIN_ENTRYPOINT_NOTHROW; |
354 | hr = MDReOpenMetaDataWithMemory(pUnk, pData, cbData); |
355 | END_ENTRYPOINT_NOTHROW; |
356 | return hr; |
357 | } |
358 | |
359 | // --------------------------------------------------------------------------- |
360 | // %%Function: ReopenMetaDataWithMemoryEx |
361 | // This function gets the public scopeless interface given the internal |
362 | // scopeless interface. |
363 | // --------------------------------------------------------------------------- |
364 | STDAPI ReOpenMetaDataWithMemoryEx( |
365 | void *pUnk, // [IN] Given scope. public interfaces |
366 | LPCVOID pData, // [in] Location of scope data. |
367 | ULONG cbData, // [in] Size of the data pointed to by pData. |
368 | DWORD dwReOpenFlags) // [in] ReOpen flags |
369 | { |
370 | CONTRACTL{ |
371 | NOTHROW; |
372 | GC_NOTRIGGER; |
373 | ENTRY_POINT; |
374 | PRECONDITION(CheckPointer(pUnk)); |
375 | PRECONDITION(CheckPointer(pData)); |
376 | } CONTRACTL_END; |
377 | |
378 | HRESULT hr = S_OK; |
379 | |
380 | BEGIN_ENTRYPOINT_NOTHROW; |
381 | hr = MDReOpenMetaDataWithMemoryEx(pUnk, pData, cbData, dwReOpenFlags); |
382 | END_ENTRYPOINT_NOTHROW; |
383 | return hr; |
384 | } |
385 | |
386 | |
387 | #ifndef CROSSGEN_COMPILE |
388 | // --------------------------------------------------------------------------- |
389 | // %%Function: CoInitializeCor |
390 | // |
391 | // Parameters: |
392 | // fFlags - Initialization flags for the engine. See the |
393 | // COINITICOR enumerator for valid values. |
394 | // |
395 | // Returns: |
396 | // S_OK - On success |
397 | // |
398 | // Description: |
399 | // Reserved to initialize the Cor runtime engine explicitly. This currently |
400 | // does nothing. |
401 | // --------------------------------------------------------------------------- |
402 | STDAPI CoInitializeCor(DWORD fFlags) |
403 | { |
404 | WRAPPER_NO_CONTRACT; |
405 | |
406 | BEGIN_ENTRYPOINT_NOTHROW; |
407 | |
408 | // Since the CLR doesn't currently support being unloaded, we don't hold a ref |
409 | // count and don't even pretend to try to unload. |
410 | END_ENTRYPOINT_NOTHROW; |
411 | |
412 | return (S_OK); |
413 | } |
414 | |
415 | // --------------------------------------------------------------------------- |
416 | // %%Function: CoUninitializeCor |
417 | // |
418 | // Parameters: |
419 | // none |
420 | // |
421 | // Returns: |
422 | // Nothing |
423 | // |
424 | // Description: |
425 | // Function to indicate the client is done with the CLR. This currently does |
426 | // nothing. |
427 | // --------------------------------------------------------------------------- |
428 | STDAPI_(void) CoUninitializeCor(void) |
429 | { |
430 | WRAPPER_NO_CONTRACT; |
431 | |
432 | BEGIN_ENTRYPOINT_VOIDRET; |
433 | |
434 | // Since the CLR doesn't currently support being unloaded, we don't hold a ref |
435 | // count and don't even pretend to try to unload. |
436 | END_ENTRYPOINT_VOIDRET; |
437 | |
438 | } |
439 | |
440 | // Undef LoadStringRC & LoadStringRCEx so we can export these functions. |
441 | #undef LoadStringRC |
442 | #undef LoadStringRCEx |
443 | |
444 | // --------------------------------------------------------------------------- |
445 | // %%Function: LoadStringRC |
446 | // |
447 | // Parameters: |
448 | // none |
449 | // |
450 | // Returns: |
451 | // Nothing |
452 | // |
453 | // Description: |
454 | // Function to load a resource based on it's ID. |
455 | // --------------------------------------------------------------------------- |
456 | STDAPI LoadStringRC( |
457 | UINT iResourceID, |
458 | __out_ecount(iMax) __out_z LPWSTR szBuffer, |
459 | int iMax, |
460 | int bQuiet |
461 | ) |
462 | { |
463 | WRAPPER_NO_CONTRACT; |
464 | |
465 | HRESULT hr = S_OK; |
466 | |
467 | if (NULL == szBuffer) |
468 | return E_INVALIDARG; |
469 | if (0 == iMax) |
470 | return E_INVALIDARG; |
471 | |
472 | BEGIN_ENTRYPOINT_NOTHROW; |
473 | hr = UtilLoadStringRC(iResourceID, szBuffer, iMax, bQuiet); |
474 | END_ENTRYPOINT_NOTHROW; |
475 | return hr; |
476 | } |
477 | |
478 | // --------------------------------------------------------------------------- |
479 | // %%Function: LoadStringRCEx |
480 | // |
481 | // Parameters: |
482 | // none |
483 | // |
484 | // Returns: |
485 | // Nothing |
486 | // |
487 | // Description: |
488 | // Ex version of the function to load a resource based on it's ID. |
489 | // --------------------------------------------------------------------------- |
490 | #ifdef FEATURE_USE_LCID |
491 | STDAPI LoadStringRCEx( |
492 | LCID lcid, |
493 | UINT iResourceID, |
494 | __out_ecount(iMax) __out_z LPWSTR szBuffer, |
495 | int iMax, |
496 | int bQuiet, |
497 | int *pcwchUsed |
498 | ) |
499 | { |
500 | WRAPPER_NO_CONTRACT; |
501 | HRESULT hr = S_OK; |
502 | |
503 | if (NULL == szBuffer) |
504 | return E_INVALIDARG; |
505 | if (0 == iMax) |
506 | return E_INVALIDARG; |
507 | |
508 | BEGIN_ENTRYPOINT_NOTHROW; |
509 | hr = UtilLoadStringRCEx(lcid, iResourceID, szBuffer, iMax, bQuiet, pcwchUsed); |
510 | END_ENTRYPOINT_NOTHROW; |
511 | return hr; |
512 | } |
513 | #endif |
514 | // Redefine them as errors to prevent people from using these from inside the rest of the compilation unit. |
515 | #define LoadStringRC __error("From inside the CLR, use UtilLoadStringRC; LoadStringRC is only meant to be exported.") |
516 | #define LoadStringRCEx __error("From inside the CLR, use UtilLoadStringRCEx; LoadStringRC is only meant to be exported.") |
517 | |
518 | #endif // CROSSGEN_COMPILE |
519 | |
520 | |
521 | // Replacement for legacy shim API GetCORRequiredVersion(...) used in linked libraries. |
522 | // Used in code:TiggerStorage::GetDefaultVersion#CallTo_CLRRuntimeHostInternal_GetImageVersionString. |
523 | HRESULT |
524 | CLRRuntimeHostInternal_GetImageVersionString( |
525 | __out_ecount_opt(*pcchBuffer) LPWSTR wszBuffer, |
526 | __inout DWORD *pcchBuffer) |
527 | { |
528 | // Simply forward the call to the ICLRRuntimeHostInternal implementation. |
529 | STATIC_CONTRACT_WRAPPER; |
530 | |
531 | HRESULT hr = GetCORVersionInternal(wszBuffer, *pcchBuffer, pcchBuffer); |
532 | |
533 | return hr; |
534 | } // CLRRuntimeHostInternal_GetImageVersionString |
535 | |
536 | STDAPI GetCORSystemDirectoryInternaL(SString& pBuffer) |
537 | { |
538 | CONTRACTL { |
539 | NOTHROW; |
540 | GC_NOTRIGGER; |
541 | ENTRY_POINT; |
542 | } CONTRACTL_END; |
543 | |
544 | HRESULT hr = S_OK; |
545 | BEGIN_ENTRYPOINT_NOTHROW; |
546 | |
547 | |
548 | #ifdef CROSSGEN_COMPILE |
549 | |
550 | if (WszGetModuleFileName(NULL, pBuffer) > 0) |
551 | { |
552 | hr = CopySystemDirectory(pBuffer, pBuffer); |
553 | } |
554 | else { |
555 | hr = HRESULT_FROM_GetLastError(); |
556 | } |
557 | |
558 | #else |
559 | |
560 | if (!PAL_GetPALDirectoryWrapper(pBuffer)) { |
561 | hr = HRESULT_FROM_GetLastError(); |
562 | } |
563 | #endif |
564 | |
565 | END_ENTRYPOINT_NOTHROW; |
566 | return hr; |
567 | } |
568 | |
569 | // |
570 | // Returns version of the runtime (null-terminated). |
571 | // |
572 | // Arguments: |
573 | // pBuffer - [out] Output buffer allocated by caller of size cchBuffer. |
574 | // cchBuffer - Size of pBuffer in characters. |
575 | // pdwLength - [out] Size of the version string in characters (incl. null-terminator). Will be filled |
576 | // even if ERROR_INSUFFICIENT_BUFFER is returned. |
577 | // |
578 | // Return Value: |
579 | // S_OK - Output buffer contains the version string. |
580 | // HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) - *pdwLength contains required size of the buffer in |
581 | // characters. |
582 | |
583 | STDAPI GetCORVersionInternal( |
584 | __out_ecount_z_opt(cchBuffer) LPWSTR pBuffer, |
585 | DWORD cchBuffer, |
586 | __out DWORD *pdwLength) |
587 | { |
588 | CONTRACTL { |
589 | NOTHROW; |
590 | GC_NOTRIGGER; |
591 | ENTRY_POINT; |
592 | PRECONDITION(CheckPointer(pBuffer, NULL_OK)); |
593 | PRECONDITION(CheckPointer(pdwLength)); |
594 | } CONTRACTL_END; |
595 | |
596 | HRESULT hr; |
597 | BEGIN_ENTRYPOINT_NOTHROW; |
598 | |
599 | if ((pBuffer != NULL) && (cchBuffer > 0)) |
600 | { // Initialize the output for case the function fails |
601 | *pBuffer = W('\0'); |
602 | } |
603 | |
604 | #define VERSION_NUMBER_NOSHIM W("v") QUOTE_MACRO_L(CLR_MAJOR_VERSION.CLR_MINOR_VERSION.CLR_BUILD_VERSION) |
605 | |
606 | DWORD length = (DWORD)(wcslen(VERSION_NUMBER_NOSHIM) + 1); |
607 | if (length > cchBuffer) |
608 | { |
609 | hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); |
610 | } |
611 | else |
612 | { |
613 | if (pBuffer == NULL) |
614 | { |
615 | hr = E_POINTER; |
616 | } |
617 | else |
618 | { |
619 | CopyMemory(pBuffer, VERSION_NUMBER_NOSHIM, length * sizeof(WCHAR)); |
620 | hr = S_OK; |
621 | } |
622 | } |
623 | *pdwLength = length; |
624 | |
625 | END_ENTRYPOINT_NOTHROW; |
626 | return hr; |
627 | |
628 | } |
629 | |
630 | static DWORD g_dwSystemDirectory = 0; |
631 | static WCHAR * g_pSystemDirectory = NULL; |
632 | |
633 | HRESULT GetInternalSystemDirectory(__out_ecount_part_opt(*pdwLength,*pdwLength) LPWSTR buffer, __inout DWORD* pdwLength) |
634 | { |
635 | CONTRACTL { |
636 | NOTHROW; |
637 | GC_NOTRIGGER; |
638 | PRECONDITION(CheckPointer(buffer, NULL_OK)); |
639 | PRECONDITION(CheckPointer(pdwLength)); |
640 | } CONTRACTL_END; |
641 | |
642 | if (g_dwSystemDirectory == 0) |
643 | SetInternalSystemDirectory(); |
644 | |
645 | // |
646 | // g_dwSystemDirectory includes the NULL in its count! |
647 | // |
648 | if(*pdwLength < g_dwSystemDirectory) |
649 | { |
650 | *pdwLength = g_dwSystemDirectory; |
651 | return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); |
652 | } |
653 | |
654 | if (buffer != NULL) |
655 | { |
656 | // |
657 | // wcsncpy_s will automatically append a null and g_dwSystemDirectory |
658 | // includes the null in its count, so we have to subtract 1. |
659 | // |
660 | wcsncpy_s(buffer, *pdwLength, g_pSystemDirectory, g_dwSystemDirectory-1); |
661 | } |
662 | *pdwLength = g_dwSystemDirectory; |
663 | return S_OK; |
664 | } |
665 | |
666 | |
667 | LPCWSTR GetInternalSystemDirectory(__out DWORD* pdwLength) |
668 | { |
669 | LIMITED_METHOD_CONTRACT; |
670 | |
671 | if (g_dwSystemDirectory == 0) |
672 | { |
673 | SetInternalSystemDirectory(); |
674 | } |
675 | |
676 | if (pdwLength != NULL) |
677 | { |
678 | * pdwLength = g_dwSystemDirectory; |
679 | } |
680 | |
681 | return g_pSystemDirectory; |
682 | } |
683 | |
684 | |
685 | HRESULT SetInternalSystemDirectory() |
686 | { |
687 | CONTRACTL { |
688 | NOTHROW; |
689 | GC_NOTRIGGER; |
690 | } CONTRACTL_END; |
691 | |
692 | HRESULT hr = S_OK; |
693 | if(g_dwSystemDirectory == 0) { |
694 | |
695 | DWORD len = 0; |
696 | NewArrayHolder<WCHAR> pSystemDirectory; |
697 | EX_TRY{ |
698 | |
699 | // use local buffer for thread safety |
700 | PathString wzSystemDirectory; |
701 | |
702 | hr = GetCORSystemDirectoryInternaL(wzSystemDirectory); |
703 | |
704 | if (FAILED(hr)) { |
705 | wzSystemDirectory.Set(W('\0')); |
706 | } |
707 | |
708 | pSystemDirectory = wzSystemDirectory.GetCopyOfUnicodeString(); |
709 | if (pSystemDirectory == NULL) |
710 | { |
711 | hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); |
712 | } |
713 | len = wzSystemDirectory.GetCount() + 1; |
714 | |
715 | } |
716 | EX_CATCH_HRESULT(hr); |
717 | |
718 | // publish results idempotently with correct memory ordering |
719 | g_pSystemDirectory = pSystemDirectory.Extract(); |
720 | |
721 | (void)InterlockedExchange((LONG *)&g_dwSystemDirectory, len); |
722 | } |
723 | |
724 | return hr; |
725 | } |
726 | |
727 | #if defined(CROSSGEN_COMPILE) |
728 | void SetMscorlibPath(LPCWSTR wzSystemDirectory) |
729 | { |
730 | DWORD len = (DWORD)wcslen(wzSystemDirectory); |
731 | bool appendSeparator = wzSystemDirectory[len-1] != DIRECTORY_SEPARATOR_CHAR_W; |
732 | DWORD lenAlloc = appendSeparator ? len+2 : len+1; |
733 | if (g_dwSystemDirectory < lenAlloc) |
734 | { |
735 | delete [] g_pSystemDirectory; |
736 | g_pSystemDirectory = new (nothrow) WCHAR[lenAlloc]; |
737 | |
738 | if (g_pSystemDirectory == NULL) |
739 | { |
740 | SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
741 | return; |
742 | } |
743 | } |
744 | |
745 | wcscpy_s(g_pSystemDirectory, len+1, wzSystemDirectory); |
746 | |
747 | if(appendSeparator) |
748 | { |
749 | g_pSystemDirectory[len] = DIRECTORY_SEPARATOR_CHAR_W; |
750 | g_pSystemDirectory[len+1] = W('\0'); |
751 | g_dwSystemDirectory = len + 1; |
752 | } |
753 | else |
754 | { |
755 | g_dwSystemDirectory = len; |
756 | } |
757 | } |
758 | #endif |
759 | |