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 | |
25 | LOADEDMODULES * LOADEDMODULES::s_pLoadedModules = NULL; |
26 | UTSemReadWrite * LOADEDMODULES::m_pSemReadWrite = NULL; |
27 | RegMeta * (LOADEDMODULES::m_HashedModules[LOADEDMODULES_HASH_SIZE]) = { NULL }; |
28 | |
29 | //***************************************************************************** |
30 | // Hash a file name. |
31 | //***************************************************************************** |
32 | ULONG 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 | // |
42 | HRESULT |
43 | LOADEDMODULES::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 | |
77 | ErrExit: |
78 | return hr; |
79 | } // LOADEDMODULES::InitializeStatics |
80 | |
81 | //--------------------------------------------------------------------------------------- |
82 | // |
83 | // Destroy the static instance and lock. |
84 | // |
85 | void |
86 | LOADEDMODULES::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 | //***************************************************************************** |
105 | HRESULT 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 | |
131 | ErrExit: |
132 | return hr; |
133 | } // LOADEDMODULES::AddModuleToLoadedList |
134 | |
135 | //***************************************************************************** |
136 | // Remove a RegMeta pointer from the loaded module list |
137 | //***************************************************************************** |
138 | BOOL 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 | |
211 | ErrExit: |
212 | return bRemoved; |
213 | } // LOADEDMODULES::RemoveModuleFromLoadedList |
214 | |
215 | |
216 | //***************************************************************************** |
217 | // Search the cached RegMetas for a given scope. |
218 | //***************************************************************************** |
219 | HRESULT 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 | |
326 | ErrExit: |
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 | //***************************************************************************** |
339 | BOOL 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 | |
360 | ErrExit: |
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 |
374 | HRESULT |
375 | LOADEDMODULES::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 | } |
438 | ErrExit: |
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 | //***************************************************************************** |
468 | HRESULT 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 | //***************************************************************************** |
548 | HRESULT 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 | //************************************************************* |
664 | HRESULT 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 | |
705 | ErrExit: |
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 | //******************************************************************************* |
718 | ULONG _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 | |