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// File: RegMeta_IMetaDataImport.cpp
6//
7
8//
9// Methods of code:RegMeta class which implement public API interfaces:
10// * code:IMetaDataImport
11// * code:IMetaDataImport2
12//
13// ======================================================================================
14
15#include "stdafx.h"
16#include "regmeta.h"
17#include "metadata.h"
18#include "corerror.h"
19#include "mdutil.h"
20#include "rwutil.h"
21#include "mdlog.h"
22#include "importhelper.h"
23#include "filtermanager.h"
24#include "mdperf.h"
25#include "switches.h"
26#include "posterror.h"
27#include "stgio.h"
28#include "sstring.h"
29
30#include <metamodelrw.h>
31
32#define DEFINE_CUSTOM_NODUPCHECK 1
33#define DEFINE_CUSTOM_DUPCHECK 2
34#define SET_CUSTOM 3
35
36#if defined(_DEBUG) && defined(_TRACE_REMAPS)
37#define LOGGING
38#endif
39#include <log.h>
40
41#ifdef _MSC_VER
42#pragma warning(disable: 4102)
43#endif
44
45//*****************************************************************************
46// determine if a token is valid or not
47//*****************************************************************************
48BOOL RegMeta::IsValidToken( // true if tk is valid token
49 mdToken tk) // [IN] token to be checked
50{
51 BOOL fRet = FALSE;
52 HRESULT hr = S_OK;
53 BEGIN_ENTRYPOINT_VOIDRET;
54
55 LOCKREADNORET();
56
57 // If acquiring the lock failed...
58 IfFailGo(hr);
59
60 fRet = m_pStgdb->m_MiniMd._IsValidToken(tk);
61
62ErrExit:
63 END_ENTRYPOINT_VOIDRET;
64 return fRet;
65} // RegMeta::IsValidToken
66
67//*****************************************************************************
68// Close an enumerator.
69//*****************************************************************************
70void STDMETHODCALLTYPE RegMeta::CloseEnum(
71 HCORENUM hEnum) // The enumerator.
72{
73 BEGIN_CLEANUP_ENTRYPOINT;
74
75 LOG((LOGMD, "RegMeta::CloseEnum(0x%08x)\n", hEnum));
76
77 // No need to lock this function.
78 HENUMInternal *pmdEnum = reinterpret_cast<HENUMInternal *> (hEnum);
79
80 if (pmdEnum == NULL)
81 return;
82
83 // This function may be called through RCW. When hosted, we have probed before this call, so the
84 // following contract violation is OK.
85 CONTRACT_VIOLATION(SOToleranceViolation);
86 HENUMInternal::DestroyEnum(pmdEnum);
87 END_CLEANUP_ENTRYPOINT;
88} // RegMeta::CloseEnum
89
90//*****************************************************************************
91// Query the count of items represented by an enumerator.
92//*****************************************************************************
93HRESULT CountEnum(
94 HCORENUM hEnum, // The enumerator.
95 ULONG *pulCount) // Put the count here.
96{
97 HENUMInternal *pmdEnum = reinterpret_cast<HENUMInternal *> (hEnum);
98 HRESULT hr = S_OK;
99
100 // No need to lock this function.
101
102 LOG((LOGMD, "RegMeta::CountEnum(0x%08x, 0x%08x)\n", hEnum, pulCount));
103 START_MD_PERF();
104
105 _ASSERTE( pulCount );
106
107 if (pmdEnum == NULL)
108 {
109 *pulCount = 0;
110 goto ErrExit;
111 }
112
113 if (pmdEnum->m_tkKind == (TBL_MethodImpl << 24))
114 {
115 // Number of tokens must always be a multiple of 2.
116 _ASSERTE(! (pmdEnum->m_ulCount % 2) );
117 // There are two entries in the Enumerator for each MethodImpl.
118 *pulCount = pmdEnum->m_ulCount / 2;
119 }
120 else
121 *pulCount = pmdEnum->m_ulCount;
122ErrExit:
123 STOP_MD_PERF(CountEnum);
124 return hr;
125} // ::CountEnum
126
127STDMETHODIMP RegMeta::CountEnum(
128 HCORENUM hEnum, // The enumerator.
129 ULONG *pulCount) // Put the count here.
130{
131 HRESULT hr = S_OK;
132 BEGIN_ENTRYPOINT_NOTHROW;
133
134 hr = ::CountEnum(hEnum, pulCount);
135 END_ENTRYPOINT_NOTHROW;
136 return hr;
137} // RegMeta::CountEnum
138
139//*****************************************************************************
140// Reset an enumerator to any position within the enumerator.
141//*****************************************************************************
142STDMETHODIMP RegMeta::ResetEnum(
143 HCORENUM hEnum, // The enumerator.
144 ULONG ulPos) // Seek position.
145{
146 HRESULT hr = S_OK;
147
148 BEGIN_ENTRYPOINT_NOTHROW;
149
150 HENUMInternal *pmdEnum = reinterpret_cast<HENUMInternal *> (hEnum);
151
152 // No need to lock this function.
153
154 LOG((LOGMD, "RegMeta::ResetEnum(0x%08x, 0x%08x)\n", hEnum, ulPos));
155 START_MD_PERF();
156
157 if (pmdEnum == NULL)
158 goto ErrExit;
159
160 pmdEnum->u.m_ulCur = pmdEnum->u.m_ulStart + ulPos;
161
162ErrExit:
163 STOP_MD_PERF(ResetEnum);
164 END_ENTRYPOINT_NOTHROW;
165 return hr;
166} // RegMeta::ResetEnum
167
168//*****************************************************************************
169// Enumerate Sym.TypeDef.
170//*****************************************************************************
171STDMETHODIMP RegMeta::EnumTypeDefs(
172 HCORENUM *phEnum, // Pointer to the enumerator.
173 mdTypeDef rTypeDefs[], // Put TypeDefs here.
174 ULONG cMax, // Max TypeDefs to put.
175 ULONG *pcTypeDefs) // Put # put here.
176{
177 HRESULT hr = S_OK;
178
179 BEGIN_ENTRYPOINT_NOTHROW;
180
181 HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
182 HENUMInternal *pEnum;
183
184 LOG((LOGMD, "RegMeta::EnumTypeDefs(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
185 phEnum, rTypeDefs, cMax, pcTypeDefs));
186 START_MD_PERF();
187 LOCKREAD();
188
189
190 if ( *ppmdEnum == 0 )
191 {
192 // instantiating a new ENUM
193 CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
194
195 if (pMiniMd->HasDelete() &&
196 ((m_OptionValue.m_ImportOption & MDImportOptionAllTypeDefs) == 0))
197 {
198 IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtTypeDef, &pEnum) );
199
200 // add all Types to the dynamic array if name is not _Delete
201 for (ULONG index = 2; index <= pMiniMd->getCountTypeDefs(); index ++ )
202 {
203 TypeDefRec *pRec;
204 IfFailGo(pMiniMd->GetTypeDefRecord(index, &pRec));
205 LPCSTR szTypeDefName;
206 IfFailGo(pMiniMd->getNameOfTypeDef(pRec, &szTypeDefName));
207 if (IsDeletedName(szTypeDefName))
208 {
209 continue;
210 }
211 IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtTypeDef) ) );
212 }
213 }
214 else
215 {
216 // create the enumerator
217 IfFailGo( HENUMInternal::CreateSimpleEnum(
218 mdtTypeDef,
219 2,
220 pMiniMd->getCountTypeDefs() + 1,
221 &pEnum) );
222 }
223
224 // set the output parameter
225 *ppmdEnum = pEnum;
226 }
227 else
228 {
229 pEnum = *ppmdEnum;
230 }
231
232 // we can only fill the minimun of what caller asked for or what we have left
233 hr = HENUMInternal::EnumWithCount(pEnum, cMax, rTypeDefs, pcTypeDefs);
234
235ErrExit:
236 HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
237
238 STOP_MD_PERF(EnumTypeDefs);
239
240 END_ENTRYPOINT_NOTHROW;
241
242 return hr;
243} // RegMeta::EnumTypeDefs
244
245//*****************************************************************************
246// Enumerate Sym.InterfaceImpl where Coclass == td
247//*****************************************************************************
248STDMETHODIMP RegMeta::EnumInterfaceImpls(
249 HCORENUM *phEnum, // Pointer to the enum.
250 mdTypeDef td, // TypeDef to scope the enumeration.
251 mdInterfaceImpl rImpls[], // Put InterfaceImpls here.
252 ULONG cMax, // Max InterfaceImpls to put.
253 ULONG *pcImpls) // Put # put here.
254{
255 HRESULT hr = S_OK;
256
257 BEGIN_ENTRYPOINT_NOTHROW;
258
259 HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
260 ULONG ridStart;
261 ULONG ridEnd;
262 HENUMInternal *pEnum;
263 InterfaceImplRec *pRec;
264 ULONG index;
265
266 LOG((LOGMD, "RegMeta::EnumInterfaceImpls(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
267 phEnum, td, rImpls, cMax, pcImpls));
268 START_MD_PERF();
269 LOCKREAD();
270
271 _ASSERTE(TypeFromToken(td) == mdtTypeDef);
272
273
274 if ( *ppmdEnum == 0 )
275 {
276 // instantiating a new ENUM
277 CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
278 if ( pMiniMd->IsSorted( TBL_InterfaceImpl ) )
279 {
280 IfFailGo(pMiniMd->getInterfaceImplsForTypeDef(RidFromToken(td), &ridEnd, &ridStart));
281 IfFailGo( HENUMInternal::CreateSimpleEnum( mdtInterfaceImpl, ridStart, ridEnd, &pEnum) );
282 }
283 else
284 {
285 // table is not sorted so we have to create dynmaic array
286 // create the dynamic enumerator
287 //
288 ridStart = 1;
289 ridEnd = pMiniMd->getCountInterfaceImpls() + 1;
290
291 IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtInterfaceImpl, &pEnum) );
292
293 for (index = ridStart; index < ridEnd; index ++ )
294 {
295 IfFailGo(pMiniMd->GetInterfaceImplRecord(index, &pRec));
296 if ( td == pMiniMd->getClassOfInterfaceImpl(pRec) )
297 {
298 IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtInterfaceImpl) ) );
299 }
300 }
301 }
302
303 // set the output parameter
304 *ppmdEnum = pEnum;
305 }
306 else
307 {
308 pEnum = *ppmdEnum;
309 }
310
311 // fill the output token buffer
312 hr = HENUMInternal::EnumWithCount(pEnum, cMax, rImpls, pcImpls);
313
314ErrExit:
315 HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
316
317 STOP_MD_PERF(EnumInterfaceImpls);
318
319 END_ENTRYPOINT_NOTHROW;
320
321 return hr;
322} // RegMeta::EnumInterfaceImpls
323
324STDMETHODIMP RegMeta::EnumGenericParams(HCORENUM *phEnum, mdToken tkOwner,
325 mdGenericParam rTokens[], ULONG cMaxTokens, ULONG *pcTokens)
326{
327 HRESULT hr = S_OK;
328
329 BEGIN_ENTRYPOINT_NOTHROW;
330
331 HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
332 ULONG ridStart;
333 ULONG ridEnd;
334 HENUMInternal *pEnum;
335 GenericParamRec *pRec;
336 ULONG index;
337 CMiniMdRW *pMiniMd = NULL;
338
339
340 LOG((LOGMD, "RegMeta::EnumGenericParams(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
341 phEnum, tkOwner, rTokens, cMaxTokens, pcTokens));
342 START_MD_PERF();
343 LOCKREAD();
344
345 pMiniMd = &(m_pStgdb->m_MiniMd);
346
347
348 // See if this version of the metadata can do Generics
349 if (!pMiniMd->SupportsGenerics())
350 {
351 if (pcTokens)
352 *pcTokens = 0;
353 hr = S_FALSE;
354 goto ErrExit;
355 }
356
357
358 _ASSERTE(TypeFromToken(tkOwner) == mdtTypeDef || TypeFromToken(tkOwner) == mdtMethodDef);
359
360
361 if ( *ppmdEnum == 0 )
362 {
363 // instantiating a new ENUM
364
365 //@todo GENERICS: review this. Are we expecting a sorted table or not?
366 if ( pMiniMd->IsSorted( TBL_GenericParam ) )
367 {
368 if (TypeFromToken(tkOwner) == mdtTypeDef)
369 {
370 IfFailGo(pMiniMd->getGenericParamsForTypeDef(RidFromToken(tkOwner), &ridEnd, &ridStart));
371 }
372 else
373 {
374 IfFailGo(pMiniMd->getGenericParamsForMethodDef(RidFromToken(tkOwner), &ridEnd, &ridStart));
375 }
376
377 IfFailGo( HENUMInternal::CreateSimpleEnum(mdtGenericParam, ridStart, ridEnd, &pEnum) );
378 }
379 else
380 {
381 // table is not sorted so we have to create dynamic array
382 // create the dynamic enumerator
383 //
384 ridStart = 1;
385 ridEnd = pMiniMd->getCountGenericParams() + 1;
386
387 IfFailGo( HENUMInternal::CreateDynamicArrayEnum(mdtGenericParam, &pEnum) );
388
389 for (index = ridStart; index < ridEnd; index ++ )
390 {
391 IfFailGo(pMiniMd->GetGenericParamRecord(index, &pRec));
392 if ( tkOwner == pMiniMd->getOwnerOfGenericParam(pRec) )
393 {
394 IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtGenericParam) ) );
395 }
396 }
397 }
398
399 // set the output parameter
400 *ppmdEnum = pEnum;
401 }
402 else
403 {
404 pEnum = *ppmdEnum;
405 }
406
407 // fill the output token buffer
408 hr = HENUMInternal::EnumWithCount(pEnum, cMaxTokens, rTokens, pcTokens);
409
410ErrExit:
411 HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
412 STOP_MD_PERF(EnumGenericPars);
413 END_ENTRYPOINT_NOTHROW;
414
415 return hr;
416} // RegMeta::EnumGenericParams
417
418STDMETHODIMP RegMeta::EnumMethodSpecs(
419 HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
420 mdToken tkOwner, // [IN] MethodDef or MemberRef whose MethodSpecs are requested
421 mdMethodSpec rTokens[], // [OUT] Put MethodSpecs here.
422 ULONG cMaxTokens, // [IN] Max tokens to put.
423 ULONG *pcTokens) // [OUT] Put actual count here.
424{
425 HRESULT hr = S_OK;
426
427 BEGIN_ENTRYPOINT_NOTHROW;
428
429 HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
430 ULONG ridStart;
431 ULONG ridEnd;
432 HENUMInternal *pEnum;
433 MethodSpecRec *pRec;
434 ULONG index;
435 CMiniMdRW *pMiniMd = NULL;
436
437 LOG((LOGMD, "RegMeta::EnumMethodSpecs(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
438 phEnum, tkOwner, rTokens, cMaxTokens, pcTokens));
439 START_MD_PERF();
440 LOCKREAD();
441
442 pMiniMd = &(m_pStgdb->m_MiniMd);
443
444 // See if this version of the metadata can do Generics
445 if (!pMiniMd->SupportsGenerics())
446 {
447 if (pcTokens)
448 *pcTokens = 0;
449 hr = S_FALSE;
450 goto ErrExit;
451 }
452
453
454 _ASSERTE(RidFromToken(tkOwner)==0 || TypeFromToken(tkOwner) == mdtMethodDef || TypeFromToken(tkOwner) == mdtMemberRef);
455
456
457 if ( *ppmdEnum == 0 )
458 {
459 // instantiating a new ENUM
460
461 if(RidFromToken(tkOwner)==0) // enumerate all MethodSpecs
462 {
463 ridStart = 1;
464 ridEnd = pMiniMd->getCountMethodSpecs() + 1;
465
466 IfFailGo( HENUMInternal::CreateSimpleEnum( mdtMethodSpec, ridStart, ridEnd, &pEnum) );
467 }
468 else
469 {
470 //@todo GENERICS: review this. Are we expecting a sorted table or not?
471 if ( pMiniMd->IsSorted( TBL_MethodSpec ) )
472 {
473 if (TypeFromToken(tkOwner) == mdtMemberRef)
474 {
475 IfFailGo(pMiniMd->getMethodSpecsForMemberRef(RidFromToken(tkOwner), &ridEnd, &ridStart));
476 }
477 else
478 {
479 IfFailGo(pMiniMd->getMethodSpecsForMethodDef(RidFromToken(tkOwner), &ridEnd, &ridStart));
480 }
481
482 IfFailGo( HENUMInternal::CreateSimpleEnum(mdtMethodSpec, ridStart, ridEnd, &pEnum) );
483 }
484 else
485 {
486 // table is not sorted so we have to create dynamic array
487 // create the dynamic enumerator
488 //
489 ridStart = 1;
490 ridEnd = pMiniMd->getCountMethodSpecs() + 1;
491
492 IfFailGo( HENUMInternal::CreateDynamicArrayEnum(mdtMethodSpec, &pEnum) );
493
494 for (index = ridStart; index < ridEnd; index ++ )
495 {
496 IfFailGo(pMiniMd->GetMethodSpecRecord(index, &pRec));
497 if ( tkOwner == pMiniMd->getMethodOfMethodSpec(pRec) )
498 {
499 IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtMethodSpec) ) );
500 }
501 }
502 }
503 }
504 // set the output parameter
505 *ppmdEnum = pEnum;
506 }
507 else
508 {
509 pEnum = *ppmdEnum;
510 }
511
512 // fill the output token buffer
513 hr = HENUMInternal::EnumWithCount(pEnum, cMaxTokens, rTokens, pcTokens);
514
515ErrExit:
516 HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
517 STOP_MD_PERF(EnumMethodSpecs);
518 END_ENTRYPOINT_NOTHROW;
519
520 return hr;
521} // STDMETHODIMP RegMeta::EnumMethodSpecs()
522
523STDMETHODIMP RegMeta::EnumGenericParamConstraints(
524 HCORENUM *phEnum, // [IN|OUT] Pointer to the enum.
525 mdGenericParam tkOwner, // [IN] GenericParam whose constraints are requested
526 mdGenericParamConstraint rTokens[], // [OUT] Put GenericParamConstraints here.
527 ULONG cMaxTokens, // [IN] Max GenericParamConstraints to put.
528 ULONG *pcTokens) // [OUT] Put # of tokens here.
529{
530 HRESULT hr = S_OK;
531
532 BEGIN_ENTRYPOINT_NOTHROW;
533
534 HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
535 ULONG ridStart;
536 ULONG ridEnd;
537 HENUMInternal *pEnum;
538 GenericParamConstraintRec *pRec;
539 ULONG index;
540 CMiniMdRW *pMiniMd = NULL;
541
542 LOG((LOGMD, "RegMeta::EnumGenericParamConstraints(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
543 phEnum, tkOwner, rTokens, cMaxTokens, pcTokens));
544 START_MD_PERF();
545 LOCKREAD();
546
547 pMiniMd = &(m_pStgdb->m_MiniMd);
548
549
550 if(TypeFromToken(tkOwner) != mdtGenericParam)
551 IfFailGo(META_E_BAD_INPUT_PARAMETER);
552
553 // See if this version of the metadata can do Generics
554 if (!pMiniMd->SupportsGenerics())
555 {
556 if (pcTokens)
557 *pcTokens = 0;
558 hr = S_FALSE;
559 goto ErrExit;
560 }
561
562 if ( *ppmdEnum == 0 )
563 {
564 // instantiating a new ENUM
565
566 //<TODO> GENERICS: review this. Are we expecting a sorted table or not? </TODO>
567 if ( pMiniMd->IsSorted( TBL_GenericParamConstraint ) )
568 {
569 IfFailGo(pMiniMd->getGenericParamConstraintsForGenericParam(RidFromToken(tkOwner), &ridEnd, &ridStart));
570 IfFailGo( HENUMInternal::CreateSimpleEnum(mdtGenericParamConstraint, ridStart, ridEnd, &pEnum) );
571 }
572 else
573 {
574 // table is not sorted so we have to create dynamic array
575 // create the dynamic enumerator
576 //
577 ridStart = 1;
578 ridEnd = pMiniMd->getCountGenericParamConstraints() + 1;
579
580 IfFailGo( HENUMInternal::CreateDynamicArrayEnum(mdtGenericParamConstraint, &pEnum));
581
582 for (index = ridStart; index < ridEnd; index ++ )
583 {
584 IfFailGo(pMiniMd->GetGenericParamConstraintRecord(index, &pRec));
585 if ( tkOwner == pMiniMd->getOwnerOfGenericParamConstraint(pRec))
586 {
587 IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index,
588 mdtGenericParamConstraint)));
589 }
590 }
591 }
592
593 // set the output parameter
594 *ppmdEnum = pEnum;
595 }
596 else
597 {
598 pEnum = *ppmdEnum;
599 }
600
601 // fill the output token buffer
602 hr = HENUMInternal::EnumWithCount(pEnum, cMaxTokens, rTokens, pcTokens);
603
604ErrExit:
605 HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
606 STOP_MD_PERF(EnumGenericParamConstraints);
607 END_ENTRYPOINT_NOTHROW;
608
609 return hr;
610}
611
612//*****************************************************************************
613// Enumerate Sym.TypeRef
614//*****************************************************************************
615STDMETHODIMP RegMeta::EnumTypeRefs(
616 HCORENUM *phEnum, // Pointer to the enumerator.
617 mdTypeRef rTypeRefs[], // Put TypeRefs here.
618 ULONG cMax, // Max TypeRefs to put.
619 ULONG *pcTypeRefs) // Put # put here.
620{
621 HRESULT hr = S_OK;
622
623 BEGIN_ENTRYPOINT_NOTHROW;
624
625 HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
626 ULONG cTotal;
627 HENUMInternal *pEnum = *ppmdEnum;
628
629
630
631 LOG((LOGMD, "RegMeta::EnumTypeRefs(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
632 phEnum, rTypeRefs, cMax, pcTypeRefs));
633 START_MD_PERF();
634 LOCKREAD();
635
636 if ( pEnum == 0 )
637 {
638 // instantiating a new ENUM
639 CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
640 cTotal = pMiniMd->getCountTypeRefs();
641
642 IfFailGo( HENUMInternal::CreateSimpleEnum( mdtTypeRef, 1, cTotal + 1, &pEnum) );
643
644 // set the output parameter
645 *ppmdEnum = pEnum;
646 }
647
648 // fill the output token buffer
649 hr = HENUMInternal::EnumWithCount(pEnum, cMax, rTypeRefs, pcTypeRefs);
650
651ErrExit:
652 HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
653
654
655 STOP_MD_PERF(EnumTypeRefs);
656 END_ENTRYPOINT_NOTHROW;
657
658 return hr;
659} // STDMETHODIMP RegMeta::EnumTypeRefs()
660
661//*****************************************************************************
662// Given a namespace and a class name, return the typedef
663//*****************************************************************************
664STDMETHODIMP RegMeta::FindTypeDefByName(// S_OK or error.
665 LPCWSTR wzTypeDef, // [IN] Name of the Type.
666 mdToken tkEnclosingClass, // [IN] Enclosing class.
667 mdTypeDef *ptd) // [OUT] Put the TypeDef token here.
668{
669 HRESULT hr = S_OK;
670 BEGIN_ENTRYPOINT_NOTHROW
671
672 LOG((LOGMD, "{%08x} RegMeta::FindTypeDefByName(%S, 0x%08x, 0x%08x)\n",
673 this, MDSTR(wzTypeDef), tkEnclosingClass, ptd));
674 START_MD_PERF();
675 LOCKREAD();
676
677
678 if (wzTypeDef == NULL)
679 IfFailGo(E_INVALIDARG);
680 PREFIX_ASSUME(wzTypeDef != NULL);
681 LPSTR szTypeDef;
682 UTF8STR(wzTypeDef, szTypeDef);
683 LPCSTR szNamespace;
684 LPCSTR szName;
685
686 _ASSERTE(ptd);
687 _ASSERTE(TypeFromToken(tkEnclosingClass) == mdtTypeDef ||
688 TypeFromToken(tkEnclosingClass) == mdtTypeRef ||
689 IsNilToken(tkEnclosingClass));
690
691 // initialize output parameter
692 *ptd = mdTypeDefNil;
693
694 ns::SplitInline(szTypeDef, szNamespace, szName);
695 hr = ImportHelper::FindTypeDefByName(&(m_pStgdb->m_MiniMd),
696 szNamespace,
697 szName,
698 tkEnclosingClass,
699 ptd);
700ErrExit:
701
702 STOP_MD_PERF(FindTypeDefByName);
703 END_ENTRYPOINT_NOTHROW;
704
705 return hr;
706} // STDMETHODIMP RegMeta::FindTypeDefByName()
707
708//*****************************************************************************
709// Get values from Sym.Module
710//*****************************************************************************
711STDMETHODIMP RegMeta::GetScopeProps(
712 __out_ecount_opt (cchName) LPWSTR szName, // Put name here
713 ULONG cchName, // Size in chars of name buffer
714 ULONG *pchName, // Put actual length of name here
715 GUID *pmvid) // Put MVID here
716{
717 HRESULT hr = S_OK;
718
719 BEGIN_ENTRYPOINT_NOTHROW;
720
721 CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
722 ModuleRec *pModuleRec;
723
724
725 LOG((LOGMD, "RegMeta::GetScopeProps(%S, 0x%08x, 0x%08x, 0x%08x)\n",
726 MDSTR(szName), cchName, pchName, pmvid));
727 START_MD_PERF();
728 LOCKREAD();
729
730 // there is only one module record
731 IfFailGo(pMiniMd->GetModuleRecord(1, &pModuleRec));
732
733 if (pmvid != NULL)
734 {
735 IfFailGo(pMiniMd->getMvidOfModule(pModuleRec, pmvid));
736 }
737 // This call has to be last to set 'hr', so CLDB_S_TRUNCATION is not rewritten with S_OK
738 if (szName || pchName)
739 IfFailGo( pMiniMd->getNameOfModule(pModuleRec, szName, cchName, pchName) );
740ErrExit:
741
742 STOP_MD_PERF(GetScopeProps);
743 END_ENTRYPOINT_NOTHROW;
744
745 return hr;
746} // STDMETHODIMP RegMeta::GetScopeProps()
747
748//*****************************************************************************
749// Get the token for a Scope's (primary) module record.
750//*****************************************************************************
751STDMETHODIMP RegMeta::GetModuleFromScope(// S_OK.
752 mdModule *pmd) // [OUT] Put mdModule token here.
753{
754 HRESULT hr = S_OK;
755 BEGIN_ENTRYPOINT_NOTHROW;
756
757 LOG((LOGMD, "RegMeta::GetModuleFromScope(0x%08x)\n", pmd));
758 START_MD_PERF();
759
760 _ASSERTE(pmd);
761
762 // No need to lock this function.
763
764 *pmd = TokenFromRid(1, mdtModule);
765
766 STOP_MD_PERF(GetModuleFromScope);
767 END_ENTRYPOINT_NOTHROW;
768
769 return hr;
770} // STDMETHODIMP RegMeta::GetModuleFromScope()
771
772//*****************************************************************************
773// Given a token, is it (or its parent) global?
774//*****************************************************************************
775HRESULT RegMeta::IsGlobal( // S_OK ir error.
776 mdToken tk, // [IN] Type, Field, or Method token.
777 int *pbGlobal) // [OUT] Put 1 if global, 0 otherwise.
778{
779 HRESULT hr=S_OK; // A result.
780
781 BEGIN_ENTRYPOINT_NOTHROW;
782
783 CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
784 mdToken tkParent; // Parent of field or method.
785
786 LOG((LOGMD, "RegMeta::GetTokenForGlobalType(0x%08x, %08x)\n", tk, pbGlobal));
787 //START_MD_PERF();
788
789 // No need to lock this function.
790
791 if (!IsValidToken(tk))
792 IfFailGo(E_INVALIDARG);
793
794 switch (TypeFromToken(tk))
795 {
796 case mdtTypeDef:
797 *pbGlobal = IsGlobalMethodParentToken(tk);
798 break;
799
800 case mdtFieldDef:
801 IfFailGo( pMiniMd->FindParentOfFieldHelper(tk, &tkParent) );
802 *pbGlobal = IsGlobalMethodParentToken(tkParent);
803 break;
804
805 case mdtMethodDef:
806 IfFailGo( pMiniMd->FindParentOfMethodHelper(tk, &tkParent) );
807 *pbGlobal = IsGlobalMethodParentToken(tkParent);
808 break;
809
810 case mdtProperty:
811 IfFailGo( pMiniMd->FindParentOfPropertyHelper(tk, &tkParent) );
812 *pbGlobal = IsGlobalMethodParentToken(tkParent);
813 break;
814
815 case mdtEvent:
816 IfFailGo( pMiniMd->FindParentOfEventHelper(tk, &tkParent) );
817 *pbGlobal = IsGlobalMethodParentToken(tkParent);
818 break;
819
820 // Anything else is NOT global.
821 default:
822 *pbGlobal = FALSE;
823 }
824
825ErrExit:
826 //STOP_MD_PERF(GetModuleFromScope);
827 END_ENTRYPOINT_NOTHROW;
828
829 return hr;
830} // HRESULT RegMeta::IsGlobal()
831
832//*****************************************************************************
833// return flags for a given class
834//*****************************************************************************
835HRESULT
836RegMeta::GetTypeDefProps(
837 mdTypeDef td, // [IN] TypeDef token for inquiry.
838 __out_ecount_opt (cchTypeDef) LPWSTR szTypeDef, // [OUT] Put name here.
839 ULONG cchTypeDef, // [IN] size of name buffer in wide chars.
840 ULONG *pchTypeDef, // [OUT] put size of name (wide chars) here.
841 DWORD *pdwTypeDefFlags, // [OUT] Put flags here.
842 mdToken *ptkExtends) // [OUT] Put base class TypeDef/TypeRef here.
843{
844 HRESULT hr = S_OK;
845
846 BEGIN_ENTRYPOINT_NOTHROW;
847
848 CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
849 TypeDefRec *pTypeDefRec;
850 BOOL fTruncation = FALSE; // Was there name truncation?
851
852 LOG((LOGMD, "{%08x} RegMeta::GetTypeDefProps(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
853 this, td, szTypeDef, cchTypeDef, pchTypeDef,
854 pdwTypeDefFlags, ptkExtends));
855 START_MD_PERF();
856 LOCKREAD();
857
858 if (TypeFromToken(td) != mdtTypeDef)
859 {
860 hr = S_FALSE;
861 goto ErrExit;
862 }
863 if (td == mdTypeDefNil)
864 { // Backward compatibility with CLR 2.0 implementation
865 if (pdwTypeDefFlags != NULL)
866 *pdwTypeDefFlags = 0;
867 if (ptkExtends != NULL)
868 *ptkExtends = mdTypeRefNil;
869 if (pchTypeDef != NULL)
870 *pchTypeDef = 1;
871 if ((szTypeDef != NULL) && (cchTypeDef > 0))
872 szTypeDef[0] = 0;
873
874 hr = S_OK;
875 goto ErrExit;
876 }
877
878 IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(td), &pTypeDefRec));
879
880 if ((szTypeDef != NULL) || (pchTypeDef != NULL))
881 {
882 LPCSTR szNamespace;
883 LPCSTR szName;
884
885 IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeDefRec, &szNamespace));
886 MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzNamespace, szNamespace);
887 IfNullGo(wzNamespace);
888
889 IfFailGo(pMiniMd->getNameOfTypeDef(pTypeDefRec, &szName));
890 MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzName, szName);
891 IfNullGo(wzName);
892
893 if (szTypeDef != NULL)
894 {
895 fTruncation = !(ns::MakePath(szTypeDef, cchTypeDef, wzNamespace, wzName));
896 }
897 if (pchTypeDef != NULL)
898 {
899 if (fTruncation || (szTypeDef == NULL))
900 {
901 *pchTypeDef = ns::GetFullLength(wzNamespace, wzName);
902 }
903 else
904 {
905 *pchTypeDef = (ULONG)(wcslen(szTypeDef) + 1);
906 }
907 }
908 }
909 if (pdwTypeDefFlags != NULL)
910 { // caller wants type flags
911 *pdwTypeDefFlags = pMiniMd->getFlagsOfTypeDef(pTypeDefRec);
912 }
913 if (ptkExtends != NULL)
914 {
915 *ptkExtends = pMiniMd->getExtendsOfTypeDef(pTypeDefRec);
916
917 // take care of the 0 case
918 if (RidFromToken(*ptkExtends) == 0)
919 {
920 *ptkExtends = mdTypeRefNil;
921 }
922 }
923
924 if (fTruncation && (hr == S_OK))
925 {
926 if ((szTypeDef != NULL) && (cchTypeDef > 0))
927 { // null-terminate the truncated output string
928 szTypeDef[cchTypeDef - 1] = W('\0');
929 }
930 hr = CLDB_S_TRUNCATION;
931 }
932
933ErrExit:
934 END_ENTRYPOINT_NOTHROW;
935
936 STOP_MD_PERF(GetTypeDefProps);
937
938 return hr;
939} // RegMeta::GetTypeDefProps
940
941//*****************************************************************************
942// Retrieve information about an implemented interface.
943//*****************************************************************************
944STDMETHODIMP RegMeta::GetInterfaceImplProps( // S_OK or error.
945 mdInterfaceImpl iiImpl, // [IN] InterfaceImpl token.
946 mdTypeDef *pClass, // [OUT] Put implementing class token here.
947 mdToken *ptkIface) // [OUT] Put implemented interface token here.
948{
949 HRESULT hr = S_OK;
950
951 BEGIN_ENTRYPOINT_NOTHROW;
952
953 CMiniMdRW *pMiniMd = NULL;
954 InterfaceImplRec *pIIRec = NULL;
955
956
957
958 LOG((LOGMD, "RegMeta::GetInterfaceImplProps(0x%08x, 0x%08x, 0x%08x)\n",
959 iiImpl, pClass, ptkIface));
960 START_MD_PERF();
961 LOCKREAD();
962
963 _ASSERTE(TypeFromToken(iiImpl) == mdtInterfaceImpl);
964
965 pMiniMd = &(m_pStgdb->m_MiniMd);
966 IfFailGo(pMiniMd->GetInterfaceImplRecord(RidFromToken(iiImpl), &pIIRec));
967
968 if (pClass)
969 {
970 *pClass = pMiniMd->getClassOfInterfaceImpl(pIIRec);
971 }
972 if (ptkIface)
973 {
974 *ptkIface = pMiniMd->getInterfaceOfInterfaceImpl(pIIRec);
975 }
976
977ErrExit:
978 STOP_MD_PERF(GetInterfaceImplProps);
979 END_ENTRYPOINT_NOTHROW;
980
981 return hr;
982} // STDMETHODIMP RegMeta::GetInterfaceImplProps()
983
984//*****************************************************************************
985// Retrieve information about a TypeRef.
986//*****************************************************************************
987STDMETHODIMP
988RegMeta::GetTypeRefProps(
989 mdTypeRef tr, // The class ref token.
990 mdToken *ptkResolutionScope, // Resolution scope, ModuleRef or AssemblyRef.
991 __out_ecount_opt (cchTypeRef) LPWSTR szTypeRef, // Put the name here.
992 ULONG cchTypeRef, // Size of the name buffer, wide chars.
993 ULONG *pchTypeRef) // Put actual size of name here.
994{
995 HRESULT hr = S_OK;
996
997 BEGIN_ENTRYPOINT_NOTHROW;
998
999 CMiniMdRW *pMiniMd;
1000 TypeRefRec *pTypeRefRec;
1001 BOOL fTruncation = FALSE; // Was there name truncation?
1002
1003 LOG((LOGMD, "RegMeta::GetTypeRefProps(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
1004 tr, ptkResolutionScope, szTypeRef, cchTypeRef, pchTypeRef));
1005
1006 START_MD_PERF();
1007 LOCKREAD();
1008
1009 if (TypeFromToken(tr) != mdtTypeRef)
1010 {
1011 hr = S_FALSE;
1012 goto ErrExit;
1013 }
1014 if (tr == mdTypeRefNil)
1015 { // Backward compatibility with CLR 2.0 implementation
1016 if (ptkResolutionScope != NULL)
1017 *ptkResolutionScope = mdTokenNil;
1018 if (pchTypeRef != NULL)
1019 *pchTypeRef = 1;
1020 if ((szTypeRef != NULL) && (cchTypeRef > 0))
1021 szTypeRef[0] = 0;
1022
1023 hr = S_OK;
1024 goto ErrExit;
1025 }
1026
1027 pMiniMd = &(m_pStgdb->m_MiniMd);
1028 IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tr), &pTypeRefRec));
1029
1030 if (ptkResolutionScope != NULL)
1031 {
1032 *ptkResolutionScope = pMiniMd->getResolutionScopeOfTypeRef(pTypeRefRec);
1033 }
1034
1035 if ((szTypeRef != NULL) || (pchTypeRef != NULL))
1036 {
1037 LPCSTR szNamespace;
1038 LPCSTR szName;
1039
1040 IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szNamespace));
1041 MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzNamespace, szNamespace);
1042 IfNullGo(wzNamespace);
1043
1044 IfFailGo(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szName));
1045 MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzName, szName);
1046 IfNullGo(wzName);
1047
1048 if (szTypeRef != NULL)
1049 {
1050 fTruncation = !(ns::MakePath(szTypeRef, cchTypeRef, wzNamespace, wzName));
1051 }
1052 if (pchTypeRef != NULL)
1053 {
1054 if (fTruncation || (szTypeRef == NULL))
1055 {
1056 *pchTypeRef = ns::GetFullLength(wzNamespace, wzName);
1057 }
1058 else
1059 {
1060 *pchTypeRef = (ULONG)(wcslen(szTypeRef) + 1);
1061 }
1062 }
1063 }
1064 if (fTruncation && (hr == S_OK))
1065 {
1066 if ((szTypeRef != NULL) && (cchTypeRef > 0))
1067 { // null-terminate the truncated output string
1068 szTypeRef[cchTypeRef - 1] = W('\0');
1069 }
1070 hr = CLDB_S_TRUNCATION;
1071 }
1072
1073ErrExit:
1074 STOP_MD_PERF(GetTypeRefProps);
1075 END_ENTRYPOINT_NOTHROW;
1076 return hr;
1077} // RegMeta::GetTypeRefProps
1078
1079//*****************************************************************************
1080// Given a TypeRef name, return the typeref
1081//*****************************************************************************
1082STDMETHODIMP RegMeta::FindTypeRef( // S_OK or error.
1083 mdToken tkResolutionScope, // [IN] Resolution Scope.
1084 LPCWSTR wzTypeName, // [IN] Name of the TypeRef.
1085 mdTypeRef *ptk) // [OUT] Put the TypeRef token here.
1086{
1087 HRESULT hr = S_OK; // A result.
1088
1089 BEGIN_ENTRYPOINT_NOTHROW;
1090
1091 LPUTF8 szFullName;
1092 LPCUTF8 szNamespace;
1093 LPCUTF8 szName;
1094 CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
1095
1096 _ASSERTE(wzTypeName && ptk);
1097
1098
1099
1100 LOG((LOGMD, "RegMeta::FindTypeRef(0x%8x, %ls, 0x%08x)\n",
1101 tkResolutionScope, MDSTR(wzTypeName), ptk));
1102 START_MD_PERF();
1103 LOCKREAD();
1104
1105 // Convert the name to UTF8.
1106 PREFIX_ASSUME(wzTypeName != NULL); // caller might pass NULL, but they'll AV.
1107 UTF8STR(wzTypeName, szFullName);
1108 ns::SplitInline(szFullName, szNamespace, szName);
1109
1110 // Look up the name.
1111 hr = ImportHelper::FindTypeRefByName(pMiniMd, tkResolutionScope,
1112 szNamespace,
1113 szName,
1114 ptk);
1115ErrExit:
1116
1117 STOP_MD_PERF(FindTypeRef);
1118 END_ENTRYPOINT_NOTHROW;
1119
1120 return hr;
1121} // STDMETHODIMP RegMeta::FindTypeRef()
1122
1123//*******************************************************************************
1124// Find a given param of a Method.
1125//*******************************************************************************
1126HRESULT RegMeta::_FindParamOfMethod( // S_OK or error.
1127 mdMethodDef md, // [IN] The owning method of the param.
1128 ULONG iSeq, // [IN] The sequence # of the param.
1129 mdParamDef *pParamDef) // [OUT] Put ParamDef token here.
1130{
1131 HRESULT hr;
1132 ParamRec *pParamRec;
1133 RID ridStart, ridEnd;
1134 RID pmRid;
1135
1136 _ASSERTE(TypeFromToken(md) == mdtMethodDef && pParamDef);
1137
1138 // get the methoddef record
1139 MethodRec *pMethodRec;
1140 IfFailRet(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(md), &pMethodRec));
1141
1142 // figure out the start rid and end rid of the parameter list of this methoddef
1143 ridStart = m_pStgdb->m_MiniMd.getParamListOfMethod(pMethodRec);
1144 IfFailRet(m_pStgdb->m_MiniMd.getEndParamListOfMethod(RidFromToken(md), &ridEnd));
1145
1146 // loop through each param
1147 // <TODO>@consider: parameters are sorted by sequence. Maybe a binary search?
1148 //</TODO>
1149 for (; ridStart < ridEnd; ridStart++)
1150 {
1151 IfFailRet(m_pStgdb->m_MiniMd.GetParamRid(ridStart, &pmRid));
1152 IfFailRet(m_pStgdb->m_MiniMd.GetParamRecord(pmRid, &pParamRec));
1153 if (iSeq == m_pStgdb->m_MiniMd.getSequenceOfParam(pParamRec))
1154 {
1155 // parameter has the sequence number matches what we are looking for
1156 *pParamDef = TokenFromRid(pmRid, mdtParamDef);
1157 return S_OK;
1158 }
1159 }
1160 return CLDB_E_RECORD_NOTFOUND;
1161} // HRESULT RegMeta::_FindParamOfMethod()
1162
1163//*******************************************************************************
1164// Given the signature, return the token for signature.
1165//*******************************************************************************
1166HRESULT RegMeta::_GetTokenFromSig( // S_OK or error.
1167 PCCOR_SIGNATURE pvSig, // [IN] Signature to define.
1168 ULONG cbSig, // [IN] Size of signature data.
1169 mdSignature *pmsig) // [OUT] returned signature token.
1170{
1171 HRESULT hr = S_OK;
1172
1173 _ASSERTE(pmsig);
1174
1175 if (CheckDups(MDDupSignature))
1176 {
1177 hr = ImportHelper::FindStandAloneSig(&(m_pStgdb->m_MiniMd), pvSig, cbSig, pmsig);
1178 if (SUCCEEDED(hr))
1179 {
1180 if (IsENCOn())
1181 return S_OK;
1182 else
1183 return META_S_DUPLICATE;
1184 }
1185 else if (hr != CLDB_E_RECORD_NOTFOUND)
1186 IfFailGo(hr);
1187 }
1188
1189 // Create a new record.
1190 StandAloneSigRec *pSigRec;
1191 RID iSigRec;
1192
1193 IfFailGo(m_pStgdb->m_MiniMd.AddStandAloneSigRecord(&pSigRec, &iSigRec));
1194
1195 // Set output parameter.
1196 *pmsig = TokenFromRid(iSigRec, mdtSignature);
1197
1198 // Save signature.
1199 IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_StandAloneSig, StandAloneSigRec::COL_Signature,
1200 pSigRec, pvSig, cbSig));
1201 IfFailGo(UpdateENCLog(*pmsig));
1202ErrExit:
1203 return hr;
1204} // RegMeta::_GetTokenFromSig
1205