Add a fourth parameter to the DEFINE_DACVAR macro that is the actual fully qualified...
[platform/upstream/coreclr.git] / src / dlls / mscoree / mscoree.cpp
1 //
2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
4 //
5 //*****************************************************************************
6 // MSCoree.cpp
7 //*****************************************************************************
8 #include "stdafx.h"                     // Standard header.
9
10 #include <utilcode.h>                   // Utility helpers.
11 #include <posterror.h>                  // Error handlers
12 #define INIT_GUIDS  
13 #include <corpriv.h>
14 #include <winwrap.h>
15 #include <mscoree.h>
16 #include "shimload.h"
17 #include "metadataexports.h"
18
19 #if !defined(FEATURE_CORECLR)
20 #include "corsym.h"
21 #endif 
22
23 #if defined(FEATURE_CORECLR)
24 #include "product_version.h"
25 #endif // FEATURE_CORECLR
26
27 #ifdef FEATURE_COMINTEROP
28 #include "ComCallUnmarshal.h"
29 #endif // FEATURE_COMINTEROP
30
31 #if !defined(FEATURE_CORECLR) && !defined(CROSSGEN_COMPILE)
32 #include <metahost.h>
33 extern ICLRRuntimeInfo *g_pCLRRuntime;
34 #endif // !FEATURE_CORECLR && !CROSSGEN_COMPILE
35
36 #ifdef FEATURE_HOSTED_BINDER
37 #include "clrprivhosting.h"
38 #endif
39
40 #ifndef FEATURE_CORECLR
41 #include "clr/win32.h"
42 #endif // FEATURE_CORECLR
43
44 #ifdef FEATURE_PROFAPI_ATTACH_DETACH
45 #include "../../vm/profattach.h"
46 #endif // FEATURE_PROFAPI_ATTACH_DETACH
47
48
49 #if defined(FEATURE_CORECLR)
50 #include <dbgenginemetrics.h>
51 #endif // FEATURE_CORECLR
52
53 // Locals.
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.
58
59 #ifdef FEATURE_COMINTEROP_MANAGED_ACTIVATION
60 // try to load a com+ class and give out an IClassFactory
61 HRESULT STDMETHODCALLTYPE EEDllGetClassObject(
62                             REFCLSID rclsid,
63                             REFIID riid,
64                             LPVOID FAR *ppv);
65 #endif // FEATURE_COMINTEROP_MANAGED_ACTIVATION
66
67 // Globals.
68 HINSTANCE g_hThisInst;  // This library.
69
70 #ifndef CROSSGEN_COMPILE
71 //*****************************************************************************
72 // Handle lifetime of loaded library.
73 //*****************************************************************************
74
75 #ifdef FEATURE_MERGE_JIT_AND_ENGINE
76 void            jitOnDllProcessAttach();
77 void            jitOnDllProcessDetach();
78 #endif // FEATURE_MERGE_JIT_AND_ENGINE
79
80
81 #ifdef FEATURE_CORECLR
82
83 #include <shlwapi.h>
84
85 #include <process.h> // for __security_init_cookie()
86
87 void* __stdcall GetCLRFunction(LPCSTR FunctionName);
88
89 extern "C" IExecutionEngine* __stdcall IEE();
90
91 #ifdef NO_CRT_INIT
92 #define _CRT_INIT(hInstance, dwReason, lpReserved) (TRUE)
93 #else
94 extern "C" BOOL WINAPI _CRT_INIT(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved);
95 #endif
96
97 extern "C" BOOL WINAPI DllMain(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved);
98
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)
104 {
105     STATIC_CONTRACT_NOTHROW;
106
107     BOOL result;
108     switch (dwReason)
109     {
110         case DLL_PROCESS_ATTACH:
111 #ifndef FEATURE_PAL        
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        
117
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.
121
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);
128
129             if (!(result = _CRT_INIT(hInstance, dwReason, lpReserved)))
130             {
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
133                 break;
134             }
135             result = DllMain(hInstance, dwReason, lpReserved);
136             break;
137         
138         case DLL_THREAD_ATTACH:
139             _CRT_INIT(hInstance, dwReason, lpReserved);
140             result = DllMain(hInstance, dwReason, lpReserved);
141             break;
142
143         case DLL_PROCESS_DETACH: // intentional fallthru
144         case DLL_THREAD_DETACH:
145             result = DllMain(hInstance, dwReason, lpReserved);
146             _CRT_INIT(hInstance, dwReason, lpReserved);
147             break;
148
149         default:
150             result = FALSE;  // it'd be an OS bug if we got here - not much we can do.
151             break;   
152     }
153     return result;
154 }
155 #endif //FEATURE_CORECLR
156
157 extern "C"
158 BOOL WINAPI DllMain(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved)
159 {
160     STATIC_CONTRACT_NOTHROW;
161
162     switch (dwReason)
163     {
164     case DLL_PROCESS_ATTACH:
165         {
166             // Save the module handle.
167             g_hThisInst = (HINSTANCE)hInstance;
168
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)))
174             {
175                 return FALSE;
176             }
177 #endif // FEATURE_CORECLR
178
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();
183 #ifdef FEATURE_PAL
184             DacGlobals::Initialize();
185 #endif
186             if (!EEDllMain((HINSTANCE)hInstance, dwReason, lpReserved))
187             {
188                 return FALSE;
189             }
190
191 #ifdef FEATURE_MERGE_JIT_AND_ENGINE
192             jitOnDllProcessAttach();
193 #endif // FEATURE_MERGE_JIT_AND_ENGINE
194         }
195         break;
196
197     case DLL_PROCESS_DETACH:
198         {
199 #ifdef FEATURE_PAL
200             PAL_CleanupDacTableAddress();
201 #endif
202             EEDllMain((HINSTANCE)hInstance, dwReason, lpReserved);
203
204 #ifdef FEATURE_MERGE_JIT_AND_ENGINE
205             jitOnDllProcessDetach();
206 #endif // FEATURE_MERGE_JIT_AND_ENGINE
207
208         }
209         break;
210
211     case DLL_THREAD_DETACH:
212         {
213             EEDllMain((HINSTANCE)hInstance, dwReason, lpReserved);
214         }
215         break;
216     }
217
218     return TRUE;
219 }
220
221 #ifndef FEATURE_CORECLR // coreclr does not export this 
222 // ---------------------------------------------------------------------------
223 // %%Function: DllGetClassObjectInternal  %%Owner: NatBro   %%Reviewed: 00/00/00
224 // 
225 // Parameters:
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
230 //                            with
231 //  ppv                     - location to return reference to the interface
232 //                            specified by iid
233 // 
234 // Returns:
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
240 // 
241 // Description:
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 // ---------------------------------------------------------------------------
248
249 #ifdef FEATURE_COMINTEROP
250 // This could be merged with Metadata's class factories!
251 static CComCallUnmarshalFactory g_COMCallUnmarshal;
252 #endif // FEATURE_COMINTEROP
253
254 STDAPI InternalDllGetClassObject(
255     REFCLSID rclsid,
256     REFIID riid,
257     LPVOID FAR *ppv)
258 {
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;
262
263     HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
264     BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW);
265
266
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)
272 #endif
273        )
274     {
275         hr = MetaDataDllGetClassObject(rclsid, riid, ppv);
276     }
277 #ifdef FEATURE_PROFAPI_ATTACH_DETACH
278     else if (rclsid == CLSID_CLRProfiling)
279     {
280         hr = ICLRProfilingGetClassObject(rclsid, riid, ppv);
281     }
282 #endif // FEATURE_PROFAPI_ATTACH_DETACH
283 #ifdef FEATURE_COMINTEROP
284     else if (rclsid == CLSID_ComCallUnmarshal || rclsid == CLSID_ComCallUnmarshalV4)
285     {
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);
289     }
290     else if (rclsid == CLSID_CorSymBinder_SxS)
291     {
292         EX_TRY
293         {
294         // PDB format - use diasymreader.dll with COM activation
295         InlineSString<_MAX_PATH> ssBuf;
296         hr = FakeCoCallDllGetClassObject(rclsid,
297             GetHModuleDirectory(GetModuleInst(), ssBuf).GetUnicode(),
298             riid,
299             ppv,
300             NULL);
301         }
302         EX_CATCH_HRESULT(hr);
303     }
304     else
305     {
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
310     }
311 #endif // FEATURE_COMINTEROP
312
313     END_SO_INTOLERANT_CODE;
314     return hr;
315 }  // InternalDllGetClassObject
316
317
318 STDAPI DllGetClassObjectInternal(
319                                  REFCLSID rclsid,
320                                  REFIID riid,
321                                  LPVOID FAR *ppv)
322 {
323     STATIC_CONTRACT_NOTHROW;
324     STATIC_CONTRACT_ENTRY_POINT;
325
326     HRESULT hr = S_OK;
327     BEGIN_ENTRYPOINT_NOTHROW;
328     
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;
336
337     return hr;
338 }
339 #endif // FEATURE_CORECLR
340
341 #ifdef FEATURE_COMINTEROP
342 // ---------------------------------------------------------------------------
343 // %%Function: DllCanUnloadNowInternal  
344 // 
345 // Returns:
346 //  S_FALSE                 - Indicating that COR, once loaded, may not be
347 //                            unloaded.
348 // ---------------------------------------------------------------------------
349 STDAPI DllCanUnloadNowInternal(void)
350 {
351     STATIC_CONTRACT_NOTHROW;
352     STATIC_CONTRACT_ENTRY_POINT;    
353
354     //we should never unload unless the process is dying
355     return S_FALSE;
356 }  // DllCanUnloadNowInternal
357
358 // ---------------------------------------------------------------------------
359 // %%Function: DllRegisterServerInternal 
360 // 
361 // Description:
362 //  Registers
363 // ---------------------------------------------------------------------------
364 STDAPI DllRegisterServerInternal(HINSTANCE hMod, LPCWSTR version)
365 {
366
367     CONTRACTL{
368         NOTHROW;
369         GC_NOTRIGGER;
370         ENTRY_POINT;
371         PRECONDITION(CheckPointer(version));
372     } CONTRACTL_END;
373
374     return S_OK;
375 }  // DllRegisterServerInternal
376
377 // ---------------------------------------------------------------------------
378 // %%Function: DllUnregisterServerInternal      
379 // ---------------------------------------------------------------------------
380 STDAPI DllUnregisterServerInternal(void)
381 {
382
383     CONTRACTL
384     {
385         GC_NOTRIGGER;
386         NOTHROW;
387         ENTRY_POINT;
388     }
389     CONTRACTL_END;
390
391     return S_OK;
392     
393 }  // DllUnregisterServerInternal
394 #endif // FEATURE_COMINTEROP
395
396 #endif // CROSSGEN_COMPILE
397
398 HINSTANCE GetModuleInst()
399 {
400     LIMITED_METHOD_CONTRACT;
401     return (g_hThisInst);
402 }
403
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.
412 {
413
414     CONTRACTL {
415         NOTHROW;
416         GC_NOTRIGGER;
417         ENTRY_POINT;
418         PRECONDITION(CheckPointer(ppv));
419     } CONTRACTL_END;
420     
421     NonVMComHolder<IClassFactory> pcf(NULL);
422     HRESULT hr;
423     BEGIN_ENTRYPOINT_NOTHROW;
424
425     IfFailGo(MetaDataDllGetClassObject(rclsid, IID_IClassFactory, (void **) &pcf));
426     hr = pcf->CreateInstance(NULL, riid, ppv);
427
428 ErrExit:
429     END_ENTRYPOINT_NOTHROW;
430
431     return (hr);
432 }
433
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
444 {
445     CONTRACTL{
446         NOTHROW;
447         GC_NOTRIGGER;
448         ENTRY_POINT;
449         PRECONDITION(CheckPointer(pData));
450         PRECONDITION(CheckPointer(ppv));
451     } CONTRACTL_END;
452
453     HRESULT hr = S_OK;
454     BEGIN_ENTRYPOINT_NOTHROW;
455
456     hr = GetMDInternalInterface(pData, cbData, flags, riid, ppv);
457
458     END_ENTRYPOINT_NOTHROW;
459     return hr;
460 }
461
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
471 {
472     CONTRACTL{
473         NOTHROW;
474         GC_NOTRIGGER;
475         ENTRY_POINT;
476         PRECONDITION(CheckPointer(pv));
477         PRECONDITION(CheckPointer(ppv));
478     } CONTRACTL_END;
479     
480     HRESULT hr = S_OK;
481     BEGIN_ENTRYPOINT_NOTHROW;
482
483     hr = GetMDInternalInterfaceFromPublic(pv, riid, ppv);
484
485     END_ENTRYPOINT_NOTHROW;
486     return hr;
487 }
488
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
498 {
499     CONTRACTL{
500         NOTHROW;
501         GC_NOTRIGGER;
502         PRECONDITION(CheckPointer(pv));
503         PRECONDITION(CheckPointer(ppv));
504         ENTRY_POINT;
505     } CONTRACTL_END;
506     
507     HRESULT hr = S_OK;
508     BEGIN_ENTRYPOINT_NOTHROW;
509
510     hr = GetMDPublicInterfaceFromInternal(pv, riid, ppv);
511
512     END_ENTRYPOINT_NOTHROW;
513     return hr;
514 }
515
516
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.
526 {
527     CONTRACTL{
528         NOTHROW;
529         GC_NOTRIGGER;
530         ENTRY_POINT;
531         PRECONDITION(CheckPointer(pUnk));
532         PRECONDITION(CheckPointer(pData));
533     } CONTRACTL_END;
534
535     HRESULT hr = S_OK;    
536
537     BEGIN_ENTRYPOINT_NOTHROW;
538     hr = MDReOpenMetaDataWithMemory(pUnk, pData, cbData);
539     END_ENTRYPOINT_NOTHROW;
540     return hr;
541 }
542
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              
553 {
554     CONTRACTL{
555         NOTHROW;
556         GC_NOTRIGGER;
557         ENTRY_POINT;
558         PRECONDITION(CheckPointer(pUnk));
559         PRECONDITION(CheckPointer(pData));
560     } CONTRACTL_END;
561
562     HRESULT hr = S_OK;    
563
564     BEGIN_ENTRYPOINT_NOTHROW;
565     hr = MDReOpenMetaDataWithMemoryEx(pUnk, pData, cbData, dwReOpenFlags);
566     END_ENTRYPOINT_NOTHROW;
567     return hr;
568 }
569
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.
579 {
580     CONTRACTL
581     {
582         NOTHROW;
583         ENTRY_POINT;
584     }
585     CONTRACTL_END;
586     HRESULT hr=S_OK;
587     BEGIN_ENTRYPOINT_NOTHROW;
588
589     hr=GetAssemblyMDInternalImport(szFileName, riid, ppIUnk);
590     END_ENTRYPOINT_NOTHROW;
591     return hr;
592 }
593 #endif
594
595 #ifndef CROSSGEN_COMPILE
596 // ---------------------------------------------------------------------------
597 // %%Function: CoInitializeCor
598 // 
599 // Parameters:
600 //  fFlags                  - Initialization flags for the engine.  See the
601 //                              COINITICOR enumerator for valid values.
602 // 
603 // Returns:
604 //  S_OK                    - On success
605 // 
606 // Description:
607 //  Reserved to initialize the Cor runtime engine explicitly.  This currently
608 //  does nothing.
609 // ---------------------------------------------------------------------------
610 STDAPI CoInitializeCor(DWORD fFlags)
611 {
612     WRAPPER_NO_CONTRACT;
613
614     BEGIN_ENTRYPOINT_NOTHROW;
615
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;
619
620     return (S_OK);
621 }
622
623 // ---------------------------------------------------------------------------
624 // %%Function: CoUninitializeCor
625 // 
626 // Parameters:
627 //  none
628 // 
629 // Returns:
630 //  Nothing
631 // 
632 // Description:
633 //  Function to indicate the client is done with the CLR. This currently does
634 //  nothing.
635 // ---------------------------------------------------------------------------
636 STDAPI_(void)   CoUninitializeCor(void)
637 {
638     WRAPPER_NO_CONTRACT;
639
640     BEGIN_ENTRYPOINT_VOIDRET;
641
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;
645
646 }
647
648 // Undef LoadStringRC & LoadStringRCEx so we can export these functions.
649 #undef LoadStringRC
650 #undef LoadStringRCEx
651
652 // ---------------------------------------------------------------------------
653 // %%Function: LoadStringRC
654 // 
655 // Parameters:
656 //  none
657 // 
658 // Returns:
659 //  Nothing
660 // 
661 // Description:
662 //  Function to load a resource based on it's ID.
663 // ---------------------------------------------------------------------------
664 STDAPI LoadStringRC(
665     UINT iResourceID, 
666     __out_ecount(iMax) __out_z LPWSTR szBuffer, 
667     int iMax, 
668     int bQuiet
669 )
670 {
671     WRAPPER_NO_CONTRACT;
672
673     HRESULT hr = S_OK;
674
675     if (NULL == szBuffer)
676         return E_INVALIDARG;
677     if (0 == iMax)
678         return E_INVALIDARG;
679     
680     BEGIN_ENTRYPOINT_NOTHROW;
681     hr = UtilLoadStringRC(iResourceID, szBuffer, iMax, bQuiet);
682     END_ENTRYPOINT_NOTHROW;
683     return hr;
684 }
685
686 // ---------------------------------------------------------------------------
687 // %%Function: LoadStringRCEx
688 // 
689 // Parameters:
690 //  none
691 // 
692 // Returns:
693 //  Nothing
694 // 
695 // Description:
696 //  Ex version of the function to load a resource based on it's ID.
697 // ---------------------------------------------------------------------------
698 #ifdef FEATURE_USE_LCID
699 STDAPI LoadStringRCEx(
700     LCID lcid,
701     UINT iResourceID, 
702     __out_ecount(iMax) __out_z LPWSTR szBuffer, 
703     int iMax, 
704     int bQuiet,
705     int *pcwchUsed
706 )
707 {
708     WRAPPER_NO_CONTRACT;
709     HRESULT hr = S_OK;
710
711     if (NULL == szBuffer)
712         return E_INVALIDARG;
713     if (0 == iMax)
714         return E_INVALIDARG;
715     
716     BEGIN_ENTRYPOINT_NOTHROW;   
717     hr = UtilLoadStringRCEx(lcid, iResourceID, szBuffer, iMax, bQuiet, pcwchUsed);
718     END_ENTRYPOINT_NOTHROW;
719     return hr;
720 }
721 #endif
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.")
725
726 #endif // CROSSGEN_COMPILE
727
728
729 #if defined(FEATURE_CORECLR) || defined(CROSSGEN_COMPILE)
730
731 //
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.
735 // 
736 // Arguments:
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.
743 // 
744 // Return Value:
745 //    S_OK - Output buffer contains path name.
746 //    HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) - *pdwLength contains required size of the buffer in 
747 //                                                    characters.
748 //    other errors - If input parameters are incorrect (NULL).
749 //
750 static
751 HRESULT CopySystemDirectory(__in WCHAR *pFileName,
752                             __out_ecount_z_opt(cchBuffer) LPWSTR pBuffer, 
753                             DWORD  cchBuffer,
754                             __out DWORD *pdwLength)
755 {
756     if ((pBuffer != NULL) && (cchBuffer > 0))
757     {   // Initialize the output for case the function fails
758         *pBuffer = W('\0');
759     }
760     
761     if (pdwLength == NULL)
762         return E_POINTER;
763     
764     HRESULT hr = S_OK;
765     if (pFileName == NULL)
766         return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
767     
768     SIZE_T dwFileNameLength = wcslen(pFileName);
769     LPWSTR pSeparator = wcsrchr(pFileName, W('\\'));
770     if (pSeparator != NULL)
771     {
772         dwFileNameLength = (DWORD)(pSeparator - pFileName + 1);
773         pFileName[dwFileNameLength] = W('\0');
774     }
775     
776     dwFileNameLength++; // Add back in the null
777     *pdwLength = (DWORD)dwFileNameLength;
778     if ((dwFileNameLength > cchBuffer) || (pBuffer == NULL))
779     {
780         hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
781     }
782     else
783     {
784         CopyMemory(pBuffer, 
785                    pFileName,
786                    dwFileNameLength * sizeof(WCHAR));
787     }
788     return hr;
789 }
790
791 extern HINSTANCE            g_pMSCorEE;
792
793 #ifndef FEATURE_PAL
794
795 BOOL PAL_GetPALDirectory(__out_ecount(cchBuffer) LPWSTR pbuffer, 
796                          DWORD  cchBuffer)
797 {
798
799     HRESULT hr = S_OK;
800
801     WCHAR pPath[MAX_PATH];
802     DWORD dwPath = MAX_PATH;
803
804 #ifndef CROSSGEN_COMPILE
805     _ASSERTE(g_pMSCorEE != NULL);
806 #endif
807
808     dwPath = WszGetModuleFileName(g_pMSCorEE, pPath, dwPath);
809     if(dwPath == 0)
810     {
811         hr = HRESULT_FROM_GetLastErrorNA();
812     }
813     else 
814     {
815         DWORD dwLength;
816         hr = CopySystemDirectory(pPath, pbuffer, cchBuffer, &dwLength);
817     }
818
819     return (hr == S_OK);
820 }
821
822 BOOL PAL_GetPALDirectoryW(__out_ecount(cchBuffer) LPWSTR pbuffer, 
823                          DWORD  cchBuffer)
824 {
825     return PAL_GetPALDirectory(pbuffer, cchBuffer);
826 }
827
828 #endif // FEATURE_PAL
829
830 #endif // FEATURE_CORECLR || CROSSGEN_COMPILE
831
832
833 // Note that there are currently two callers of this function: code:CCompRC.LoadLibrary
834 // and code:CorLaunchApplication.
835 STDAPI GetRequestedRuntimeInfoInternal(LPCWSTR pExe, 
836                                LPCWSTR pwszVersion,
837                                LPCWSTR pConfigurationFile, 
838                                DWORD startupFlags,
839                                DWORD runtimeInfoFlags, 
840                                __out_ecount_opt(dwDirectory) LPWSTR pDirectory, 
841                                DWORD dwDirectory, 
842                                __out_opt DWORD *pdwDirectoryLength, 
843                                __out_ecount_opt(cchBuffer) LPWSTR pVersion, 
844                                DWORD cchBuffer, 
845                                __out_opt DWORD* pdwLength)
846 {
847     CONTRACTL
848     {
849         NOTHROW;
850         GC_NOTRIGGER;
851         ENTRY_POINT;
852         PRECONDITION(pDirectory != NULL && pVersion != NULL && cchBuffer > 0);
853     } CONTRACTL_END;
854
855     // for simplicity we will cheat and return the entire system directory in pDirectory
856     pVersion[0] = 0;
857     if (pdwLength != NULL)
858         *pdwLength = 0;
859
860     if (pdwDirectoryLength == NULL)
861         pdwDirectoryLength = &dwDirectory;
862
863     return GetCORSystemDirectoryInternal(pDirectory, dwDirectory, pdwDirectoryLength);
864 }
865
866 // Replacement for legacy shim API GetCORRequiredVersion(...) used in linked libraries.
867 // Used in code:TiggerStorage::GetDefaultVersion#CallTo_CLRRuntimeHostInternal_GetImageVersionString.
868 HRESULT 
869 CLRRuntimeHostInternal_GetImageVersionString(
870     __out_ecount_opt(*pcchBuffer) LPWSTR wszBuffer, 
871     __inout                       DWORD *pcchBuffer)
872 {
873     // Simply forward the call to the ICLRRuntimeHostInternal implementation.
874     STATIC_CONTRACT_WRAPPER;
875
876 #if defined(FEATURE_CORECLR) || defined(CROSSGEN_COMPILE)
877     HRESULT hr = GetCORVersionInternal(wszBuffer, *pcchBuffer, pcchBuffer);
878 #else
879     ReleaseHolder<ICLRRuntimeHostInternal> pRuntimeHostInternal;
880     HRESULT hr = g_pCLRRuntime->GetInterface(CLSID_CLRRuntimeHostInternal,
881                                              IID_ICLRRuntimeHostInternal,
882                                              &pRuntimeHostInternal);
883     if (SUCCEEDED(hr))
884     {
885         hr = pRuntimeHostInternal->GetImageVersionString(wszBuffer, pcchBuffer);
886     }
887 #endif
888     
889     return hr;
890 } // CLRRuntimeHostInternal_GetImageVersionString
891
892
893 STDAPI GetCORSystemDirectoryInternal(__out_ecount_part_opt(cchBuffer, *pdwLength) LPWSTR pBuffer, 
894                              DWORD  cchBuffer,
895                              __out_opt DWORD* pdwLength)
896 {
897 #if defined(FEATURE_CORECLR) || defined(CROSSGEN_COMPILE)
898
899     CONTRACTL {
900         NOTHROW;
901         GC_NOTRIGGER;
902         ENTRY_POINT;
903         PRECONDITION(CheckPointer(pBuffer, NULL_OK));
904         PRECONDITION(CheckPointer(pdwLength, NULL_OK));
905     } CONTRACTL_END;
906
907     HRESULT hr = S_OK;
908     BEGIN_ENTRYPOINT_NOTHROW;
909     
910     if(pdwLength == NULL)
911         IfFailGo(E_POINTER);
912
913     if (pBuffer == NULL)
914         IfFailGo(E_POINTER);
915
916     if (!PAL_GetPALDirectory(pBuffer, cchBuffer)) {
917         IfFailGo(HRESULT_FROM_GetLastError());
918     }
919
920     // Include the null terminator in the length
921     *pdwLength = (DWORD)wcslen(pBuffer)+1;
922
923 ErrExit:
924     END_ENTRYPOINT_NOTHROW;
925     return hr;
926
927 #else // FEATURE_CORECLR || CROSSGEN_COMPILE
928
929     // Simply forward the call to the ICLRRuntimeInfo implementation.
930     STATIC_CONTRACT_WRAPPER;
931     HRESULT hr = S_OK;
932     if (g_pCLRRuntime)
933     {
934         hr = g_pCLRRuntime->GetRuntimeDirectory(pBuffer, &cchBuffer);
935         *pdwLength = cchBuffer;
936     }
937     else
938     {
939         // not invoked via shim (most probably loaded by Fusion)
940         WCHAR wszPath[_MAX_PATH];
941         DWORD dwLength = WszGetModuleFileName(g_hThisInst, wszPath,NumItems(wszPath));
942             
943
944         if (dwLength == 0 || (dwLength == NumItems(wszPath) && GetLastError() == ERROR_INSUFFICIENT_BUFFER))
945         {
946             return E_UNEXPECTED;
947         }
948
949         LPWSTR pwzSeparator = wcsrchr(wszPath, W('\\'));
950         if (pwzSeparator == NULL)
951         {
952             return E_UNEXPECTED;
953         }
954         pwzSeparator[1] = W('\0'); // after '\'
955
956         LPWSTR pwzDirectoryName = wszPath; 
957
958         size_t cchLength = wcslen(pwzDirectoryName) + 1;
959
960         if (cchBuffer < cchLength)
961         {
962             hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
963         }
964         else
965         {
966             if (pBuffer != NULL)
967             {
968                 // all look good, copy the string over
969                 wcscpy_s(pBuffer,
970                          cchLength,
971                          pwzDirectoryName
972                         );
973             }
974         }
975
976         // hand out the length regardless of success/failure
977         *pdwLength = (DWORD)cchLength;
978     }
979     return hr;
980
981 #endif // FEATURE_CORECLR || CROSSGEN_COMPILE
982 }
983
984 //
985 // Returns version of the runtime (null-terminated).
986 // 
987 // Arguments:
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.
992 // 
993 // Return Value:
994 //    S_OK - Output buffer contains the version string.
995 //    HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) - *pdwLength contains required size of the buffer in 
996 //                                                    characters.
997 //
998
999 STDAPI GetCORVersionInternal(
1000 __out_ecount_z_opt(cchBuffer) LPWSTR pBuffer, 
1001                               DWORD cchBuffer,
1002                         __out DWORD *pdwLength)
1003 {
1004 #if defined(FEATURE_CORECLR) || defined(CROSSGEN_COMPILE)
1005
1006     CONTRACTL {
1007         NOTHROW;
1008         GC_NOTRIGGER;
1009         ENTRY_POINT;
1010         PRECONDITION(CheckPointer(pBuffer, NULL_OK));
1011         PRECONDITION(CheckPointer(pdwLength));
1012     } CONTRACTL_END;
1013         
1014     HRESULT hr;
1015     BEGIN_ENTRYPOINT_NOTHROW;
1016     
1017     if ((pBuffer != NULL) && (cchBuffer > 0))
1018     {   // Initialize the output for case the function fails
1019         *pBuffer = W('\0');
1020     }
1021
1022 #define VERSION_NUMBER_NOSHIM W("v") QUOTE_MACRO_L(VER_MAJORVERSION.VER_MINORVERSION.VER_PRODUCTBUILD)
1023
1024     DWORD length = (DWORD)(wcslen(VERSION_NUMBER_NOSHIM) + 1);
1025     if (length > cchBuffer)
1026     {
1027         hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
1028     }
1029     else
1030     {
1031         if (pBuffer == NULL)
1032         {
1033             hr = E_POINTER;
1034         }
1035         else
1036         {
1037             CopyMemory(pBuffer, VERSION_NUMBER_NOSHIM, length * sizeof(WCHAR));
1038             hr = S_OK;
1039         }
1040     }
1041     *pdwLength = length;
1042
1043     END_ENTRYPOINT_NOTHROW;
1044     return hr;
1045
1046 #else // FEATURE_CORECLR || CROSSGEN_COMPILE
1047
1048     // Simply forward the call to the ICLRRuntimeInfo implementation.
1049     STATIC_CONTRACT_WRAPPER;
1050     HRESULT hr = S_OK;
1051     if (g_pCLRRuntime)
1052     {
1053         hr = g_pCLRRuntime->GetVersionString(pBuffer, &cchBuffer);
1054        *pdwLength = cchBuffer;
1055     }
1056     else
1057     {
1058         // not invoked via shim (most probably loaded by Fusion)
1059         WCHAR wszPath[_MAX_PATH];
1060         DWORD dwLength = WszGetModuleFileName(g_hThisInst, wszPath,NumItems(wszPath));
1061             
1062
1063         if (dwLength == 0 || (dwLength == NumItems(wszPath) && GetLastError() == ERROR_INSUFFICIENT_BUFFER))
1064         {
1065             return E_UNEXPECTED;
1066         }
1067
1068         LPWSTR pwzSeparator = wcsrchr(wszPath, W('\\'));
1069         if (pwzSeparator == NULL)
1070         {
1071             return E_UNEXPECTED;
1072         }
1073         *pwzSeparator = W('\0');
1074
1075         LPWSTR pwzDirectoryName = wcsrchr(wszPath, W('\\')); 
1076         if (pwzDirectoryName == NULL)
1077         {
1078             return E_UNEXPECTED;
1079         }
1080         pwzDirectoryName++; // skip '\'
1081
1082         size_t cchLength = wcslen(pwzDirectoryName) + 1;
1083
1084         if (cchBuffer < cchLength)
1085         {
1086             hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
1087         }
1088         else
1089         {
1090             if (pBuffer != NULL)
1091             {
1092                 // all look good, copy the string over
1093                 wcscpy_s(pBuffer,
1094                          cchLength,
1095                          pwzDirectoryName
1096                         );
1097             }
1098         }
1099
1100         // hand out the length regardless of success/failure
1101         *pdwLength = (DWORD)cchLength;
1102        
1103     }
1104     return hr;
1105
1106 #endif // FEATURE_CORECLR || CROSSGEN_COMPILE
1107
1108 }
1109
1110
1111 #ifndef CROSSGEN_COMPILE
1112 STDAPI LoadLibraryShimInternal(LPCWSTR szDllName, LPCWSTR szVersion, LPVOID pvReserved, HMODULE *phModDll)
1113 {
1114 #ifdef FEATURE_CORECLR
1115
1116     CONTRACTL {
1117         NOTHROW;
1118         GC_NOTRIGGER;
1119         PRECONDITION(CheckPointer(szDllName, NULL_OK));
1120         PRECONDITION(CheckPointer(szVersion, NULL_OK));
1121         PRECONDITION(CheckPointer(pvReserved, NULL_OK));
1122         PRECONDITION(CheckPointer(phModDll));
1123     } CONTRACTL_END;
1124
1125     if (szDllName == NULL)
1126         return E_POINTER;
1127
1128     HRESULT hr = S_OK;
1129     
1130     BEGIN_ENTRYPOINT_NOTHROW;
1131
1132     WCHAR szDllPath[_MAX_PATH+1];
1133
1134     if (!PAL_GetPALDirectoryW(szDllPath, _MAX_PATH)) {
1135         IfFailGo(HRESULT_FROM_GetLastError());
1136     }
1137     wcsncat(szDllPath, szDllName, _MAX_PATH - wcslen(szDllPath));
1138     
1139     if ((*phModDll = WszLoadLibrary(szDllPath)) == NULL)
1140         IfFailGo(HRESULT_FROM_GetLastError());
1141
1142 ErrExit:
1143     END_ENTRYPOINT_NOTHROW;
1144     return hr;
1145
1146 #else // FEATURE_CORECLR
1147
1148     // Simply forward the call to the ICLRRuntimeInfo implementation.
1149     STATIC_CONTRACT_WRAPPER;
1150     if (g_pCLRRuntime)
1151     {
1152         return g_pCLRRuntime->LoadLibrary(szDllName, phModDll);
1153     }
1154     else
1155     {
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));
1160             
1161
1162         if (dwLength == 0 || (dwLength == NumItems(wszPath) && GetLastError() == ERROR_INSUFFICIENT_BUFFER))
1163         {
1164             return E_UNEXPECTED;
1165         }
1166
1167         LPWSTR pwzSeparator = wcsrchr(wszPath, W('\\'));
1168         if (pwzSeparator == NULL)
1169         {
1170             return E_UNEXPECTED;
1171         }
1172         pwzSeparator[1]=W('\0');
1173
1174         wcscat_s(wszPath,NumItems(wszPath),szDllName);
1175         *phModDll= WszLoadLibraryEx(wszPath,NULL,GetLoadWithAlteredSearchPathFlag());
1176
1177         if (*phModDll == NULL)
1178         {
1179             return HRESULT_FROM_GetLastError();
1180         }
1181         return S_OK;
1182     }
1183
1184 #endif // FEATURE_CORECLR
1185
1186 }
1187
1188 #endif // CROSSGEN_COMPILE
1189
1190 static DWORD g_dwSystemDirectory = 0;
1191 static WCHAR g_pSystemDirectory[_MAX_PATH + 1];
1192
1193 HRESULT GetInternalSystemDirectory(__out_ecount_part_opt(*pdwLength,*pdwLength) LPWSTR buffer, __inout DWORD* pdwLength)
1194 {
1195     CONTRACTL {
1196         NOTHROW;
1197         GC_NOTRIGGER;
1198         PRECONDITION(CheckPointer(buffer, NULL_OK));
1199         PRECONDITION(CheckPointer(pdwLength));
1200     } CONTRACTL_END;
1201     
1202     if (g_dwSystemDirectory == 0)
1203         SetInternalSystemDirectory();
1204
1205     //
1206     // g_dwSystemDirectory includes the NULL in its count!
1207     //
1208     if(*pdwLength < g_dwSystemDirectory) 
1209     {
1210         *pdwLength = g_dwSystemDirectory;
1211         return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
1212     }
1213
1214     if (buffer != NULL)
1215     {
1216         //
1217         // wcsncpy_s will automatically append a null and g_dwSystemDirectory 
1218         // includes the null in its count, so we have to subtract 1.
1219         //
1220         wcsncpy_s(buffer, *pdwLength, g_pSystemDirectory, g_dwSystemDirectory-1);
1221     }
1222     *pdwLength = g_dwSystemDirectory;
1223     return S_OK;
1224 }
1225
1226
1227 LPCWSTR GetInternalSystemDirectory(__out DWORD* pdwLength)
1228 {
1229     LIMITED_METHOD_CONTRACT;
1230
1231     if (g_dwSystemDirectory == 0)
1232     {
1233         SetInternalSystemDirectory();
1234     }
1235     
1236     if (pdwLength != NULL)
1237     {
1238         * pdwLength = g_dwSystemDirectory;
1239     }
1240
1241     return g_pSystemDirectory;
1242 }
1243
1244
1245 HRESULT SetInternalSystemDirectory()
1246  {
1247     CONTRACTL {
1248         NOTHROW;
1249         GC_NOTRIGGER;
1250     } CONTRACTL_END;
1251
1252     HRESULT hr = S_OK;
1253
1254     if(g_dwSystemDirectory == 0) {
1255         DWORD len;
1256
1257         // use local buffer for thread safety
1258         WCHAR wzSystemDirectory[COUNTOF(g_pSystemDirectory)];
1259         
1260         hr = GetCORSystemDirectoryInternal(wzSystemDirectory, COUNTOF(wzSystemDirectory), &len);
1261
1262         if(FAILED(hr)) {
1263             wzSystemDirectory[0] = W('\0');
1264             len = 1;
1265         }
1266
1267         // publish results idempotently with correct memory ordering
1268         memcpy(g_pSystemDirectory, wzSystemDirectory, len * sizeof(WCHAR));
1269         (void)InterlockedExchange((LONG *)&g_dwSystemDirectory, len);
1270     }
1271
1272     return hr;
1273 }
1274
1275 #if defined(CROSSGEN_COMPILE) && defined(FEATURE_CORECLR)
1276 void SetMscorlibPath(LPCWCHAR wzSystemDirectory)
1277 {
1278     wcscpy_s(g_pSystemDirectory, COUNTOF(g_pSystemDirectory), wzSystemDirectory);
1279
1280     DWORD len = (DWORD)wcslen(g_pSystemDirectory);
1281
1282     if(g_pSystemDirectory[len-1] != '\\')
1283     {
1284         g_pSystemDirectory[len] = W('\\');
1285         g_pSystemDirectory[len+1] = W('\0');
1286         g_dwSystemDirectory = len + 1;
1287     }
1288     else
1289         g_dwSystemDirectory = len;
1290 }
1291 #endif