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 | //=============================================================================================== |
32 | static 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 | //=============================================================================================== |
119 | FCIMPL2(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 |
146 | FCIMPLEND |
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 | //************************************************** |
154 | void 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 | //************************************************** |
204 | mdTypeRef 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 | ==============================================================================*/ |
318 | INT32 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 | //****************************************************************************** |
357 | INT32 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 | //****************************************************************************** |
439 | void 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 | //****************************************************************************** |
478 | INT32 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 | //****************************************************************************** |
559 | mdMemberRef 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 | //****************************************************************************** |
633 | INT32 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 | //****************************************************************************** |
665 | void 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 | //****************************************************************************** |
709 | mdString 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 | ==============================================================================*/ |
736 | void 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 | //****************************************************************************** |
755 | BOOL 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 | //****************************************************************************** |
777 | mdTypeSpec 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. |
799 | void 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 |
844 | void 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 | |
875 | static 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 | ==============================================================================*/ |
892 | void 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 | ==============================================================================*/ |
951 | HINSTANCE 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 | |
978 | static Object* GetTypesInner(Module* pModule); |
979 | |
980 | // Get class will return an array contain all of the classes |
981 | // that are defined within this Module. |
982 | FCIMPL1(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 | } |
1001 | FCIMPLEND |
1002 | |
1003 | Object* 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 | |
1119 | FCIMPL1(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 | } |
1128 | FCIMPLEND |
1129 | |
1130 | |
1131 | //--------------------------------------------------------------------- |
1132 | // Helper code for PunkSafeHandle class. This does the Release in the |
1133 | // safehandle's critical finalizer. |
1134 | //--------------------------------------------------------------------- |
1135 | static 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 | //--------------------------------------------------------------------- |
1157 | FCIMPL0(void*, COMPunkSafeHandle::nGetDReleaseTarget) |
1158 | { |
1159 | FCALL_CONTRACT; |
1160 | |
1161 | return (void*)DReleaseTarget; |
1162 | } |
1163 | FCIMPLEND |
1164 | |
1165 | |
1166 | |