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
6#include "common.h"
7#include "commodule.h"
8#include "comdynamic.h"
9#include "reflectclasswriter.h"
10#include "class.h"
11#include "ceesectionstring.h"
12#include <cor.h>
13#include "typeparse.h"
14#include "typekey.h"
15#include "ildbsymlib.h"
16
17
18//===============================================================================================
19// CreateISymWriterforDynamicModule:
20// Helper to create a ISymUnmanagedWriter instance and hook it up to a newly created dynamic
21// module. This object is used to capture debugging information (source line info, etc.)
22// for the dynamic module. This function determines the appropriate symbol format type
23// (ILDB or PDB), and in the case of PDB (Windows desktop only) loads diasymreader.dll.
24//
25// Arguments:
26// mod - The ReflectionModule for the new dynamic module
27// filenameTemp - the filename at which the module may be saved (ignored if no save access)
28//
29// Return value:
30// The address where the new writer instance has been stored
31//===============================================================================================
32static ISymUnmanagedWriter **CreateISymWriterForDynamicModule(ReflectionModule *mod, const WCHAR *wszFilename)
33{
34 STANDARD_VM_CONTRACT;
35
36 _ASSERTE(mod->IsReflection());
37
38 // Determine which symbol format to use. For Silverlight 2.0 RTM we use ILDB mode to address security
39 // and portability issues with diasymreader.
40 //
41 // For desktop builds we'll eventually want to make ILDB is the default, but we need to emit PDB format if
42 // the symbols can be saved to disk to preserve back compat.
43 //
44 ESymbolFormat symFormatToUse = eSymbolFormatILDB;
45
46
47 static ConfigDWORD dbgForcePDBSymbols;
48 if(dbgForcePDBSymbols.val_DontUse_(W("DbgForcePDBSymbols"), 0) == 1)
49 {
50 symFormatToUse = eSymbolFormatPDB;
51 }
52
53 // Create a stream for the symbols to be emitted into. This
54 // lives on the Module for the life of the Module.
55 SafeComHolder<CGrowableStream> pStream(new CGrowableStream());
56
57 mod->SetInMemorySymbolStream(pStream, symFormatToUse);
58
59 // Create an ISymUnmanagedWriter and initialize it with the
60 // stream and the proper file name. This symbol writer will be
61 // replaced with new ones periodically as the symbols get
62 // retrieved by the debugger.
63 SafeComHolder<ISymUnmanagedWriter> pWriter;
64
65 HRESULT hr;
66 if (symFormatToUse == eSymbolFormatILDB)
67 {
68 // Create an ILDB symbol writer from the ildbsymbols library statically linked in
69 hr = IldbSymbolsCreateInstance(CLSID_CorSymWriter_SxS,
70 IID_ISymUnmanagedWriter,
71 (void**)&pWriter);
72 }
73 else
74 {
75 _ASSERTE(symFormatToUse == eSymbolFormatPDB);
76 hr = FakeCoCreateInstanceEx(CLSID_CorSymWriter_SxS,
77 GetInternalSystemDirectory(),
78 IID_ISymUnmanagedWriter,
79 (void**)&pWriter,
80 NULL);
81 }
82
83 if (SUCCEEDED(hr))
84 {
85 {
86 GCX_PREEMP();
87
88 // The other reference is given to the Sym Writer
89 // But, the writer takes it's own reference.
90 hr = pWriter->Initialize(mod->GetEmitter(),
91 wszFilename,
92 (IStream*)pStream,
93 TRUE);
94 }
95 if (SUCCEEDED(hr))
96 {
97 mod->GetReflectionModule()->SetISymUnmanagedWriter(pWriter.Extract());
98
99 // Return the address of where we've got our
100 // ISymUnmanagedWriter stored so we can pass it over
101 // to the managed symbol writer object that most of
102 // reflection emit will use to write symbols.
103 return mod->GetISymUnmanagedWriterAddr();
104 }
105 else
106 {
107 COMPlusThrowHR(hr);
108 }
109 }
110 else
111 {
112 COMPlusThrowHR(hr);
113 }
114}
115
116//===============================================================================================
117// Attaches an unmanaged symwriter to a newly created dynamic module.
118//===============================================================================================
119FCIMPL2(LPVOID, COMModule::nCreateISymWriterForDynamicModule, ReflectModuleBaseObject* reflectionModuleUNSAFE, StringObject* filenameUNSAFE)
120{
121 FCALL_CONTRACT;
122
123 REFLECTMODULEBASEREF refModule = (REFLECTMODULEBASEREF)ObjectToOBJECTREF(reflectionModuleUNSAFE);
124
125 ReflectionModule *mod = (ReflectionModule*)refModule->GetModule();
126 STRINGREF filename = (STRINGREF)filenameUNSAFE;
127
128 LPVOID pInternalSymWriter = NULL;
129
130 HELPER_METHOD_FRAME_BEGIN_RET_2(filename, refModule);
131
132 SString name;
133 if (filename != NULL)
134 {
135 filename->GetSString(name);
136 }
137
138 GCX_PREEMP();
139 pInternalSymWriter = CreateISymWriterForDynamicModule(mod, name.GetUnicode());
140
141 HELPER_METHOD_FRAME_END();
142
143 return pInternalSymWriter;
144
145} // COMModule::nCreateISymWriterForDynamicModule
146FCIMPLEND
147
148//**************************************************
149// LoadInMemoryTypeByName
150// Explicitly loading an in memory type
151// <TODO>@todo: this function is not dealing with nested type correctly yet.
152// We will need to parse the full name by finding "+" for enclosing type, etc.</TODO>
153//**************************************************
154void QCALLTYPE COMModule::LoadInMemoryTypeByName(QCall::ModuleHandle pModule, LPCWSTR wszFullName)
155{
156 QCALL_CONTRACT;
157
158 TypeHandle typeHnd;
159
160 BEGIN_QCALL;
161
162 if (!pModule->IsReflection())
163 COMPlusThrow(kNotSupportedException, W("NotSupported_NonReflectedType"));
164
165 RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter();
166 _ASSERTE(pRCW);
167
168 // it is ok to use public import API because this is a dynamic module anyway. We are also receiving Unicode full name as
169 // parameter.
170 IMetaDataImport * pImport = pRCW->GetRWImporter();
171
172 if (wszFullName == NULL)
173 IfFailThrow( E_FAIL );
174
175 // look up the handle
176 mdTypeDef td;
177 HRESULT hr = pImport->FindTypeDefByName(wszFullName, mdTokenNil, &td);
178 if (FAILED(hr))
179 {
180 if (hr != CLDB_E_RECORD_NOTFOUND)
181 COMPlusThrowHR(hr);
182
183 // Get the UTF8 version of strFullName
184 MAKE_UTF8PTR_FROMWIDE(szFullName, wszFullName);
185 pModule->GetAssembly()->ThrowTypeLoadException(szFullName, IDS_CLASSLOAD_GENERAL);
186 }
187
188 TypeKey typeKey(pModule, td);
189 typeHnd = pModule->GetClassLoader()->LoadTypeHandleForTypeKey(&typeKey, TypeHandle());
190
191 END_QCALL;
192
193 return;
194}
195
196//**************************************************
197// GetTypeRef
198// This function will return the type token given full qual name. If the type
199// is defined locally, we will return the TypeDef token. Or we will return a TypeRef token
200// with proper resolution scope calculated.
201// wszFullName is escaped (TYPE_NAME_RESERVED_CHAR). It should not be byref or contain enclosing type name,
202// assembly name, and generic argument list.
203//**************************************************
204mdTypeRef QCALLTYPE COMModule::GetTypeRef(QCall::ModuleHandle pModule,
205 LPCWSTR wszFullName,
206 QCall::ModuleHandle pRefedModule,
207 LPCWSTR wszRefedModuleFileName,
208 INT32 tkResolutionArg)
209{
210 QCALL_CONTRACT;
211
212 mdTypeRef tr = 0;
213
214 BEGIN_QCALL;
215
216 RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter();
217 _ASSERTE(pRCW);
218
219 IMetaDataEmit * pEmit = pRCW->GetEmitter();
220 IMetaDataImport * pImport = pRCW->GetRWImporter();
221
222 if (wszFullName == NULL) {
223 COMPlusThrow(kArgumentNullException, W("ArgumentNull_String"));
224 }
225
226 InlineSString<128> ssNameUnescaped;
227 LPCWSTR wszTemp = wszFullName;
228
229 WCHAR c;
230 while(0 != (c = *wszTemp++))
231 {
232 if ( c == W('\\') &&
233 IsTypeNameReservedChar(*wszTemp) )
234 {
235 ssNameUnescaped.Append(*wszTemp++);
236 }
237 else
238 {
239 _ASSERTE( ! IsTypeNameReservedChar(c) );
240 ssNameUnescaped.Append(c);
241 }
242 }
243
244 LPCWSTR wszFullNameUnescaped = ssNameUnescaped.GetUnicode();
245
246 Assembly * pThisAssembly = pModule->GetClassLoader()->GetAssembly();
247 Assembly * pRefedAssembly = pRefedModule->GetClassLoader()->GetAssembly();
248
249 if (pModule == pRefedModule)
250 {
251 // referenced type is from the same module so we must be able to find a TypeDef.
252 IfFailThrow(pImport->FindTypeDefByName(
253 wszFullNameUnescaped,
254 RidFromToken(tkResolutionArg) ? tkResolutionArg : mdTypeDefNil,
255 &tr));
256 }
257 else
258 {
259 mdToken tkResolution = mdTokenNil;
260 if (RidFromToken(tkResolutionArg))
261 {
262 // reference to nested type
263 tkResolution = tkResolutionArg;
264 }
265 else
266 {
267 // reference to top level type
268 if ( pThisAssembly != pRefedAssembly )
269 {
270 SafeComHolderPreemp<IMetaDataAssemblyEmit> pAssemblyEmit;
271
272 // Generate AssemblyRef
273 IfFailThrow( pEmit->QueryInterface(IID_IMetaDataAssemblyEmit, (void **) &pAssemblyEmit) );
274 tkResolution = pThisAssembly->AddAssemblyRef(pRefedAssembly, pAssemblyEmit);
275
276 // Add the assembly ref token and the manifest module it is referring to this module's rid map.
277 // This is needed regardless of whether the dynamic assembly has run access. Even in Save-only
278 // or Refleciton-only mode, CreateType() of the referencing type may still need the referenced
279 // type to be resolved and loaded, e.g. if the referencing type is a subclass of the referenced type.
280 //
281 // Don't cache if there is assembly associated with the token already. The assembly ref resolution
282 // can be ambiguous because of reflection emit does not require unique assembly names.
283 // We always let the first association win. Ideally, we would disallow this situation by throwing
284 // exception, but that would be a breaking change.
285 if(pModule->LookupAssemblyRef(tkResolution) == NULL)
286 {
287 pModule->ForceStoreAssemblyRef(tkResolution, pRefedAssembly);
288 }
289 }
290 else
291 {
292 _ASSERTE(pModule != pRefedModule);
293 _ASSERTE(wszRefedModuleFileName != NULL);
294
295 // Generate ModuleRef
296 IfFailThrow(pEmit->DefineModuleRef(wszRefedModuleFileName, &tkResolution));
297 }
298 }
299
300 IfFailThrow( pEmit->DefineTypeRefByName(tkResolution, wszFullNameUnescaped, &tr) );
301 }
302
303 END_QCALL;
304
305 return tr;
306}
307
308
309/*=============================GetArrayMethodToken==============================
310**Action:
311**Returns:
312**Arguments: REFLECTMODULEBASEREF refThis
313** U1ARRAYREF sig
314** STRINGREF methodName
315** int tkTypeSpec
316**Exceptions:
317==============================================================================*/
318INT32 QCALLTYPE COMModule::GetArrayMethodToken(QCall::ModuleHandle pModule,
319 INT32 tkTypeSpec,
320 LPCWSTR wszMethodName,
321 LPCBYTE pSignature,
322 INT32 sigLength)
323{
324 QCALL_CONTRACT;
325
326 mdMemberRef memberRefE = mdTokenNil;
327
328 BEGIN_QCALL;
329
330 if (!wszMethodName)
331 COMPlusThrow(kArgumentNullException, W("ArgumentNull_String"));
332 if (!tkTypeSpec)
333 COMPlusThrow(kArgumentNullException, W("ArgumentNull_Type"));
334
335 RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter();
336 _ASSERTE(pRCW);
337
338 HRESULT hr = pRCW->GetEmitter()->DefineMemberRef(tkTypeSpec, wszMethodName, (PCCOR_SIGNATURE)pSignature, sigLength, &memberRefE);
339 if (FAILED(hr))
340 {
341 _ASSERTE(!"Failed on DefineMemberRef");
342 COMPlusThrowHR(hr);
343 }
344
345 END_QCALL;
346
347 return (INT32)memberRefE;
348}
349
350
351//******************************************************************************
352//
353// GetMemberRefToken
354// This function will return a MemberRef token given a MethodDef token and the module where the MethodDef/FieldDef is defined.
355//
356//******************************************************************************
357INT32 QCALLTYPE COMModule::GetMemberRef(QCall::ModuleHandle pModule, QCall::ModuleHandle pRefedModule, INT32 tr, INT32 token)
358{
359 QCALL_CONTRACT;
360
361 mdMemberRef memberRefE = 0;
362
363 BEGIN_QCALL;
364
365 RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter();
366 _ASSERTE( pRCW );
367
368 LPCUTF8 szName;
369 ULONG cbComSig;
370 PCCOR_SIGNATURE pvComSig;
371
372 if (TypeFromToken(token) == mdtMethodDef)
373 {
374 IfFailThrow(pRefedModule->GetMDImport()->GetNameOfMethodDef(token, &szName));
375 IfFailThrow(pRefedModule->GetMDImport()->GetSigOfMethodDef(token, &cbComSig, &pvComSig));
376 }
377 else
378 {
379 IfFailThrow(pRefedModule->GetMDImport()->GetNameOfFieldDef(token, &szName));
380 IfFailThrow(pRefedModule->GetMDImport()->GetSigOfFieldDef(token, &cbComSig, &pvComSig));
381 }
382
383 MAKE_WIDEPTR_FROMUTF8(wzName, szName);
384
385 // Translate the method sig into this scope
386 //
387 Assembly * pRefedAssembly = pRefedModule->GetAssembly();
388 Assembly * pRefingAssembly = pModule->GetAssembly();
389
390 if (pRefedAssembly->IsCollectible() && pRefedAssembly != pRefingAssembly)
391 {
392 if (pRefingAssembly->IsCollectible())
393 pRefingAssembly->GetLoaderAllocator()->EnsureReference(pRefedAssembly->GetLoaderAllocator());
394 else
395 COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleBoundNonCollectible"));
396 }
397
398 SafeComHolderPreemp<IMetaDataAssemblyEmit> pAssemblyEmit;
399 IfFailThrow( pRefingAssembly->GetManifestModule()->GetEmitter()->QueryInterface(IID_IMetaDataAssemblyEmit, (void **) &pAssemblyEmit) );
400
401 CQuickBytes qbNewSig;
402 ULONG cbNewSig;
403
404 IfFailThrow( pRefedModule->GetMDImport()->TranslateSigWithScope(
405 pRefedAssembly->GetManifestImport(),
406 NULL, 0, // hash value
407 pvComSig,
408 cbComSig,
409 pAssemblyEmit, // Emit assembly scope.
410 pRCW->GetEmitter(),
411 &qbNewSig,
412 &cbNewSig) );
413
414 mdTypeRef tref;
415
416 if (TypeFromToken(tr) == mdtTypeDef)
417 {
418 // define a TypeRef using the TypeDef
419 DefineTypeRefHelper(pRCW->GetEmitter(), tr, &tref);
420 }
421 else
422 tref = tr;
423
424 // Define the memberRef
425 IfFailThrow( pRCW->GetEmitter()->DefineMemberRef(tref, wzName, (PCCOR_SIGNATURE) qbNewSig.Ptr(), cbNewSig, &memberRefE) );
426
427 END_QCALL;
428
429 // assign output parameter
430 return (INT32)memberRefE;
431}
432
433
434//******************************************************************************
435//
436// Return a TypeRef token given a TypeDef token from the same emit scope
437//
438//******************************************************************************
439void COMModule::DefineTypeRefHelper(
440 IMetaDataEmit *pEmit, // given emit scope
441 mdTypeDef td, // given typedef in the emit scope
442 mdTypeRef *ptr) // return typeref
443{
444 CONTRACTL {
445 STANDARD_VM_CHECK;
446
447 PRECONDITION(CheckPointer(pEmit));
448 PRECONDITION(CheckPointer(ptr));
449 }
450 CONTRACTL_END;
451
452 CQuickBytes qb;
453 WCHAR* szTypeDef = (WCHAR*) qb.AllocThrows((MAX_CLASSNAME_LENGTH+1) * sizeof(WCHAR));
454 mdToken rs; // resolution scope
455 DWORD dwFlags;
456
457 SafeComHolder<IMetaDataImport> pImport;
458 IfFailThrow( pEmit->QueryInterface(IID_IMetaDataImport, (void **)&pImport) );
459 IfFailThrow( pImport->GetTypeDefProps(td, szTypeDef, MAX_CLASSNAME_LENGTH, NULL, &dwFlags, NULL) );
460 if ( IsTdNested(dwFlags) )
461 {
462 mdToken tdNested;
463 IfFailThrow( pImport->GetNestedClassProps(td, &tdNested) );
464 DefineTypeRefHelper( pEmit, tdNested, &rs);
465 }
466 else
467 rs = TokenFromRid( 1, mdtModule );
468
469 IfFailThrow( pEmit->DefineTypeRefByName( rs, szTypeDef, ptr) );
470} // DefineTypeRefHelper
471
472
473//******************************************************************************
474//
475// Return a MemberRef token given a RuntimeMethodInfo
476//
477//******************************************************************************
478INT32 QCALLTYPE COMModule::GetMemberRefOfMethodInfo(QCall::ModuleHandle pModule, INT32 tr, MethodDesc * pMeth)
479{
480 QCALL_CONTRACT;
481
482 mdMemberRef memberRefE = 0;
483
484 BEGIN_QCALL;
485
486 if (!pMeth)
487 COMPlusThrow(kArgumentNullException);
488
489 // Otherwise, we want to return memberref token.
490 if (pMeth->IsArray())
491 {
492 _ASSERTE(!"Should not have come here!");
493 COMPlusThrow(kNotSupportedException);
494 }
495
496 if (pMeth->GetMethodTable()->GetModule() == pModule)
497 {
498 // If the passed in method is defined in the same module, just return the MethodDef token
499 memberRefE = pMeth->GetMemberDef();
500 }
501 else
502 {
503 RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter();
504 _ASSERTE(pRCW);
505
506 LPCUTF8 szName;
507 IfFailThrow(pMeth->GetMDImport()->GetNameOfMethodDef(pMeth->GetMemberDef(), &szName));
508
509 ULONG cbComSig;
510 PCCOR_SIGNATURE pvComSig;
511 IfFailThrow(pMeth->GetMDImport()->GetSigOfMethodDef(pMeth->GetMemberDef(), &cbComSig, &pvComSig));
512
513 // Translate the method sig into this scope
514 Assembly * pRefedAssembly = pMeth->GetModule()->GetAssembly();
515 Assembly * pRefingAssembly = pModule->GetAssembly();
516
517 SafeComHolderPreemp<IMetaDataAssemblyEmit> pAssemblyEmit;
518 IfFailThrow( pRefingAssembly->GetManifestModule()->GetEmitter()->QueryInterface(IID_IMetaDataAssemblyEmit, (void **) &pAssemblyEmit) );
519
520 CQuickBytes qbNewSig;
521 ULONG cbNewSig;
522
523 if (pRefedAssembly->IsCollectible() && pRefedAssembly != pRefingAssembly)
524 {
525 if (pRefingAssembly->IsCollectible())
526 pRefingAssembly->GetLoaderAllocator()->EnsureReference(pRefedAssembly->GetLoaderAllocator());
527 else
528 COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleBoundNonCollectible"));
529 }
530
531 IfFailThrow( pMeth->GetMDImport()->TranslateSigWithScope(
532 pRefedAssembly->GetManifestImport(),
533 NULL, 0, // hash blob value
534 pvComSig,
535 cbComSig,
536 pAssemblyEmit, // Emit assembly scope.
537 pRCW->GetEmitter(),
538 &qbNewSig,
539 &cbNewSig) );
540
541 // translate the name to unicode string
542 MAKE_WIDEPTR_FROMUTF8(wszName, szName);
543
544 // Define the memberRef
545 IfFailThrow( pRCW->GetEmitter()->DefineMemberRef(tr, wszName, (PCCOR_SIGNATURE) qbNewSig.Ptr(), cbNewSig, &memberRefE) );
546 }
547
548 END_QCALL;
549
550 return memberRefE;
551}
552
553
554//******************************************************************************
555//
556// Return a MemberRef token given a RuntimeFieldInfo
557//
558//******************************************************************************
559mdMemberRef QCALLTYPE COMModule::GetMemberRefOfFieldInfo(QCall::ModuleHandle pModule, mdTypeDef tr, void * th, mdFieldDef tkField)
560{
561 QCALL_CONTRACT;
562
563 mdMemberRef memberRefE = 0;
564
565 BEGIN_QCALL;
566
567 if (TypeFromToken(tr) == mdtTypeDef)
568 {
569 // If the passed in method is defined in the same module, just return the FieldDef token
570 memberRefE = tkField;
571 }
572 else
573 {
574 TypeHandle typeHandle = TypeHandle::FromPtr(th);
575
576 RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter();
577 _ASSERTE(pRCW);
578
579 // get the field name and sig
580 Module * pRefedModule = typeHandle.GetModule();
581 IMDInternalImport * pRefedMDImport = pRefedModule->GetMDImport();
582
583 LPCUTF8 szName;
584 IfFailThrow(pRefedMDImport->GetNameOfFieldDef(tkField, &szName));
585
586 ULONG cbComSig;
587 PCCOR_SIGNATURE pvComSig;
588 IfFailThrow(pRefedMDImport->GetSigOfFieldDef(tkField, &cbComSig, &pvComSig));
589
590 // translate the name to unicode string
591 MAKE_WIDEPTR_FROMUTF8(wszName, szName);
592
593 Assembly * pRefedAssembly = pRefedModule->GetAssembly();
594 Assembly * pRefingAssembly = pModule->GetAssembly();
595
596 if (pRefedAssembly->IsCollectible() && pRefedAssembly != pRefingAssembly)
597 {
598 if (pRefingAssembly->IsCollectible())
599 pRefingAssembly->GetLoaderAllocator()->EnsureReference(pRefedAssembly->GetLoaderAllocator());
600 else
601 COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleBoundNonCollectible"));
602 }
603 SafeComHolderPreemp<IMetaDataAssemblyEmit> pAssemblyEmit;
604 IfFailThrow( pRefingAssembly->GetManifestModule()->GetEmitter()->QueryInterface(IID_IMetaDataAssemblyEmit, (void **) &pAssemblyEmit) );
605
606 // Translate the field signature this scope
607 CQuickBytes qbNewSig;
608 ULONG cbNewSig;
609
610 IfFailThrow( pRefedMDImport->TranslateSigWithScope(
611 pRefedAssembly->GetManifestImport(),
612 NULL, 0, // hash value
613 pvComSig,
614 cbComSig,
615 pAssemblyEmit, // Emit assembly scope.
616 pRCW->GetEmitter(),
617 &qbNewSig,
618 &cbNewSig) );
619
620 IfFailThrow( pRCW->GetEmitter()->DefineMemberRef(tr, wszName, (PCCOR_SIGNATURE) qbNewSig.Ptr(), cbNewSig, &memberRefE) );
621 }
622
623 END_QCALL;
624
625 return memberRefE;
626}
627
628//******************************************************************************
629//
630// Return a MemberRef token given a Signature
631//
632//******************************************************************************
633INT32 QCALLTYPE COMModule::GetMemberRefFromSignature(QCall::ModuleHandle pModule,
634 INT32 tr,
635 LPCWSTR wszMemberName,
636 LPCBYTE pSignature,
637 INT32 sigLength)
638{
639 QCALL_CONTRACT;
640
641 mdMemberRef memberRefE = mdTokenNil;
642
643 BEGIN_QCALL;
644
645 RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter();
646 _ASSERTE(pRCW);
647
648 IfFailThrow( pRCW->GetEmitter()->DefineMemberRef(tr,
649 wszMemberName,
650 pSignature,
651 sigLength,
652 &memberRefE) );
653
654 END_QCALL;
655
656 return memberRefE;
657}
658
659//******************************************************************************
660//
661// SetFieldRVAContent
662// This function is used to set the FieldRVA with the content data
663//
664//******************************************************************************
665void QCALLTYPE COMModule::SetFieldRVAContent(QCall::ModuleHandle pModule, INT32 tkField, LPCBYTE pContent, INT32 length)
666{
667 QCALL_CONTRACT;
668
669 BEGIN_QCALL;
670
671 RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter();
672 _ASSERTE(pRCW);
673
674 ICeeGen * pGen = pRCW->GetCeeGen();
675
676 ReflectionModule * pReflectionModule = pModule->GetReflectionModule();
677
678 // Create the .sdata section if not created
679 if (pReflectionModule->m_sdataSection == 0)
680 IfFailThrow( pGen->GetSectionCreate (".sdata", sdReadWrite, &pReflectionModule->m_sdataSection) );
681
682 // Get the size of current .sdata section. This will be the RVA for this field within the section
683 DWORD dwRVA = 0;
684 IfFailThrow( pGen->GetSectionDataLen(pReflectionModule->m_sdataSection, &dwRVA) );
685 dwRVA = (dwRVA + sizeof(DWORD)-1) & ~(sizeof(DWORD)-1);
686
687 // allocate the space in .sdata section
688 void * pvBlob;
689 IfFailThrow( pGen->GetSectionBlock(pReflectionModule->m_sdataSection, length, sizeof(DWORD), (void**) &pvBlob) );
690
691 // copy over the initialized data if specified
692 if (pContent != NULL)
693 memcpy(pvBlob, pContent, length);
694
695 // set FieldRVA into metadata. Note that this is not final RVA in the image if save to disk. We will do another round of fix up upon save.
696 IfFailThrow( pRCW->GetEmitter()->SetFieldRVA(tkField, dwRVA) );
697
698 END_QCALL;
699}
700
701
702//******************************************************************************
703//
704// GetStringConstant
705// If this is a dynamic module, this routine will define a new
706// string constant or return the token of an existing constant.
707//
708//******************************************************************************
709mdString QCALLTYPE COMModule::GetStringConstant(QCall::ModuleHandle pModule, LPCWSTR pwzValue, INT32 iLength)
710{
711 QCALL_CONTRACT;
712
713 mdString strRef = mdTokenNil;
714
715 BEGIN_QCALL;
716
717 RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter();
718 _ASSERTE(pRCW);
719
720 _ASSERTE(pwzValue != NULL);
721
722 HRESULT hr = pRCW->GetEmitter()->DefineUserString(pwzValue, iLength, &strRef);
723 if (FAILED(hr)) {
724 COMPlusThrowHR(hr);
725 }
726
727 END_QCALL;
728
729 return strRef;
730}
731
732
733/*=============================SetModuleName====================================
734// SetModuleName
735==============================================================================*/
736void QCALLTYPE COMModule::SetModuleName(QCall::ModuleHandle pModule, LPCWSTR wszModuleName)
737{
738 QCALL_CONTRACT;
739
740 BEGIN_QCALL;
741
742 RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter();
743 _ASSERTE(pRCW);
744
745 IfFailThrow( pRCW->GetEmitter()->SetModuleProps(wszModuleName) );
746
747 END_QCALL;
748}
749
750//******************************************************************************
751//
752// Return a type spec token given a byte array
753//
754//******************************************************************************
755BOOL QCALLTYPE COMModule::IsTransient(QCall::ModuleHandle pModule)
756{
757 QCALL_CONTRACT;
758
759 BOOL fIsTransient = FALSE;
760
761 BEGIN_QCALL;
762
763 /* Only reflection modules can be transient */
764 if (pModule->IsReflection())
765 fIsTransient = pModule->GetReflectionModule()->IsTransient();
766
767 END_QCALL;
768
769 return fIsTransient;
770}
771
772//******************************************************************************
773//
774// Return a type spec token given a byte array
775//
776//******************************************************************************
777mdTypeSpec QCALLTYPE COMModule::GetTokenFromTypeSpec(QCall::ModuleHandle pModule, LPCBYTE pSignature, INT32 sigLength)
778{
779 QCALL_CONTRACT;
780
781 mdTypeSpec ts = mdTokenNil;
782
783 BEGIN_QCALL;
784
785 RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter();
786 _ASSERTE(pRCW);
787
788 IfFailThrow(pRCW->GetEmitter()->GetTokenFromTypeSpec((PCCOR_SIGNATURE)pSignature, sigLength, &ts));
789
790 END_QCALL;
791
792 return ts;
793}
794
795
796// GetType
797// Given a class name, this method will look for that class
798// with in the module.
799void QCALLTYPE COMModule::GetType(QCall::ModuleHandle pModule, LPCWSTR wszName, BOOL bThrowOnError, BOOL bIgnoreCase, QCall::ObjectHandleOnStack retType, QCall::ObjectHandleOnStack keepAlive)
800{
801 CONTRACTL
802 {
803 QCALL_CHECK;
804 PRECONDITION(CheckPointer(wszName));
805 }
806 CONTRACTL_END;
807
808 TypeHandle retTypeHandle;
809
810 BEGIN_QCALL;
811
812 DomainAssembly *pAssembly = pModule->GetDomainAssembly();
813 _ASSERTE(pAssembly);
814
815 BOOL prohibitAsmQualifiedName = TRUE;
816
817 // Load the class from this assembly (fail if it is in a different one).
818 retTypeHandle = TypeName::GetTypeManaged(wszName, pAssembly, bThrowOnError, bIgnoreCase, prohibitAsmQualifiedName, NULL, FALSE, (OBJECTREF*)keepAlive.m_ppObject);
819
820 // Verify that it's in 'this' module
821 // But, if it's in a different assembly than expected, that's okay, because
822 // it just means that it's been type forwarded.
823 if (!retTypeHandle.IsNull())
824 {
825 if ( (retTypeHandle.GetModule() != pModule) &&
826 (retTypeHandle.GetModule()->GetAssembly() == pModule->GetAssembly()) )
827 retTypeHandle = TypeHandle();
828 }
829
830 if (!retTypeHandle.IsNull())
831 {
832 GCX_COOP();
833 retType.Set(retTypeHandle.GetManagedClassObject());
834 }
835
836 END_QCALL;
837
838 return;
839}
840
841
842// GetName
843// This routine will return the name of the module as a String
844void QCALLTYPE COMModule::GetScopeName(QCall::ModuleHandle pModule, QCall::StringHandleOnStack retString)
845{
846 QCALL_CONTRACT;
847
848 BEGIN_QCALL;
849
850 LPCSTR szName = NULL;
851
852 if (pModule->IsResource())
853 {
854 IfFailThrow(pModule->GetAssembly()->GetManifestImport()->GetFileProps(
855 pModule->GetModuleRef(),
856 &szName,
857 NULL,
858 NULL,
859 NULL));
860 }
861 else
862 {
863 if (!pModule->GetMDImport()->IsValidToken(pModule->GetMDImport()->GetModuleFromScope()))
864 {
865 ThrowHR(COR_E_BADIMAGEFORMAT);
866 }
867 IfFailThrow(pModule->GetMDImport()->GetScopeProps(&szName, 0));
868 }
869
870 retString.Set(szName);
871
872 END_QCALL;
873}
874
875static void ReplaceNiExtension(SString& fileName, PCWSTR pwzOldSuffix, PCWSTR pwzNewSuffix)
876{
877 STANDARD_VM_CONTRACT;
878
879 if (fileName.EndsWithCaseInsensitive(pwzOldSuffix))
880 {
881 COUNT_T oldSuffixLen = (COUNT_T)wcslen(pwzOldSuffix);
882 fileName.Replace(fileName.End() - oldSuffixLen, oldSuffixLen, pwzNewSuffix);
883 }
884}
885
886/*============================GetFullyQualifiedName=============================
887**Action:
888**Returns:
889**Arguments:
890**Exceptions:
891==============================================================================*/
892void QCALLTYPE COMModule::GetFullyQualifiedName(QCall::ModuleHandle pModule, QCall::StringHandleOnStack retString)
893{
894 QCALL_CONTRACT;
895
896 BEGIN_QCALL;
897
898 HRESULT hr = S_OK;
899
900 WCHAR wszBuffer[64];
901
902 if (pModule->IsPEFile())
903 {
904 LPCWSTR fileName = pModule->GetPath();
905 if (*fileName != 0) {
906 {
907#ifdef FEATURE_WINDOWSPHONE
908 //
909 // On Phone we use only native images without any concept of the matching IL image
910 // To stop native image filenames leaking through to apps, fudge Reflection::get_Name
911 // so apps see Foo.dll instead of Foo.ni.dll
912 //
913 if (pModule->GetFile()->GetAssembly()->GetILimage()->IsTrustedNativeImage())
914 {
915 SString fileNameWithoutNi(fileName);
916
917 ReplaceNiExtension(fileNameWithoutNi, W(".ni.dll"), W(".dll"));
918 ReplaceNiExtension(fileNameWithoutNi, W(".ni.exe"), W(".exe"));
919 ReplaceNiExtension(fileNameWithoutNi, W(".ni.winmd"), W(".winmd"));
920
921 retString.Set(fileNameWithoutNi);
922 }
923 else
924#endif
925 retString.Set(fileName);
926 }
927 } else {
928 hr = UtilLoadStringRC(IDS_EE_NAME_UNKNOWN, wszBuffer, sizeof( wszBuffer ) / sizeof( WCHAR ), true );
929 if (FAILED(hr))
930 COMPlusThrowHR(hr);
931 retString.Set(wszBuffer);
932 }
933 }
934 else
935 {
936 hr = UtilLoadStringRC(IDS_EE_NAME_INMEMORYMODULE, wszBuffer, sizeof( wszBuffer ) / sizeof( WCHAR ), true );
937 if (FAILED(hr))
938 COMPlusThrowHR(hr);
939 retString.Set(wszBuffer);
940 }
941
942 END_QCALL;
943}
944
945/*===================================GetHINSTANCE===============================
946**Action: Returns the hinst for this module.
947**Returns:
948**Arguments: refThis
949**Exceptions: None.
950==============================================================================*/
951HINSTANCE QCALLTYPE COMModule::GetHINSTANCE(QCall::ModuleHandle pModule)
952{
953 QCALL_CONTRACT;
954
955 HMODULE hMod = (HMODULE)0;
956
957 BEGIN_QCALL;
958
959 // This returns the base address - this will work for either HMODULE or HCORMODULES
960 // Other modules should have zero base
961 PEFile *pPEFile = pModule->GetFile();
962 if (!pPEFile->IsDynamic() && !pPEFile->IsResource())
963 {
964 hMod = (HMODULE) pModule->GetFile()->GetManagedFileContents();
965 }
966
967 //If we don't have an hMod, set it to -1 so that they know that there's none
968 //available
969 if (!hMod) {
970 hMod = (HMODULE)-1;
971 }
972
973 END_QCALL;
974
975 return (HINSTANCE)hMod;
976}
977
978static Object* GetTypesInner(Module* pModule);
979
980// Get class will return an array contain all of the classes
981// that are defined within this Module.
982FCIMPL1(Object*, COMModule::GetTypes, ReflectModuleBaseObject* pModuleUNSAFE)
983{
984 FCALL_CONTRACT;
985
986 OBJECTREF refRetVal = NULL;
987 REFLECTMODULEBASEREF refModule = (REFLECTMODULEBASEREF)ObjectToOBJECTREF(pModuleUNSAFE);
988 if (refModule == NULL)
989 FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
990
991 Module *pModule = refModule->GetModule();
992
993 HELPER_METHOD_FRAME_BEGIN_RET_2(refRetVal, refModule);
994
995 refRetVal = (OBJECTREF) GetTypesInner(pModule);
996
997 HELPER_METHOD_FRAME_END();
998
999 return OBJECTREFToObject(refRetVal);
1000}
1001FCIMPLEND
1002
1003Object* GetTypesInner(Module* pModule)
1004{
1005 CONTRACT(Object*) {
1006 THROWS;
1007 GC_TRIGGERS;
1008 MODE_COOPERATIVE;
1009 INJECT_FAULT(COMPlusThrowOM());
1010
1011 PRECONDITION(CheckPointer(pModule));
1012
1013 POSTCONDITION(CheckPointer(RETVAL));
1014 }
1015 CONTRACT_END;
1016
1017 DWORD dwNumTypeDefs = 0;
1018 DWORD i;
1019 IMDInternalImport *pInternalImport;
1020 PTRARRAYREF refArrClasses = NULL;
1021 PTRARRAYREF xcept = NULL;
1022 DWORD cXcept = 0;
1023 HENUMInternal hEnum;
1024 bool bSystemAssembly; // Don't expose transparent proxy
1025 int AllocSize = 0;
1026 MethodTable* pMT = NULL;
1027
1028 if (pModule->IsResource())
1029 {
1030 refArrClasses = (PTRARRAYREF) AllocateObjectArray(0, MscorlibBinder::GetClass(CLASS__CLASS));
1031 RETURN(OBJECTREFToObject(refArrClasses));
1032 }
1033
1034 GCPROTECT_BEGIN(refArrClasses);
1035 GCPROTECT_BEGIN(xcept);
1036
1037 pInternalImport = pModule->GetMDImport();
1038
1039 HENUMTypeDefInternalHolder hEnum(pInternalImport);
1040 // Get the count of typedefs
1041 hEnum.EnumTypeDefInit();
1042
1043 dwNumTypeDefs = pInternalImport->EnumTypeDefGetCount(&hEnum);
1044
1045 // Allocate the COM+ array
1046 bSystemAssembly = (pModule->GetAssembly() == SystemDomain::SystemAssembly());
1047 AllocSize = dwNumTypeDefs;
1048 refArrClasses = (PTRARRAYREF) AllocateObjectArray(AllocSize, MscorlibBinder::GetClass(CLASS__CLASS));
1049
1050 int curPos = 0;
1051 OBJECTREF throwable = 0;
1052 mdTypeDef tdCur = mdTypeDefNil;
1053
1054 GCPROTECT_BEGIN(throwable);
1055 // Now create each COM+ Method object and insert it into the array.
1056 while (pInternalImport->EnumTypeDefNext(&hEnum, &tdCur))
1057 {
1058 // Get the VM class for the current class token
1059 TypeHandle curClass;
1060
1061 EX_TRY {
1062 curClass = ClassLoader::LoadTypeDefOrRefThrowing(pModule, tdCur,
1063 ClassLoader::ThrowIfNotFound,
1064 ClassLoader::PermitUninstDefOrRef);
1065 }
1066 EX_CATCH_THROWABLE(&throwable);
1067
1068 if (throwable != 0) {
1069 // Lazily allocate an array to store the exceptions in
1070 if (xcept == NULL)
1071 xcept = (PTRARRAYREF) AllocateObjectArray(dwNumTypeDefs,g_pExceptionClass);
1072
1073 _ASSERTE(cXcept < dwNumTypeDefs);
1074 xcept->SetAt(cXcept++, throwable);
1075 throwable = 0;
1076 continue;
1077 }
1078
1079 _ASSERTE("LoadClass failed." && !curClass.IsNull());
1080
1081 pMT = curClass.GetMethodTable();
1082 PREFIX_ASSUME(pMT != NULL);
1083
1084 // Get the COM+ Class object
1085 OBJECTREF refCurClass = pMT->GetManagedClassObject();
1086 _ASSERTE("GetManagedClassObject failed." && refCurClass != NULL);
1087
1088 _ASSERTE(curPos < AllocSize);
1089 refArrClasses->SetAt(curPos++, refCurClass);
1090 }
1091 GCPROTECT_END(); //throwable
1092
1093 // check if there were exceptions thrown
1094 if (cXcept > 0) {
1095 PTRARRAYREF xceptRet = NULL;
1096 GCPROTECT_BEGIN(xceptRet);
1097
1098 xceptRet = (PTRARRAYREF) AllocateObjectArray(cXcept,g_pExceptionClass);
1099 for (i=0;i<cXcept;i++) {
1100 xceptRet->SetAt(i, xcept->GetAt(i));
1101 }
1102 OBJECTREF except = InvokeUtil::CreateClassLoadExcept((OBJECTREF*) &refArrClasses,(OBJECTREF*) &xceptRet);
1103 COMPlusThrow(except);
1104
1105 GCPROTECT_END();
1106 }
1107
1108 // We should have filled the array exactly.
1109 _ASSERTE(curPos == AllocSize);
1110
1111 // Assign the return value to the COM+ array
1112 GCPROTECT_END();
1113 GCPROTECT_END();
1114
1115 RETURN(OBJECTREFToObject(refArrClasses));
1116}
1117
1118
1119FCIMPL1(FC_BOOL_RET, COMModule::IsResource, ReflectModuleBaseObject* pModuleUNSAFE)
1120{
1121 FCALL_CONTRACT;
1122
1123 if (pModuleUNSAFE == NULL)
1124 FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
1125
1126 FC_RETURN_BOOL(pModuleUNSAFE->GetModule()->IsResource());
1127}
1128FCIMPLEND
1129
1130
1131//---------------------------------------------------------------------
1132// Helper code for PunkSafeHandle class. This does the Release in the
1133// safehandle's critical finalizer.
1134//---------------------------------------------------------------------
1135static VOID __stdcall DReleaseTarget(IUnknown *punk)
1136{
1137 CONTRACTL
1138 {
1139 NOTHROW;
1140 GC_TRIGGERS;
1141 MODE_PREEMPTIVE;
1142 SO_TOLERANT;
1143 }
1144 CONTRACTL_END;
1145
1146 if (punk)
1147 {
1148 punk->Release();
1149 }
1150}
1151
1152
1153//---------------------------------------------------------------------
1154// Helper code for PunkSafeHandle class. This returns the function that performs
1155// the Release() for the safehandle's critical finalizer.
1156//---------------------------------------------------------------------
1157FCIMPL0(void*, COMPunkSafeHandle::nGetDReleaseTarget)
1158{
1159 FCALL_CONTRACT;
1160
1161 return (void*)DReleaseTarget;
1162}
1163FCIMPLEND
1164
1165
1166