| 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 | |