2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
5 //*****************************************************************************
7 //*****************************************************************************
8 #include "stdafx.h" // Standard header.
10 #include <utilcode.h> // Utility helpers.
11 #include <posterror.h> // Error handlers
17 #include "metadataexports.h"
19 #if !defined(FEATURE_CORECLR)
23 #if defined(FEATURE_CORECLR)
24 #include "product_version.h"
25 #endif // FEATURE_CORECLR
27 #ifdef FEATURE_COMINTEROP
28 #include "ComCallUnmarshal.h"
29 #endif // FEATURE_COMINTEROP
31 #if !defined(FEATURE_CORECLR) && !defined(CROSSGEN_COMPILE)
33 extern ICLRRuntimeInfo *g_pCLRRuntime;
34 #endif // !FEATURE_CORECLR && !CROSSGEN_COMPILE
36 #ifdef FEATURE_HOSTED_BINDER
37 #include "clrprivhosting.h"
40 #ifndef FEATURE_CORECLR
41 #include "clr/win32.h"
42 #endif // FEATURE_CORECLR
44 #ifdef FEATURE_PROFAPI_ATTACH_DETACH
45 #include "../../vm/profattach.h"
46 #endif // FEATURE_PROFAPI_ATTACH_DETACH
49 #if defined(FEATURE_CORECLR)
50 #include <dbgenginemetrics.h>
51 #endif // FEATURE_CORECLR
54 BOOL STDMETHODCALLTYPE EEDllMain( // TRUE on success, FALSE on error.
55 HINSTANCE hInst, // Instance handle of the loaded module.
56 DWORD dwReason, // Reason for loading.
57 LPVOID lpReserved); // Unused.
59 #ifdef FEATURE_COMINTEROP_MANAGED_ACTIVATION
60 // try to load a com+ class and give out an IClassFactory
61 HRESULT STDMETHODCALLTYPE EEDllGetClassObject(
65 #endif // FEATURE_COMINTEROP_MANAGED_ACTIVATION
68 HINSTANCE g_hThisInst; // This library.
70 #ifndef CROSSGEN_COMPILE
71 //*****************************************************************************
72 // Handle lifetime of loaded library.
73 //*****************************************************************************
75 #ifdef FEATURE_MERGE_JIT_AND_ENGINE
76 void jitOnDllProcessAttach();
77 void jitOnDllProcessDetach();
78 #endif // FEATURE_MERGE_JIT_AND_ENGINE
81 #ifdef FEATURE_CORECLR
85 #include <process.h> // for __security_init_cookie()
87 void* __stdcall GetCLRFunction(LPCSTR FunctionName);
89 extern "C" IExecutionEngine* __stdcall IEE();
92 #define _CRT_INIT(hInstance, dwReason, lpReserved) (TRUE)
94 extern "C" BOOL WINAPI _CRT_INIT(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved);
97 extern "C" BOOL WINAPI DllMain(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved);
99 // For the CoreClr, this is the real DLL entrypoint. We make ourselves the first entrypoint as
100 // we need to capture coreclr's hInstance before the C runtine initializes. This function
101 // will capture hInstance, let the C runtime initialize and then invoke the "classic"
102 // DllMain that initializes everything else.
103 extern "C" BOOL WINAPI CoreDllMain(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved)
105 STATIC_CONTRACT_NOTHROW;
110 case DLL_PROCESS_ATTACH:
112 // Make sure the /GS security cookie is initialized before we call anything else.
113 // BinScope detects the call to __security_init_cookie in its "Has Non-GS-friendly
114 // Initialization" check and makes it pass.
115 __security_init_cookie();
116 #endif // FEATURE_PAL
118 // It's critical that we invoke InitUtilCode() before the CRT initializes.
119 // We have a lot of global ctors that will break if we let the CRT initialize without
120 // this step having been done.
122 CoreClrCallbacks cccallbacks;
123 cccallbacks.m_hmodCoreCLR = (HINSTANCE)hInstance;
124 cccallbacks.m_pfnIEE = IEE;
125 cccallbacks.m_pfnGetCORSystemDirectory = GetCORSystemDirectoryInternal;
126 cccallbacks.m_pfnGetCLRFunction = GetCLRFunction;
127 InitUtilcode(cccallbacks);
129 if (!(result = _CRT_INIT(hInstance, dwReason, lpReserved)))
131 // CRT_INIT may fail to initialize the CRT heap. Make sure we don't continue
132 // down a path that would trigger an AV and tear down the host process
135 result = DllMain(hInstance, dwReason, lpReserved);
138 case DLL_THREAD_ATTACH:
139 _CRT_INIT(hInstance, dwReason, lpReserved);
140 result = DllMain(hInstance, dwReason, lpReserved);
143 case DLL_PROCESS_DETACH: // intentional fallthru
144 case DLL_THREAD_DETACH:
145 result = DllMain(hInstance, dwReason, lpReserved);
146 _CRT_INIT(hInstance, dwReason, lpReserved);
150 result = FALSE; // it'd be an OS bug if we got here - not much we can do.
155 #endif //FEATURE_CORECLR
158 BOOL WINAPI DllMain(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved)
160 STATIC_CONTRACT_NOTHROW;
164 case DLL_PROCESS_ATTACH:
166 // Save the module handle.
167 g_hThisInst = (HINSTANCE)hInstance;
169 #ifndef FEATURE_CORECLR
170 // clr.dll cannot be unloaded
171 // Normally the shim prevents it from ever being unloaded, but we now support fusion loading
172 // us directly, so we need to take an extra ref on our handle to ensure we don't get unloaded.
173 if (FAILED(clr::win32::PreventModuleUnload(g_hThisInst)))
177 #endif // FEATURE_CORECLR
179 // Prevent buffer-overruns
180 // If buffer is overrun, it is possible the saved callback has been trashed.
181 // The callback is unsafe.
182 //SetBufferOverrunHandler();
184 DacGlobals::Initialize();
186 if (!EEDllMain((HINSTANCE)hInstance, dwReason, lpReserved))
191 #ifdef FEATURE_MERGE_JIT_AND_ENGINE
192 jitOnDllProcessAttach();
193 #endif // FEATURE_MERGE_JIT_AND_ENGINE
197 case DLL_PROCESS_DETACH:
200 PAL_CleanupDacTableAddress();
202 EEDllMain((HINSTANCE)hInstance, dwReason, lpReserved);
204 #ifdef FEATURE_MERGE_JIT_AND_ENGINE
205 jitOnDllProcessDetach();
206 #endif // FEATURE_MERGE_JIT_AND_ENGINE
211 case DLL_THREAD_DETACH:
213 EEDllMain((HINSTANCE)hInstance, dwReason, lpReserved);
221 #ifndef FEATURE_CORECLR // coreclr does not export this
222 // ---------------------------------------------------------------------------
223 // %%Function: DllGetClassObjectInternal %%Owner: NatBro %%Reviewed: 00/00/00
226 // rclsid - reference to the CLSID of the object whose
227 // ClassObject is being requested
228 // iid - reference to the IID of the interface on the
229 // ClassObject that the caller wants to communicate
231 // ppv - location to return reference to the interface
235 // S_OK - if successful, valid interface returned in *ppv,
236 // otherwise *ppv is set to NULL and one of the
237 // following errors is returned:
238 // E_NOINTERFACE - ClassObject doesn't support requested interface
239 // CLASS_E_CLASSNOTAVAILABLE - clsid does not correspond to a supported class
242 // Returns a reference to the iid interface on the main COR ClassObject.
243 // This function is one of the required by-name entry points for COM
244 // DLL's. Its purpose is to provide a ClassObject which by definition
245 // supports at least IClassFactory and can therefore create instances of
246 // objects of the given class.
247 // ---------------------------------------------------------------------------
249 #ifdef FEATURE_COMINTEROP
250 // This could be merged with Metadata's class factories!
251 static CComCallUnmarshalFactory g_COMCallUnmarshal;
252 #endif // FEATURE_COMINTEROP
254 STDAPI InternalDllGetClassObject(
259 // @todo: this is called before the runtime is really started, so the contract's don't work.
260 STATIC_CONTRACT_NOTHROW;
261 STATIC_CONTRACT_SO_TOLERANT;
263 HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
264 BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW);
267 if (rclsid == CLSID_CorMetaDataDispenser || rclsid == CLSID_CorMetaDataDispenserRuntime ||
268 rclsid == CLSID_CorRuntimeHost || rclsid == CLSID_CLRRuntimeHost ||
269 rclsid == CLSID_TypeNameFactory
270 #ifdef FEATURE_HOSTED_BINDER
271 || rclsid == __uuidof(CLRPrivRuntime)
275 hr = MetaDataDllGetClassObject(rclsid, riid, ppv);
277 #ifdef FEATURE_PROFAPI_ATTACH_DETACH
278 else if (rclsid == CLSID_CLRProfiling)
280 hr = ICLRProfilingGetClassObject(rclsid, riid, ppv);
282 #endif // FEATURE_PROFAPI_ATTACH_DETACH
283 #ifdef FEATURE_COMINTEROP
284 else if (rclsid == CLSID_ComCallUnmarshal || rclsid == CLSID_ComCallUnmarshalV4)
286 // We still respond to the 1.0/1.1/2.0 CLSID so we don't break anyone who is instantiating
287 // this (we could be called for CLSID_ComCallUnmarshal if the process is rollForward=true)
288 hr = g_COMCallUnmarshal.QueryInterface(riid, ppv);
290 else if (rclsid == CLSID_CorSymBinder_SxS)
294 // PDB format - use diasymreader.dll with COM activation
295 InlineSString<_MAX_PATH> ssBuf;
296 hr = FakeCoCallDllGetClassObject(rclsid,
297 GetHModuleDirectory(GetModuleInst(), ssBuf).GetUnicode(),
302 EX_CATCH_HRESULT(hr);
306 #ifdef FEATURE_COMINTEROP_MANAGED_ACTIVATION
307 // Returns a managed object imported into COM-classic.
308 hr = EEDllGetClassObject(rclsid,riid,ppv);
309 #endif // FEATURE_COMINTEROP_MANAGED_ACTIVATION
311 #endif // FEATURE_COMINTEROP
313 END_SO_INTOLERANT_CODE;
315 } // InternalDllGetClassObject
318 STDAPI DllGetClassObjectInternal(
323 STATIC_CONTRACT_NOTHROW;
324 STATIC_CONTRACT_ENTRY_POINT;
327 BEGIN_ENTRYPOINT_NOTHROW;
329 // InternalDllGetClassObject exists to resolve an issue
330 // on FreeBSD, where libsscoree.so's DllGetClassObject's
331 // call to DllGetClassObjectInternal() was being bound to
332 // the implementation in libmscordbi.so, not the one in
333 // libsscoree.so. The fix is to disambiguate the name.
334 hr = InternalDllGetClassObject(rclsid, riid, ppv);
335 END_ENTRYPOINT_NOTHROW;
339 #endif // FEATURE_CORECLR
341 #ifdef FEATURE_COMINTEROP
342 // ---------------------------------------------------------------------------
343 // %%Function: DllCanUnloadNowInternal
346 // S_FALSE - Indicating that COR, once loaded, may not be
348 // ---------------------------------------------------------------------------
349 STDAPI DllCanUnloadNowInternal(void)
351 STATIC_CONTRACT_NOTHROW;
352 STATIC_CONTRACT_ENTRY_POINT;
354 //we should never unload unless the process is dying
356 } // DllCanUnloadNowInternal
358 // ---------------------------------------------------------------------------
359 // %%Function: DllRegisterServerInternal
363 // ---------------------------------------------------------------------------
364 STDAPI DllRegisterServerInternal(HINSTANCE hMod, LPCWSTR version)
371 PRECONDITION(CheckPointer(version));
375 } // DllRegisterServerInternal
377 // ---------------------------------------------------------------------------
378 // %%Function: DllUnregisterServerInternal
379 // ---------------------------------------------------------------------------
380 STDAPI DllUnregisterServerInternal(void)
393 } // DllUnregisterServerInternal
394 #endif // FEATURE_COMINTEROP
396 #endif // CROSSGEN_COMPILE
398 HINSTANCE GetModuleInst()
400 LIMITED_METHOD_CONTRACT;
401 return (g_hThisInst);
404 // ---------------------------------------------------------------------------
405 // %%Function: MetaDataGetDispenser
406 // This function gets the Dispenser interface given the CLSID and REFIID.
407 // ---------------------------------------------------------------------------
408 STDAPI MetaDataGetDispenser( // Return HRESULT
409 REFCLSID rclsid, // The class to desired.
410 REFIID riid, // Interface wanted on class factory.
411 LPVOID FAR *ppv) // Return interface pointer here.
418 PRECONDITION(CheckPointer(ppv));
421 NonVMComHolder<IClassFactory> pcf(NULL);
423 BEGIN_ENTRYPOINT_NOTHROW;
425 IfFailGo(MetaDataDllGetClassObject(rclsid, IID_IClassFactory, (void **) &pcf));
426 hr = pcf->CreateInstance(NULL, riid, ppv);
429 END_ENTRYPOINT_NOTHROW;
434 // ---------------------------------------------------------------------------
435 // %%Function: GetMetaDataInternalInterface
436 // This function gets the IMDInternalImport given the metadata on memory.
437 // ---------------------------------------------------------------------------
438 STDAPI GetMetaDataInternalInterface(
439 LPVOID pData, // [IN] in memory metadata section
440 ULONG cbData, // [IN] size of the metadata section
441 DWORD flags, // [IN] MDInternal_OpenForRead or MDInternal_OpenForENC
442 REFIID riid, // [IN] desired interface
443 void **ppv) // [OUT] returned interface
449 PRECONDITION(CheckPointer(pData));
450 PRECONDITION(CheckPointer(ppv));
454 BEGIN_ENTRYPOINT_NOTHROW;
456 hr = GetMDInternalInterface(pData, cbData, flags, riid, ppv);
458 END_ENTRYPOINT_NOTHROW;
462 // ---------------------------------------------------------------------------
463 // %%Function: GetMetaDataInternalInterfaceFromPublic
464 // This function gets the internal scopeless interface given the public
465 // scopeless interface.
466 // ---------------------------------------------------------------------------
467 STDAPI GetMetaDataInternalInterfaceFromPublic(
468 IUnknown *pv, // [IN] Given interface.
469 REFIID riid, // [IN] desired interface
470 void **ppv) // [OUT] returned interface
476 PRECONDITION(CheckPointer(pv));
477 PRECONDITION(CheckPointer(ppv));
481 BEGIN_ENTRYPOINT_NOTHROW;
483 hr = GetMDInternalInterfaceFromPublic(pv, riid, ppv);
485 END_ENTRYPOINT_NOTHROW;
489 // ---------------------------------------------------------------------------
490 // %%Function: GetMetaDataPublicInterfaceFromInternal
491 // This function gets the public scopeless interface given the internal
492 // scopeless interface.
493 // ---------------------------------------------------------------------------
494 STDAPI GetMetaDataPublicInterfaceFromInternal(
495 void *pv, // [IN] Given interface.
496 REFIID riid, // [IN] desired interface.
497 void **ppv) // [OUT] returned interface
502 PRECONDITION(CheckPointer(pv));
503 PRECONDITION(CheckPointer(ppv));
508 BEGIN_ENTRYPOINT_NOTHROW;
510 hr = GetMDPublicInterfaceFromInternal(pv, riid, ppv);
512 END_ENTRYPOINT_NOTHROW;
517 // ---------------------------------------------------------------------------
518 // %%Function: ReopenMetaDataWithMemory
519 // This function gets the public scopeless interface given the internal
520 // scopeless interface.
521 // ---------------------------------------------------------------------------
522 STDAPI ReOpenMetaDataWithMemory(
523 void *pUnk, // [IN] Given scope. public interfaces
524 LPCVOID pData, // [in] Location of scope data.
525 ULONG cbData) // [in] Size of the data pointed to by pData.
531 PRECONDITION(CheckPointer(pUnk));
532 PRECONDITION(CheckPointer(pData));
537 BEGIN_ENTRYPOINT_NOTHROW;
538 hr = MDReOpenMetaDataWithMemory(pUnk, pData, cbData);
539 END_ENTRYPOINT_NOTHROW;
543 // ---------------------------------------------------------------------------
544 // %%Function: ReopenMetaDataWithMemoryEx
545 // This function gets the public scopeless interface given the internal
546 // scopeless interface.
547 // ---------------------------------------------------------------------------
548 STDAPI ReOpenMetaDataWithMemoryEx(
549 void *pUnk, // [IN] Given scope. public interfaces
550 LPCVOID pData, // [in] Location of scope data.
551 ULONG cbData, // [in] Size of the data pointed to by pData.
552 DWORD dwReOpenFlags) // [in] ReOpen flags
558 PRECONDITION(CheckPointer(pUnk));
559 PRECONDITION(CheckPointer(pData));
564 BEGIN_ENTRYPOINT_NOTHROW;
565 hr = MDReOpenMetaDataWithMemoryEx(pUnk, pData, cbData, dwReOpenFlags);
566 END_ENTRYPOINT_NOTHROW;
570 #ifdef FEATURE_FUSION
571 // ---------------------------------------------------------------------------
572 // %%Function: GetAssemblyMDImport
573 // This function gets the IMDAssemblyImport given the filename
574 // ---------------------------------------------------------------------------
575 STDAPI GetAssemblyMDImport( // Return code.
576 LPCWSTR szFileName, // [in] The scope to open.
577 REFIID riid, // [in] The interface desired.
578 IUnknown **ppIUnk) // [out] Return interface on success.
587 BEGIN_ENTRYPOINT_NOTHROW;
589 hr=GetAssemblyMDInternalImport(szFileName, riid, ppIUnk);
590 END_ENTRYPOINT_NOTHROW;
595 #ifndef CROSSGEN_COMPILE
596 // ---------------------------------------------------------------------------
597 // %%Function: CoInitializeCor
600 // fFlags - Initialization flags for the engine. See the
601 // COINITICOR enumerator for valid values.
607 // Reserved to initialize the Cor runtime engine explicitly. This currently
609 // ---------------------------------------------------------------------------
610 STDAPI CoInitializeCor(DWORD fFlags)
614 BEGIN_ENTRYPOINT_NOTHROW;
616 // Since the CLR doesn't currently support being unloaded, we don't hold a ref
617 // count and don't even pretend to try to unload.
618 END_ENTRYPOINT_NOTHROW;
623 // ---------------------------------------------------------------------------
624 // %%Function: CoUninitializeCor
633 // Function to indicate the client is done with the CLR. This currently does
635 // ---------------------------------------------------------------------------
636 STDAPI_(void) CoUninitializeCor(void)
640 BEGIN_ENTRYPOINT_VOIDRET;
642 // Since the CLR doesn't currently support being unloaded, we don't hold a ref
643 // count and don't even pretend to try to unload.
644 END_ENTRYPOINT_VOIDRET;
648 // Undef LoadStringRC & LoadStringRCEx so we can export these functions.
650 #undef LoadStringRCEx
652 // ---------------------------------------------------------------------------
653 // %%Function: LoadStringRC
662 // Function to load a resource based on it's ID.
663 // ---------------------------------------------------------------------------
666 __out_ecount(iMax) __out_z LPWSTR szBuffer,
675 if (NULL == szBuffer)
680 BEGIN_ENTRYPOINT_NOTHROW;
681 hr = UtilLoadStringRC(iResourceID, szBuffer, iMax, bQuiet);
682 END_ENTRYPOINT_NOTHROW;
686 // ---------------------------------------------------------------------------
687 // %%Function: LoadStringRCEx
696 // Ex version of the function to load a resource based on it's ID.
697 // ---------------------------------------------------------------------------
698 #ifdef FEATURE_USE_LCID
699 STDAPI LoadStringRCEx(
702 __out_ecount(iMax) __out_z LPWSTR szBuffer,
711 if (NULL == szBuffer)
716 BEGIN_ENTRYPOINT_NOTHROW;
717 hr = UtilLoadStringRCEx(lcid, iResourceID, szBuffer, iMax, bQuiet, pcwchUsed);
718 END_ENTRYPOINT_NOTHROW;
722 // Redefine them as errors to prevent people from using these from inside the rest of the compilation unit.
723 #define LoadStringRC __error("From inside the CLR, use UtilLoadStringRC; LoadStringRC is only meant to be exported.")
724 #define LoadStringRCEx __error("From inside the CLR, use UtilLoadStringRCEx; LoadStringRC is only meant to be exported.")
726 #endif // CROSSGEN_COMPILE
729 #if defined(FEATURE_CORECLR) || defined(CROSSGEN_COMPILE)
732 // Returns path name from a file name. The path name will be (null-terminated, incl. the last '\' if present).
733 // Example: For input "C:\Windows\System.dll" returns "C:\Windows\".
734 // Warning: The input file name string might be destroyed.
737 // pFileName - [in] Null-terminated file name. Will be destroyed (an additional null-terminator might be
738 // written into the string).
739 // pBuffer - [out] buffer allocated by caller of size cchBuffer.
740 // cchBuffer - Size of pBuffer in characters.
741 // pdwLength - [out] Size of the path name in characters (incl. null-terminator). Will be filled even if
742 // ERROR_INSUFFICIENT_BUFFER is returned.
745 // S_OK - Output buffer contains path name.
746 // HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) - *pdwLength contains required size of the buffer in
748 // other errors - If input parameters are incorrect (NULL).
751 HRESULT CopySystemDirectory(__in WCHAR *pFileName,
752 __out_ecount_z_opt(cchBuffer) LPWSTR pBuffer,
754 __out DWORD *pdwLength)
756 if ((pBuffer != NULL) && (cchBuffer > 0))
757 { // Initialize the output for case the function fails
761 if (pdwLength == NULL)
765 if (pFileName == NULL)
766 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
768 SIZE_T dwFileNameLength = wcslen(pFileName);
769 LPWSTR pSeparator = wcsrchr(pFileName, W('\\'));
770 if (pSeparator != NULL)
772 dwFileNameLength = (DWORD)(pSeparator - pFileName + 1);
773 pFileName[dwFileNameLength] = W('\0');
776 dwFileNameLength++; // Add back in the null
777 *pdwLength = (DWORD)dwFileNameLength;
778 if ((dwFileNameLength > cchBuffer) || (pBuffer == NULL))
780 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
786 dwFileNameLength * sizeof(WCHAR));
791 extern HINSTANCE g_pMSCorEE;
795 BOOL PAL_GetPALDirectory(__out_ecount(cchBuffer) LPWSTR pbuffer,
801 WCHAR pPath[MAX_PATH];
802 DWORD dwPath = MAX_PATH;
804 #ifndef CROSSGEN_COMPILE
805 _ASSERTE(g_pMSCorEE != NULL);
808 dwPath = WszGetModuleFileName(g_pMSCorEE, pPath, dwPath);
811 hr = HRESULT_FROM_GetLastErrorNA();
816 hr = CopySystemDirectory(pPath, pbuffer, cchBuffer, &dwLength);
822 BOOL PAL_GetPALDirectoryW(__out_ecount(cchBuffer) LPWSTR pbuffer,
825 return PAL_GetPALDirectory(pbuffer, cchBuffer);
828 #endif // FEATURE_PAL
830 #endif // FEATURE_CORECLR || CROSSGEN_COMPILE
833 // Note that there are currently two callers of this function: code:CCompRC.LoadLibrary
834 // and code:CorLaunchApplication.
835 STDAPI GetRequestedRuntimeInfoInternal(LPCWSTR pExe,
837 LPCWSTR pConfigurationFile,
839 DWORD runtimeInfoFlags,
840 __out_ecount_opt(dwDirectory) LPWSTR pDirectory,
842 __out_opt DWORD *pdwDirectoryLength,
843 __out_ecount_opt(cchBuffer) LPWSTR pVersion,
845 __out_opt DWORD* pdwLength)
852 PRECONDITION(pDirectory != NULL && pVersion != NULL && cchBuffer > 0);
855 // for simplicity we will cheat and return the entire system directory in pDirectory
857 if (pdwLength != NULL)
860 if (pdwDirectoryLength == NULL)
861 pdwDirectoryLength = &dwDirectory;
863 return GetCORSystemDirectoryInternal(pDirectory, dwDirectory, pdwDirectoryLength);
866 // Replacement for legacy shim API GetCORRequiredVersion(...) used in linked libraries.
867 // Used in code:TiggerStorage::GetDefaultVersion#CallTo_CLRRuntimeHostInternal_GetImageVersionString.
869 CLRRuntimeHostInternal_GetImageVersionString(
870 __out_ecount_opt(*pcchBuffer) LPWSTR wszBuffer,
871 __inout DWORD *pcchBuffer)
873 // Simply forward the call to the ICLRRuntimeHostInternal implementation.
874 STATIC_CONTRACT_WRAPPER;
876 #if defined(FEATURE_CORECLR) || defined(CROSSGEN_COMPILE)
877 HRESULT hr = GetCORVersionInternal(wszBuffer, *pcchBuffer, pcchBuffer);
879 ReleaseHolder<ICLRRuntimeHostInternal> pRuntimeHostInternal;
880 HRESULT hr = g_pCLRRuntime->GetInterface(CLSID_CLRRuntimeHostInternal,
881 IID_ICLRRuntimeHostInternal,
882 &pRuntimeHostInternal);
885 hr = pRuntimeHostInternal->GetImageVersionString(wszBuffer, pcchBuffer);
890 } // CLRRuntimeHostInternal_GetImageVersionString
893 STDAPI GetCORSystemDirectoryInternal(__out_ecount_part_opt(cchBuffer, *pdwLength) LPWSTR pBuffer,
895 __out_opt DWORD* pdwLength)
897 #if defined(FEATURE_CORECLR) || defined(CROSSGEN_COMPILE)
903 PRECONDITION(CheckPointer(pBuffer, NULL_OK));
904 PRECONDITION(CheckPointer(pdwLength, NULL_OK));
908 BEGIN_ENTRYPOINT_NOTHROW;
910 if(pdwLength == NULL)
916 if (!PAL_GetPALDirectory(pBuffer, cchBuffer)) {
917 IfFailGo(HRESULT_FROM_GetLastError());
920 // Include the null terminator in the length
921 *pdwLength = (DWORD)wcslen(pBuffer)+1;
924 END_ENTRYPOINT_NOTHROW;
927 #else // FEATURE_CORECLR || CROSSGEN_COMPILE
929 // Simply forward the call to the ICLRRuntimeInfo implementation.
930 STATIC_CONTRACT_WRAPPER;
934 hr = g_pCLRRuntime->GetRuntimeDirectory(pBuffer, &cchBuffer);
935 *pdwLength = cchBuffer;
939 // not invoked via shim (most probably loaded by Fusion)
940 WCHAR wszPath[_MAX_PATH];
941 DWORD dwLength = WszGetModuleFileName(g_hThisInst, wszPath,NumItems(wszPath));
944 if (dwLength == 0 || (dwLength == NumItems(wszPath) && GetLastError() == ERROR_INSUFFICIENT_BUFFER))
949 LPWSTR pwzSeparator = wcsrchr(wszPath, W('\\'));
950 if (pwzSeparator == NULL)
954 pwzSeparator[1] = W('\0'); // after '\'
956 LPWSTR pwzDirectoryName = wszPath;
958 size_t cchLength = wcslen(pwzDirectoryName) + 1;
960 if (cchBuffer < cchLength)
962 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
968 // all look good, copy the string over
976 // hand out the length regardless of success/failure
977 *pdwLength = (DWORD)cchLength;
981 #endif // FEATURE_CORECLR || CROSSGEN_COMPILE
985 // Returns version of the runtime (null-terminated).
988 // pBuffer - [out] Output buffer allocated by caller of size cchBuffer.
989 // cchBuffer - Size of pBuffer in characters.
990 // pdwLength - [out] Size of the version string in characters (incl. null-terminator). Will be filled
991 // even if ERROR_INSUFFICIENT_BUFFER is returned.
994 // S_OK - Output buffer contains the version string.
995 // HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) - *pdwLength contains required size of the buffer in
999 STDAPI GetCORVersionInternal(
1000 __out_ecount_z_opt(cchBuffer) LPWSTR pBuffer,
1002 __out DWORD *pdwLength)
1004 #if defined(FEATURE_CORECLR) || defined(CROSSGEN_COMPILE)
1010 PRECONDITION(CheckPointer(pBuffer, NULL_OK));
1011 PRECONDITION(CheckPointer(pdwLength));
1015 BEGIN_ENTRYPOINT_NOTHROW;
1017 if ((pBuffer != NULL) && (cchBuffer > 0))
1018 { // Initialize the output for case the function fails
1022 #define VERSION_NUMBER_NOSHIM W("v") QUOTE_MACRO_L(VER_MAJORVERSION.VER_MINORVERSION.VER_PRODUCTBUILD)
1024 DWORD length = (DWORD)(wcslen(VERSION_NUMBER_NOSHIM) + 1);
1025 if (length > cchBuffer)
1027 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
1031 if (pBuffer == NULL)
1037 CopyMemory(pBuffer, VERSION_NUMBER_NOSHIM, length * sizeof(WCHAR));
1041 *pdwLength = length;
1043 END_ENTRYPOINT_NOTHROW;
1046 #else // FEATURE_CORECLR || CROSSGEN_COMPILE
1048 // Simply forward the call to the ICLRRuntimeInfo implementation.
1049 STATIC_CONTRACT_WRAPPER;
1053 hr = g_pCLRRuntime->GetVersionString(pBuffer, &cchBuffer);
1054 *pdwLength = cchBuffer;
1058 // not invoked via shim (most probably loaded by Fusion)
1059 WCHAR wszPath[_MAX_PATH];
1060 DWORD dwLength = WszGetModuleFileName(g_hThisInst, wszPath,NumItems(wszPath));
1063 if (dwLength == 0 || (dwLength == NumItems(wszPath) && GetLastError() == ERROR_INSUFFICIENT_BUFFER))
1065 return E_UNEXPECTED;
1068 LPWSTR pwzSeparator = wcsrchr(wszPath, W('\\'));
1069 if (pwzSeparator == NULL)
1071 return E_UNEXPECTED;
1073 *pwzSeparator = W('\0');
1075 LPWSTR pwzDirectoryName = wcsrchr(wszPath, W('\\'));
1076 if (pwzDirectoryName == NULL)
1078 return E_UNEXPECTED;
1080 pwzDirectoryName++; // skip '\'
1082 size_t cchLength = wcslen(pwzDirectoryName) + 1;
1084 if (cchBuffer < cchLength)
1086 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
1090 if (pBuffer != NULL)
1092 // all look good, copy the string over
1100 // hand out the length regardless of success/failure
1101 *pdwLength = (DWORD)cchLength;
1106 #endif // FEATURE_CORECLR || CROSSGEN_COMPILE
1111 #ifndef CROSSGEN_COMPILE
1112 STDAPI LoadLibraryShimInternal(LPCWSTR szDllName, LPCWSTR szVersion, LPVOID pvReserved, HMODULE *phModDll)
1114 #ifdef FEATURE_CORECLR
1119 PRECONDITION(CheckPointer(szDllName, NULL_OK));
1120 PRECONDITION(CheckPointer(szVersion, NULL_OK));
1121 PRECONDITION(CheckPointer(pvReserved, NULL_OK));
1122 PRECONDITION(CheckPointer(phModDll));
1125 if (szDllName == NULL)
1130 BEGIN_ENTRYPOINT_NOTHROW;
1132 WCHAR szDllPath[_MAX_PATH+1];
1134 if (!PAL_GetPALDirectoryW(szDllPath, _MAX_PATH)) {
1135 IfFailGo(HRESULT_FROM_GetLastError());
1137 wcsncat(szDllPath, szDllName, _MAX_PATH - wcslen(szDllPath));
1139 if ((*phModDll = WszLoadLibrary(szDllPath)) == NULL)
1140 IfFailGo(HRESULT_FROM_GetLastError());
1143 END_ENTRYPOINT_NOTHROW;
1146 #else // FEATURE_CORECLR
1148 // Simply forward the call to the ICLRRuntimeInfo implementation.
1149 STATIC_CONTRACT_WRAPPER;
1152 return g_pCLRRuntime->LoadLibrary(szDllName, phModDll);
1156 // no runtime info, probably loaded directly (e.g. from Fusion)
1157 // just look next to ourselves.
1158 WCHAR wszPath[MAX_PATH];
1159 DWORD dwLength = WszGetModuleFileName(g_hThisInst, wszPath,NumItems(wszPath));
1162 if (dwLength == 0 || (dwLength == NumItems(wszPath) && GetLastError() == ERROR_INSUFFICIENT_BUFFER))
1164 return E_UNEXPECTED;
1167 LPWSTR pwzSeparator = wcsrchr(wszPath, W('\\'));
1168 if (pwzSeparator == NULL)
1170 return E_UNEXPECTED;
1172 pwzSeparator[1]=W('\0');
1174 wcscat_s(wszPath,NumItems(wszPath),szDllName);
1175 *phModDll= WszLoadLibraryEx(wszPath,NULL,GetLoadWithAlteredSearchPathFlag());
1177 if (*phModDll == NULL)
1179 return HRESULT_FROM_GetLastError();
1184 #endif // FEATURE_CORECLR
1188 #endif // CROSSGEN_COMPILE
1190 static DWORD g_dwSystemDirectory = 0;
1191 static WCHAR g_pSystemDirectory[_MAX_PATH + 1];
1193 HRESULT GetInternalSystemDirectory(__out_ecount_part_opt(*pdwLength,*pdwLength) LPWSTR buffer, __inout DWORD* pdwLength)
1198 PRECONDITION(CheckPointer(buffer, NULL_OK));
1199 PRECONDITION(CheckPointer(pdwLength));
1202 if (g_dwSystemDirectory == 0)
1203 SetInternalSystemDirectory();
1206 // g_dwSystemDirectory includes the NULL in its count!
1208 if(*pdwLength < g_dwSystemDirectory)
1210 *pdwLength = g_dwSystemDirectory;
1211 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
1217 // wcsncpy_s will automatically append a null and g_dwSystemDirectory
1218 // includes the null in its count, so we have to subtract 1.
1220 wcsncpy_s(buffer, *pdwLength, g_pSystemDirectory, g_dwSystemDirectory-1);
1222 *pdwLength = g_dwSystemDirectory;
1227 LPCWSTR GetInternalSystemDirectory(__out DWORD* pdwLength)
1229 LIMITED_METHOD_CONTRACT;
1231 if (g_dwSystemDirectory == 0)
1233 SetInternalSystemDirectory();
1236 if (pdwLength != NULL)
1238 * pdwLength = g_dwSystemDirectory;
1241 return g_pSystemDirectory;
1245 HRESULT SetInternalSystemDirectory()
1254 if(g_dwSystemDirectory == 0) {
1257 // use local buffer for thread safety
1258 WCHAR wzSystemDirectory[COUNTOF(g_pSystemDirectory)];
1260 hr = GetCORSystemDirectoryInternal(wzSystemDirectory, COUNTOF(wzSystemDirectory), &len);
1263 wzSystemDirectory[0] = W('\0');
1267 // publish results idempotently with correct memory ordering
1268 memcpy(g_pSystemDirectory, wzSystemDirectory, len * sizeof(WCHAR));
1269 (void)InterlockedExchange((LONG *)&g_dwSystemDirectory, len);
1275 #if defined(CROSSGEN_COMPILE) && defined(FEATURE_CORECLR)
1276 void SetMscorlibPath(LPCWCHAR wzSystemDirectory)
1278 wcscpy_s(g_pSystemDirectory, COUNTOF(g_pSystemDirectory), wzSystemDirectory);
1280 DWORD len = (DWORD)wcslen(g_pSystemDirectory);
1282 if(g_pSystemDirectory[len-1] != '\\')
1284 g_pSystemDirectory[len] = W('\\');
1285 g_pSystemDirectory[len+1] = W('\0');
1286 g_dwSystemDirectory = len + 1;
1289 g_dwSystemDirectory = len;