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// MDUtil.cpp
6//
7
8//
9// contains utility code to MD directory. This is only used for the full version.
10//
11//*****************************************************************************
12#include "stdafx.h"
13#include "metadata.h"
14#include "mdutil.h"
15#include "regmeta.h"
16#include "disp.h"
17#include "mdcommon.h"
18#include "importhelper.h"
19#include "sstring.h"
20
21#include <rwutil.h>
22
23#if defined(FEATURE_METADATA_IN_VM)
24
25LOADEDMODULES * LOADEDMODULES::s_pLoadedModules = NULL;
26UTSemReadWrite * LOADEDMODULES::m_pSemReadWrite = NULL;
27RegMeta * (LOADEDMODULES::m_HashedModules[LOADEDMODULES_HASH_SIZE]) = { NULL };
28
29//*****************************************************************************
30// Hash a file name.
31//*****************************************************************************
32ULONG LOADEDMODULES::HashFileName(
33 LPCWSTR szName)
34{
35 return HashString(szName) % LOADEDMODULES_HASH_SIZE;
36} // LOADEDMODULES::HashFileName
37
38//---------------------------------------------------------------------------------------
39//
40// Initialize the static instance and lock.
41//
42HRESULT
43LOADEDMODULES::InitializeStatics()
44{
45 HRESULT hr = S_OK;
46
47 if (VolatileLoad(&s_pLoadedModules) == NULL)
48 {
49 // Initialize global read-write lock
50 {
51 NewHolder<UTSemReadWrite> pSemReadWrite = new (nothrow) UTSemReadWrite();
52 IfNullGo(pSemReadWrite);
53 IfFailGo(pSemReadWrite->Init());
54
55 if (InterlockedCompareExchangeT<UTSemReadWrite *>(&m_pSemReadWrite, pSemReadWrite, NULL) == NULL)
56 { // We won the initialization race
57 pSemReadWrite.SuppressRelease();
58 }
59 }
60
61 // Initialize the global instance
62 {
63 NewHolder<LOADEDMODULES> pLoadedModules = new (nothrow) LOADEDMODULES();
64 IfNullGo(pLoadedModules);
65
66 {
67 LOCKWRITE();
68
69 if (VolatileLoad(&s_pLoadedModules) == NULL)
70 {
71 VolatileStore(&s_pLoadedModules, pLoadedModules.Extract());
72 }
73 }
74 }
75 }
76
77ErrExit:
78 return hr;
79} // LOADEDMODULES::InitializeStatics
80
81//---------------------------------------------------------------------------------------
82//
83// Destroy the static instance and lock.
84//
85void
86LOADEDMODULES::DeleteStatics()
87{
88 HRESULT hr = S_OK;
89
90 if (s_pLoadedModules != NULL)
91 {
92 delete s_pLoadedModules;
93 s_pLoadedModules = NULL;
94 }
95 if (m_pSemReadWrite != NULL)
96 {
97 delete m_pSemReadWrite;
98 m_pSemReadWrite = NULL;
99 }
100} // LOADEDMODULES::DeleteStatics
101
102//*****************************************************************************
103// Add a RegMeta pointer to the loaded module list
104//*****************************************************************************
105HRESULT LOADEDMODULES::AddModuleToLoadedList(RegMeta * pRegMeta)
106{
107 HRESULT hr = NOERROR;
108 RegMeta ** ppRegMeta;
109
110 IfFailGo(InitializeStatics());
111
112 {
113 LOCKWRITE();
114
115 ppRegMeta = s_pLoadedModules->Append();
116 IfNullGo(ppRegMeta);
117
118 // The cache holds a copy of the pointer, but no ref-count. There is no
119 // point to the ref-count, because it just changes comparisons against 0
120 // to comparisons against 1.
121 *ppRegMeta = pRegMeta;
122
123 // If the module is read-only, hash it.
124 if (pRegMeta->IsReadOnly())
125 {
126 ULONG ixHash = HashFileName(pRegMeta->GetNameOfDBFile());
127 m_HashedModules[ixHash] = pRegMeta;
128 }
129 }
130
131ErrExit:
132 return hr;
133} // LOADEDMODULES::AddModuleToLoadedList
134
135//*****************************************************************************
136// Remove a RegMeta pointer from the loaded module list
137//*****************************************************************************
138BOOL LOADEDMODULES::RemoveModuleFromLoadedList(RegMeta * pRegMeta)
139{
140 BOOL bRemoved = FALSE; // Was this module removed from the cache?
141 int iFound = -1; // Index at which it was found.
142 ULONG cRef; // Ref count of the module.
143
144 // Lock the cache for write, so that no other thread will find what this
145 // thread is about to delete, and so that no other thread will delete
146 // what this thread is about to try to find.
147 HRESULT hr = S_OK;
148
149 IfFailGo(InitializeStatics());
150
151 {
152 LOCKWRITE();
153
154 // Search for this module in list of loaded modules.
155 int count = s_pLoadedModules->Count();
156 for (int index = 0; index < count; index++)
157 {
158 if ((*s_pLoadedModules)[index] == pRegMeta)
159 { // found a match to remove
160 iFound = index;
161 break;
162 }
163 }
164
165 // If the module is still in the cache, it hasn't been deleted yet.
166 if (iFound >= 0)
167 {
168 // See if there are any external references left.
169 cRef = pRegMeta->GetRefCount();
170
171 // If the cRef that we got from the module is zero, it will stay that way,
172 // because no other thread can discover the module while this thread holds
173 // the lock.
174
175 // OTOH, if the cRef is not zero, this thread can just return, because the
176 // other thread will eventually take the ref count to zero, and will then
177 // come through here to clean up the module. And this thread must not
178 // delete the module out from under other threads.
179
180 // It is possible that the cRef is zero, yet another thread has a pointer that
181 // it discovered before this thread took the lock. (And that thread has
182 // released the ref-counts.) In such a case, this thread can still remove the
183 // module from the cache, and tell the caller to delete it, because the
184 // other thread will wait on the lock, then discover that the module
185 // is not in the cache, and it won't try to delete the module.
186
187 if (cRef != 0)
188 { // Some other thread snuck in and found the entry in the cache.
189 return FALSE;
190 }
191
192 // No other thread owns the object. Remove from cache, and tell caller
193 // that we're done with it. (Caller will delete.)
194 s_pLoadedModules->Delete(iFound);
195 bRemoved = TRUE;
196
197 // If the module is read-only, remove from hash.
198 if (pRegMeta->IsReadOnly())
199 {
200 // There may have been multiple capitalizations pointing to the same entry.
201 // Find and remove all of them.
202 for (ULONG ixHash = 0; ixHash < LOADEDMODULES_HASH_SIZE; ++ixHash)
203 {
204 if (m_HashedModules[ixHash] == pRegMeta)
205 m_HashedModules[ixHash] = NULL;
206 }
207 }
208 }
209 }
210
211ErrExit:
212 return bRemoved;
213} // LOADEDMODULES::RemoveModuleFromLoadedList
214
215
216//*****************************************************************************
217// Search the cached RegMetas for a given scope.
218//*****************************************************************************
219HRESULT LOADEDMODULES::FindCachedReadOnlyEntry(
220 LPCWSTR szName, // Name of the desired file.
221 DWORD dwOpenFlags, // Flags the new file is opened with.
222 RegMeta ** ppMeta) // Put found RegMeta here.
223{
224 RegMeta * pRegMeta = 0;
225 BOOL bWillBeCopyMemory; // Will the opened file be copied to memory?
226 DWORD dwLowFileSize; // Low bytes of this file's size
227 DWORD dwLowFileTime; // Low butes of this file's last write time
228 HRESULT hr;
229 ULONG ixHash = 0;
230
231 IfFailGo(InitializeStatics());
232
233 {
234 LOCKREAD();
235
236 hr = S_FALSE; // We haven't found a match yet.
237
238 // Avoid confusion.
239 *ppMeta = NULL;
240
241 bWillBeCopyMemory = IsOfCopyMemory(dwOpenFlags);
242
243 // The cache is locked for read, so the list will not change.
244
245 // Figure out the size and timestamp of this file
246 WIN32_FILE_ATTRIBUTE_DATA faData;
247 if (!WszGetFileAttributesEx(szName, GetFileExInfoStandard, &faData))
248 return E_FAIL;
249 dwLowFileSize = faData.nFileSizeLow;
250 dwLowFileTime = faData.ftLastWriteTime.dwLowDateTime;
251
252 // Check the hash first.
253 ixHash = HashFileName(szName);
254 if ((pRegMeta = m_HashedModules[ixHash]) != NULL)
255 {
256 _ASSERTE(pRegMeta->IsReadOnly());
257
258 // Only match if the IsOfCopyMemory() bit is the same in both. This is because
259 // when ofCopyMemory is set, the file is not locked on disk, and may become stale
260 // in memory.
261 //
262 // Also, only match if the date and size are the same
263 if (pRegMeta->IsCopyMemory() == bWillBeCopyMemory &&
264 pRegMeta->GetLowFileTimeOfDBFile() == dwLowFileTime &&
265 pRegMeta->GetLowFileSizeOfDBFile() == dwLowFileSize)
266 {
267 // If the name matches...
268 LPCWSTR pszName = pRegMeta->GetNameOfDBFile();
269 #ifdef FEATURE_CASE_SENSITIVE_FILESYSTEM
270 if (wcscmp(szName, pszName) == 0)
271 #else
272 if (SString::_wcsicmp(szName, pszName) == 0)
273 #endif
274 {
275 ULONG cRefs;
276
277 // Found it. Add a reference, and return it.
278 *ppMeta = pRegMeta;
279 cRefs = pRegMeta->AddRef();
280
281 LOG((LF_METADATA, LL_INFO10, "Disp::OpenScope found cached RegMeta in hash: %#8x, crefs: %d\n", pRegMeta, cRefs));
282
283 return S_OK;
284 }
285 }
286 }
287
288 // Not found in hash; loop through each loaded modules
289 int count = s_pLoadedModules->Count();
290 for (int index = 0; index < count; index++)
291 {
292 pRegMeta = (*s_pLoadedModules)[index];
293
294 // If the module is read-only, and the CopyMemory bit matches, and the date
295 // and size are the same....
296 if (pRegMeta->IsReadOnly() &&
297 pRegMeta->IsCopyMemory() == bWillBeCopyMemory &&
298 pRegMeta->GetLowFileTimeOfDBFile() == dwLowFileTime &&
299 pRegMeta->GetLowFileSizeOfDBFile() == dwLowFileSize)
300 {
301 // If the name matches...
302 LPCWSTR pszName = pRegMeta->GetNameOfDBFile();
303 #ifdef FEATURE_CASE_SENSITIVE_FILESYSTEM
304 if (wcscmp(szName, pszName) == 0)
305 #else
306 if (SString::_wcsicmp(szName, pszName) == 0)
307 #endif
308 {
309 ULONG cRefs;
310
311 // Found it. Add a reference, and return it.
312 *ppMeta = pRegMeta;
313 cRefs = pRegMeta->AddRef();
314
315 // Update the hash.
316 m_HashedModules[ixHash] = pRegMeta;
317
318 LOG((LF_METADATA, LL_INFO10, "Disp::OpenScope found cached RegMeta by search: %#8x, crefs: %d\n", pRegMeta, cRefs));
319
320 return S_OK;
321 }
322 }
323 }
324 }
325
326ErrExit:
327 // Didn't find it.
328 LOG((LF_METADATA, LL_INFO10, "Disp::OpenScope did not find cached RegMeta\n"));
329
330 _ASSERTE(hr != S_OK);
331 return hr;
332} // LOADEDMODULES::FindCachedReadOnlyEntry
333
334#ifdef _DEBUG
335
336//*****************************************************************************
337// Search the cached RegMetas for a given scope.
338//*****************************************************************************
339BOOL LOADEDMODULES::IsEntryInList(
340 RegMeta * pRegMeta)
341{
342 HRESULT hr = S_OK;
343
344 IfFailGo(InitializeStatics());
345
346 {
347 LOCKREAD();
348
349 // Loop through each loaded modules
350 int count = s_pLoadedModules->Count();
351 for (int index = 0; index < count; index++)
352 {
353 if ((*s_pLoadedModules)[index] == pRegMeta)
354 {
355 return TRUE;
356 }
357 }
358 }
359
360ErrExit:
361 return FALSE;
362} // LOADEDMODULES::IsEntryInList
363
364#endif //_DEBUG
365
366#endif //FEATURE_METADATA_IN_VM
367
368#ifdef FEATURE_METADATA_IN_VM
369
370//*****************************************************************************
371// Remove a RegMeta pointer from the loaded module list
372//*****************************************************************************
373// static
374HRESULT
375LOADEDMODULES::ResolveTypeRefWithLoadedModules(
376 mdTypeRef tkTypeRef, // [IN] TypeRef to be resolved.
377 RegMeta * pTypeRefRegMeta, // [IN] Scope in which the TypeRef is defined.
378 IMetaModelCommon * pTypeRefScope, // [IN] Scope in which the TypeRef is defined.
379 REFIID riid, // [IN] iid for the return interface.
380 IUnknown ** ppIScope, // [OUT] Return interface.
381 mdTypeDef * ptd) // [OUT] TypeDef corresponding the TypeRef.
382{
383 HRESULT hr = NOERROR;
384 RegMeta * pRegMeta;
385 CQuickArray<mdTypeRef> cqaNesters;
386 CQuickArray<LPCUTF8> cqaNesterNamespaces;
387 CQuickArray<LPCUTF8> cqaNesterNames;
388
389 IfFailGo(InitializeStatics());
390
391 {
392 LOCKREAD();
393
394 // Get the Nesting hierarchy.
395 IfFailGo(ImportHelper::GetNesterHierarchy(
396 pTypeRefScope,
397 tkTypeRef,
398 cqaNesters,
399 cqaNesterNamespaces,
400 cqaNesterNames));
401
402 int count = s_pLoadedModules->Count();
403 for (int index = 0; index < count; index++)
404 {
405 pRegMeta = (*s_pLoadedModules)[index];
406
407 {
408 // Do not lock the TypeRef RegMeta (again), as it is already locked for read by the caller.
409 // The code:UTSemReadWrite will block ReadLock even for thread holding already the read lock if
410 // some other thread is waiting for WriteLock on the same lock. That would cause dead-lock if we
411 // try to lock for read again here.
412 CMDSemReadWrite cSemRegMeta((pRegMeta == pTypeRefRegMeta) ? NULL : pRegMeta->GetReaderWriterLock());
413 IfFailGo(cSemRegMeta.LockRead());
414
415 hr = ImportHelper::FindNestedTypeDef(
416 pRegMeta->GetMiniMd(),
417 cqaNesterNamespaces,
418 cqaNesterNames,
419 mdTokenNil,
420 ptd);
421 }
422 if (hr == CLDB_E_RECORD_NOTFOUND)
423 { // Process next MetaData module
424 continue;
425 }
426 IfFailGo(hr);
427
428 // Found a loaded module containing the TypeDef.
429 IfFailGo(pRegMeta->QueryInterface(riid, (void **)ppIScope));
430 break;
431 }
432 }
433 if (FAILED(hr))
434 {
435 // cannot find the match!
436 hr = E_FAIL;
437 }
438ErrExit:
439 return hr;
440} // LOADEDMODULES::ResolveTypeRefWithLoadedModules
441
442#endif //FEATURE_METADATA_IN_VM
443
444#if defined(FEATURE_METADATA_IN_VM)
445
446//*****************************************************************************
447// This is a routine to try to find a class implementation given its fully
448// qualified name by using the CORPATH environment variable. CORPATH is a list
449// of directories (like PATH). Before checking CORPATH, this checks the current
450// directory, then the directory that the exe lives in. The search is
451// performed by parsing off one element at a time from the class name,
452// appending it to the directory and looking for a subdirectory or image with
453// that name. If the subdirectory exists, it drills down into that subdirectory
454// and tries the next element of the class name. When it finally bottoms out
455// but can't find the image it takes the rest of the fully qualified class name
456// and appends them with intervening '.'s trying to find a matching DLL.
457// Example:
458//
459// CORPATH=c:\bin;c:\prog
460// classname = namespace.class
461//
462// checks the following things in order:
463// c:\bin\namespace, (if <-exists) c:\bin\namespace\class.dll,
464// c:\bin\namespace.dll, c:\bin\namespace.class.dll
465// c:\prog\namespace, (if <-exists) c:\prog\namespace\class.dll,
466// c:\prog\namespace.dll, c:\prog\namespace.class.dll
467//*****************************************************************************
468HRESULT CORPATHService::GetClassFromCORPath(
469 __in __in_z LPWSTR wzClassname, // [IN] fully qualified class name
470 mdTypeRef tr, // [IN] TypeRef to be resolved.
471 IMetaModelCommon *pCommon, // [IN] Scope in which the TypeRef is defined.
472 REFIID riid, // [IN] Interface type to be returned.
473 IUnknown **ppIScope, // [OUT] Scope in which the TypeRef resolves.
474 mdTypeDef *ptd) // [OUT] typedef corresponding the typeref
475{
476 PathString rcCorPath; // The CORPATH environment variable.
477 LPWSTR szCorPath; // Used to parse CORPATH.
478 int iLen; // Length of the directory.
479 PathString rcCorDir; // Buffer for the directory.
480 WCHAR *temp; // Used as a parsing temp.
481 WCHAR *szSemiCol;
482
483 // Get the CORPATH environment variable.
484 if (WszGetEnvironmentVariable(W("CORPATH"), rcCorPath))
485 {
486 NewArrayHolder<WCHAR> szCorPathHolder = rcCorPath.GetCopyOfUnicodeString();
487 szCorPath = szCorPathHolder.GetValue();
488 // Try each directory in the path.
489 for(;*szCorPath != W('\0');)
490 {
491 // Get the next directory off the path.
492 if ((szSemiCol = wcschr(szCorPath, W(';'))))
493 {
494 temp = szCorPath;
495 *szSemiCol = W('\0');
496 szCorPath = szSemiCol + 1;
497 }
498 else
499 {
500 temp = szCorPath;
501 szCorPath += wcslen(temp);
502 }
503
504 rcCorDir.Set(temp);
505
506 // Check if we can find the class in the directory.
507 if (CORPATHService::GetClassFromDir(wzClassname, rcCorDir, tr, pCommon, riid, ppIScope, ptd) == S_OK)
508 return S_OK;
509 }
510 }
511
512 //<TODO>These should go before the path search, but it will cause test
513 // some headaches right now, so we'll give them a little time to transition.</TODO>
514
515 // Try the current directory first.
516 if ((iLen = WszGetCurrentDirectory( rcCorDir)) > 0 &&
517 CORPATHService::GetClassFromDir(wzClassname, rcCorDir, tr, pCommon, riid, ppIScope, ptd) == S_OK)
518 {
519 return S_OK;
520 }
521
522 // Try the app directory next.
523 if ((iLen = WszGetModuleFileName(NULL, rcCorDir)) > 0)
524 {
525
526 if(SUCCEEDED(CopySystemDirectory(rcCorDir, rcCorDir)) &&
527 CORPATHService::GetClassFromDir(
528 wzClassname,
529 rcCorDir,
530 tr,
531 pCommon,
532 riid,
533 ppIScope,
534 ptd) == S_OK)
535 {
536 return (S_OK);
537 }
538 }
539
540 // Couldn't find the class.
541 return S_FALSE;
542} // CORPATHService::GetClassFromCORPath
543
544//*****************************************************************************
545// This is used in conjunction with GetClassFromCORPath. See it for details
546// of the algorithm.
547//*****************************************************************************
548HRESULT CORPATHService::GetClassFromDir(
549 __in __in_z LPWSTR wzClassname, // Fully qualified class name.
550 __in SString& directory, // Directory to try. at most appended with a '\\'
551 mdTypeRef tr, // TypeRef to resolve.
552 IMetaModelCommon *pCommon, // Scope in which the TypeRef is defined.
553 REFIID riid,
554 IUnknown **ppIScope,
555 mdTypeDef *ptd) // [OUT] typedef
556{
557 WCHAR *temp; // Used as a parsing temp.
558 int iTmp;
559 bool bContinue; // Flag to check if the for loop should end.
560 LPWSTR wzSaveClassname = NULL; // Saved offset into the class name string.
561
562 // Process the class name appending each segment of the name to the
563 // directory until we find a DLL.
564 PathString dir;
565 if (!directory.EndsWith(DIRECTORY_SEPARATOR_CHAR_W))
566 {
567 directory.Append(DIRECTORY_SEPARATOR_CHAR_W);
568 }
569
570 for(;;)
571 {
572 bContinue = false;
573 dir.Set(directory);
574
575 if ((temp = wcschr(wzClassname, NAMESPACE_SEPARATOR_WCHAR)) != NULL)
576 {
577 *temp = W('\0'); //terminate with null so that it can be appended
578 dir.Append(wzClassname);
579 *temp = NAMESPACE_SEPARATOR_WCHAR; //recover the '.'
580
581 wzClassname = temp+1;
582 // Check if a directory by this name exists.
583 DWORD iAttrs = WszGetFileAttributes(dir);
584 if (iAttrs != 0xffffffff && (iAttrs & FILE_ATTRIBUTE_DIRECTORY))
585 {
586 // Next element in the class spec.
587 bContinue = true;
588 wzSaveClassname = wzClassname;
589 }
590 }
591 else
592 {
593 dir.Append(wzClassname);
594
595 // Advance past the class name.
596 iTmp = (int)wcslen(wzClassname);
597 wzClassname += iTmp;
598 }
599
600 // Try to load the image.
601 dir.Append(W(".dll"));
602
603 // OpenScope given the dll name and make sure that the class is defined in the module.
604 if ( SUCCEEDED( CORPATHService::FindTypeDef(dir, tr, pCommon, riid, ppIScope, ptd) ) )
605 {
606 return (S_OK);
607 }
608
609 // If we didn't find the dll, try some more.
610 while (*wzClassname != W('\0'))
611 {
612 // Find the length of the next class name element.
613 if ((temp = wcschr(wzClassname, NAMESPACE_SEPARATOR_WCHAR)) == NULL)
614 {
615 temp = wzClassname + wcslen(wzClassname);
616 }
617
618 // Tack on ".element.dll"
619 SString::Iterator iter = dir.End();
620 BOOL findperiod = dir.FindBack(iter, NAMESPACE_SEPARATOR_WCHAR);
621 _ASSERTE(findperiod);
622 iter++;
623 dir.Truncate(iter);
624
625 WCHAR save = *temp;
626 *temp = W('\0');
627 dir.Append(wzClassname); //element
628 *temp = save;
629
630 // Try to load the image.
631 dir.Append(W(".dll"));
632
633 // OpenScope given the dll name and make sure that the class is defined in the module.
634 if ( SUCCEEDED( CORPATHService::FindTypeDef(dir, tr, pCommon, riid, ppIScope, ptd) ) )
635 {
636 return (S_OK);
637 }
638
639 // Advance to the next class name element.
640 wzClassname = temp;
641 if (*wzClassname != '\0')
642 ++wzClassname;
643 }
644 if (bContinue)
645 {
646
647 wzClassname = wzSaveClassname;
648 }
649 else
650 {
651 break;
652 }
653 }
654 return S_FALSE;
655} // CORPATHService::GetClassFromDir
656
657//*************************************************************
658//
659// Open the file with name wzModule and check to see if there is a type
660// with namespace/class of wzNamespace/wzType. If so, return the RegMeta
661// corresponding to the file and the mdTypeDef of the typedef
662//
663//*************************************************************
664HRESULT CORPATHService::FindTypeDef(
665 __in __in_z LPCWSTR wzModule, // name of the module that we are going to open
666 mdTypeRef tr, // TypeRef to resolve.
667 IMetaModelCommon * pCommon, // Scope in which the TypeRef is defined.
668 REFIID riid,
669 IUnknown ** ppIScope,
670 mdTypeDef * ptd) // [OUT] the type that we resolve to
671{
672 HRESULT hr = NOERROR;
673 NewHolder<Disp> pDisp;
674 ReleaseHolder<IMetaDataImport2> pImport = NULL;
675 CQuickArray<mdTypeRef> cqaNesters;
676 CQuickArray<LPCUTF8> cqaNesterNamespaces;
677 CQuickArray<LPCUTF8> cqaNesterNames;
678 RegMeta * pRegMeta;
679
680 _ASSERTE((ppIScope != NULL) && (ptd != NULL));
681
682 *ppIScope = NULL;
683
684 pDisp = new (nothrow) Disp;
685 IfNullGo(pDisp);
686
687 IfFailGo(pDisp->OpenScope(wzModule, 0, IID_IMetaDataImport2, (IUnknown **)&pImport));
688 pRegMeta = static_cast<RegMeta *>(pImport.GetValue());
689
690 // Get the Nesting hierarchy.
691 IfFailGo(ImportHelper::GetNesterHierarchy(pCommon, tr, cqaNesters,
692 cqaNesterNamespaces, cqaNesterNames));
693
694 hr = ImportHelper::FindNestedTypeDef(
695 pRegMeta->GetMiniMd(),
696 cqaNesterNamespaces,
697 cqaNesterNames,
698 mdTokenNil,
699 ptd);
700 if (SUCCEEDED(hr))
701 {
702 *ppIScope = pImport.Extract();
703 }
704
705ErrExit:
706 return hr;
707} // CORPATHService::FindTypeDef
708
709#endif //FEATURE_METADATA_IN_VM
710
711//*******************************************************************************
712//
713// Determine the blob size base of the ELEMENT_TYPE_* associated with the blob.
714// This cannot be a table lookup because ELEMENT_TYPE_STRING is an unicode string.
715// The size of the blob is determined by calling wcsstr of the string + 1.
716//
717//*******************************************************************************
718ULONG _GetSizeOfConstantBlob(
719 DWORD dwCPlusTypeFlag, // ELEMENT_TYPE_*
720 void * pValue, // BLOB value
721 ULONG cchString) // String length in wide chars, or -1 for auto.
722{
723 ULONG ulSize = 0;
724
725 switch (dwCPlusTypeFlag)
726 {
727 case ELEMENT_TYPE_BOOLEAN:
728 ulSize = sizeof(BYTE);
729 break;
730 case ELEMENT_TYPE_I1:
731 case ELEMENT_TYPE_U1:
732 ulSize = sizeof(BYTE);
733 break;
734 case ELEMENT_TYPE_CHAR:
735 case ELEMENT_TYPE_I2:
736 case ELEMENT_TYPE_U2:
737 ulSize = sizeof(SHORT);
738 break;
739 case ELEMENT_TYPE_I4:
740 case ELEMENT_TYPE_U4:
741 case ELEMENT_TYPE_R4:
742 ulSize = sizeof(LONG);
743
744 break;
745
746 case ELEMENT_TYPE_I8:
747 case ELEMENT_TYPE_U8:
748 case ELEMENT_TYPE_R8:
749 ulSize = sizeof(DOUBLE);
750 break;
751
752 case ELEMENT_TYPE_STRING:
753 if (pValue == 0)
754 ulSize = 0;
755 else
756 if (cchString != (ULONG) -1)
757 ulSize = cchString * sizeof(WCHAR);
758 else
759 ulSize = (ULONG)(sizeof(WCHAR) * wcslen((LPWSTR)pValue));
760 break;
761
762 case ELEMENT_TYPE_CLASS:
763 // This was originally 'sizeof(IUnknown *)', but that varies across platforms.
764 // The only legal value is a null pointer, and on 32 bit platforms we've already
765 // stored 32 bits, so we will use just 32 bits of null. If the type is
766 // E_T_CLASS, the caller should know that the value is always NULL anyway.
767 ulSize = sizeof(ULONG);
768 break;
769 default:
770 _ASSERTE(!"Not a valid type to specify default value!");
771 break;
772 }
773 return ulSize;
774} // _GetSizeOfConstantBlob
775