| 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 | // Disp.cpp | 
|---|
| 6 | // | 
|---|
| 7 |  | 
|---|
| 8 | // | 
|---|
| 9 | // Implementation for the meta data dispenser code. | 
|---|
| 10 | // | 
|---|
| 11 | //***************************************************************************** | 
|---|
| 12 | #include "stdafx.h" | 
|---|
| 13 | #include "disp.h" | 
|---|
| 14 | #include "regmeta.h" | 
|---|
| 15 | #include "mdutil.h" | 
|---|
| 16 | #include <corerror.h> | 
|---|
| 17 | #include <mdlog.h> | 
|---|
| 18 | #include <mdcommon.h> | 
|---|
| 19 |  | 
|---|
| 20 | #ifdef EnC_SUPPORTED | 
|---|
| 21 | #define ENC_DELTA_HACK | 
|---|
| 22 | #endif | 
|---|
| 23 |  | 
|---|
| 24 | //***************************************************************************** | 
|---|
| 25 | // Ctor. | 
|---|
| 26 | //***************************************************************************** | 
|---|
| 27 | Disp::Disp() : m_cRef(0) | 
|---|
| 28 | { | 
|---|
| 29 | #if defined(LOGGING) | 
|---|
| 30 | // InitializeLogging() calls scattered around the code. | 
|---|
| 31 | // <TODO>@future: make this make some sense.</TODO> | 
|---|
| 32 | InitializeLogging(); | 
|---|
| 33 | #endif | 
|---|
| 34 |  | 
|---|
| 35 | m_OptionValue.m_DupCheck = MDDupDefault; | 
|---|
| 36 | m_OptionValue.m_RefToDefCheck = MDRefToDefDefault; | 
|---|
| 37 | m_OptionValue.m_NotifyRemap = MDNotifyDefault; | 
|---|
| 38 | m_OptionValue.m_UpdateMode = MDUpdateFull; | 
|---|
| 39 | m_OptionValue.m_ErrorIfEmitOutOfOrder = MDErrorOutOfOrderDefault; | 
|---|
| 40 | m_OptionValue.m_ThreadSafetyOptions = MDThreadSafetyDefault; | 
|---|
| 41 | m_OptionValue.m_GenerateTCEAdapters = FALSE; | 
|---|
| 42 | m_OptionValue.m_ImportOption = MDImportOptionDefault; | 
|---|
| 43 | m_OptionValue.m_LinkerOption = MDAssembly; | 
|---|
| 44 | m_OptionValue.m_RuntimeVersion = NULL; | 
|---|
| 45 | m_OptionValue.m_MetadataVersion = MDDefaultVersion; | 
|---|
| 46 | m_OptionValue.m_MergeOptions = MergeFlagsNone; | 
|---|
| 47 | m_OptionValue.m_InitialSize = MDInitialSizeDefault; | 
|---|
| 48 | m_OptionValue.m_LocalRefPreservation = MDPreserveLocalRefsNone; | 
|---|
| 49 | } // Disp::Disp | 
|---|
| 50 |  | 
|---|
| 51 | Disp::~Disp() | 
|---|
| 52 | { | 
|---|
| 53 | if (m_OptionValue.m_RuntimeVersion != NULL) | 
|---|
| 54 | delete [] m_OptionValue.m_RuntimeVersion; | 
|---|
| 55 | } // Disp::~Disp | 
|---|
| 56 |  | 
|---|
| 57 | //***************************************************************************** | 
|---|
| 58 | // Create a brand new scope.  This is based on the CLSID that was used to get | 
|---|
| 59 | // the dispenser. | 
|---|
| 60 | //***************************************************************************** | 
|---|
| 61 | __checkReturn | 
|---|
| 62 | HRESULT | 
|---|
| 63 | Disp::DefineScope( | 
|---|
| 64 | REFCLSID   rclsid,          // [in] What version to create. | 
|---|
| 65 | DWORD      dwCreateFlags,   // [in] Flags on the create. | 
|---|
| 66 | REFIID     riid,            // [in] The interface desired. | 
|---|
| 67 | IUnknown **ppIUnk)          // [out] Return interface on success. | 
|---|
| 68 | { | 
|---|
| 69 | #ifdef FEATURE_METADATA_EMIT | 
|---|
| 70 | HRESULT     hr = S_OK; | 
|---|
| 71 | PathString szFileName(PathString::Literal, W( "file:")); | 
|---|
| 72 | PathString szFileNameSuffix; | 
|---|
| 73 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 74 |  | 
|---|
| 75 | RegMeta     *pMeta = 0; | 
|---|
| 76 | OptionValue optionForNewScope = m_OptionValue; | 
|---|
| 77 |  | 
|---|
| 78 |  | 
|---|
| 79 | LOG((LF_METADATA, LL_INFO10, "Disp::DefineScope(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", rclsid, dwCreateFlags, riid, ppIUnk)); | 
|---|
| 80 |  | 
|---|
| 81 | if (dwCreateFlags) | 
|---|
| 82 | IfFailGo(E_INVALIDARG); | 
|---|
| 83 |  | 
|---|
| 84 | // Figure out what version of the metadata to emit | 
|---|
| 85 | if (rclsid == CLSID_CLR_v1_MetaData) | 
|---|
| 86 | { | 
|---|
| 87 | optionForNewScope.m_MetadataVersion = MDVersion1; | 
|---|
| 88 | } | 
|---|
| 89 | else if (rclsid == CLSID_CLR_v2_MetaData) | 
|---|
| 90 | { | 
|---|
| 91 | optionForNewScope.m_MetadataVersion = MDVersion2; | 
|---|
| 92 | } | 
|---|
| 93 | else | 
|---|
| 94 | { | 
|---|
| 95 | // If it is a version we don't understand, then we cannot continue. | 
|---|
| 96 | IfFailGo(CLDB_E_FILE_OLDVER); | 
|---|
| 97 | } | 
|---|
| 98 |  | 
|---|
| 99 | #ifdef ENC_DELTA_HACK | 
|---|
| 100 | // Testers need this flag for their tests. | 
|---|
| 101 |  | 
|---|
| 102 | DWORD len; | 
|---|
| 103 | EX_TRY{ | 
|---|
| 104 | len = WszGetEnvironmentVariable(W( "COMP_ENC_OPENSCOPE"), szFileNameSuffix); | 
|---|
| 105 | szFileName.Append(szFileNameSuffix); | 
|---|
| 106 | } | 
|---|
| 107 | EX_CATCH_HRESULT(hr); | 
|---|
| 108 |  | 
|---|
| 109 | if (len > 0) | 
|---|
| 110 | { | 
|---|
| 111 | // _ASSERTE(!"ENC override on DefineScope"); | 
|---|
| 112 | //        m_OptionValue.m_UpdateMode = MDUpdateENC; | 
|---|
| 113 | //        m_OptionValue.m_ErrorIfEmitOutOfOrder = MDErrorOutOfOrderDefault; | 
|---|
| 114 | //        hr = OpenScope(szFileName, ofWrite, riid, ppIUnk); | 
|---|
| 115 |  | 
|---|
| 116 | IMetaDataEmit *pMetaEmit; | 
|---|
| 117 | hr = OpenScope(szFileName, ofWrite, IID_IMetaDataEmit, (IUnknown **)&pMetaEmit); | 
|---|
| 118 | DWORD cb; | 
|---|
| 119 | CQuickBytes pbMetadata; | 
|---|
| 120 | hr = pMetaEmit->GetSaveSize(cssAccurate,&cb); | 
|---|
| 121 | _ASSERTE(SUCCEEDED(hr)); | 
|---|
| 122 |  | 
|---|
| 123 | IfFailGo(pbMetadata.ReSizeNoThrow(cb)); | 
|---|
| 124 |  | 
|---|
| 125 | hr = pMetaEmit->SaveToMemory(pbMetadata.Ptr(),cb); | 
|---|
| 126 | _ASSERTE(SUCCEEDED(hr)); | 
|---|
| 127 | //        hr = OpenScopeOnMemory( pbMetadata.Ptr(), cb, ofWrite|MDUpdateENC|MDUpdateDelta, riid, ppIUnk); | 
|---|
| 128 |  | 
|---|
| 129 |  | 
|---|
| 130 | VARIANT encOption; | 
|---|
| 131 | V_VT(&encOption) = VT_UI4; | 
|---|
| 132 | V_UI4(&encOption) = MDUpdateENC; | 
|---|
| 133 | SetOption(MetaDataSetENC, &encOption); | 
|---|
| 134 | V_UI4(&encOption) = MDErrorOutOfOrderDefault; | 
|---|
| 135 | SetOption(MetaDataErrorIfEmitOutOfOrder, &encOption); | 
|---|
| 136 | hr = OpenScopeOnMemory( pbMetadata.Ptr(), cb, ofWrite, riid, ppIUnk); | 
|---|
| 137 | _ASSERTE(SUCCEEDED(hr)); | 
|---|
| 138 | BOOL fResult = SUCCEEDED(hr); | 
|---|
| 139 | // print out a message so people know what's happening | 
|---|
| 140 | printf( "Defining scope for EnC using %S %s\n", | 
|---|
| 141 | static_cast<LPCWSTR>(szFileNameSuffix), fResult ? "succeeded": "failed"); | 
|---|
| 142 |  | 
|---|
| 143 | goto ErrExit; | 
|---|
| 144 | } | 
|---|
| 145 | #endif // ENC_DELTA_HACK | 
|---|
| 146 |  | 
|---|
| 147 | // Create a new coclass for this guy. | 
|---|
| 148 | pMeta = new (nothrow) RegMeta(); | 
|---|
| 149 | IfNullGo(pMeta); | 
|---|
| 150 |  | 
|---|
| 151 | IfFailGo(pMeta->SetOption(&optionForNewScope)); | 
|---|
| 152 |  | 
|---|
| 153 | // Create the MiniMd-style scope. | 
|---|
| 154 | IfFailGo(pMeta->CreateNewMD()); | 
|---|
| 155 |  | 
|---|
| 156 | // Get the requested interface. | 
|---|
| 157 | IfFailGo(pMeta->QueryInterface(riid, (void **)ppIUnk)); | 
|---|
| 158 |  | 
|---|
| 159 | // Add the new RegMeta to the cache. | 
|---|
| 160 | IfFailGo(pMeta->AddToCache()); | 
|---|
| 161 |  | 
|---|
| 162 | LOG((LOGMD, "{%08x} Created new emit scope\n", pMeta)); | 
|---|
| 163 |  | 
|---|
| 164 | ErrExit: | 
|---|
| 165 | if (FAILED(hr)) | 
|---|
| 166 | { | 
|---|
| 167 | if (pMeta != NULL) | 
|---|
| 168 | delete pMeta; | 
|---|
| 169 | *ppIUnk = NULL; | 
|---|
| 170 | } | 
|---|
| 171 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 172 |  | 
|---|
| 173 | return hr; | 
|---|
| 174 | #else //!FEATURE_METADATA_EMIT | 
|---|
| 175 | return E_NOTIMPL; | 
|---|
| 176 | #endif //!FEATURE_METADATA_EMIT | 
|---|
| 177 | } // Disp::DefineScope | 
|---|
| 178 |  | 
|---|
| 179 |  | 
|---|
| 180 | //***************************************************************************** | 
|---|
| 181 | // Deliver scope to caller of OpenScope or OpenScopeOnMemory (this may | 
|---|
| 182 | // involve wrapping a WinMD adapter.) | 
|---|
| 183 | //***************************************************************************** | 
|---|
| 184 | static HRESULT DeliverScope(IMDCommon *pMDCommon, REFIID riid, DWORD dwOpenFlags, IUnknown **ppIUnk) | 
|---|
| 185 | { | 
|---|
| 186 | HRESULT     hr; | 
|---|
| 187 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 188 |  | 
|---|
| 189 | #if defined(FEATURE_COMINTEROP) | 
|---|
| 190 | IfFailGo((dwOpenFlags & ofNoTransform) ? S_FALSE : CheckIfWinMDAdapterNeeded(pMDCommon)); | 
|---|
| 191 | if (hr == S_OK) | 
|---|
| 192 | { | 
|---|
| 193 | IfFailGo(CreateWinMDImport(pMDCommon, riid, (void**)ppIUnk)); | 
|---|
| 194 | } | 
|---|
| 195 | else | 
|---|
| 196 | #endif | 
|---|
| 197 | { | 
|---|
| 198 | IfFailGo(pMDCommon->QueryInterface(riid, (void**)ppIUnk)); | 
|---|
| 199 | } | 
|---|
| 200 |  | 
|---|
| 201 | ErrExit: | 
|---|
| 202 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 203 | return hr; | 
|---|
| 204 | } | 
|---|
| 205 |  | 
|---|
| 206 | //***************************************************************************** | 
|---|
| 207 | // Open an existing scope. | 
|---|
| 208 | //***************************************************************************** | 
|---|
| 209 | HRESULT Disp::OpenScope(                // Return code. | 
|---|
| 210 | LPCWSTR     szFileName,             // [in] The scope to open. | 
|---|
| 211 | DWORD       dwOpenFlags,            // [in] Open mode flags. | 
|---|
| 212 | REFIID      riid,                   // [in] The interface desired. | 
|---|
| 213 | IUnknown    **ppIUnk)               // [out] Return interface on success. | 
|---|
| 214 | { | 
|---|
| 215 | HRESULT     hr; | 
|---|
| 216 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 217 | LOG((LF_METADATA, LL_INFO10, "Disp::OpenScope(%S, 0x%08x, 0x%08x, 0x%08x)\n", MDSTR(szFileName), dwOpenFlags, riid, ppIUnk)); | 
|---|
| 218 |  | 
|---|
| 219 | IMDCommon *pMDCommon = NULL; | 
|---|
| 220 |  | 
|---|
| 221 | // Validate that there is some sort of file name. | 
|---|
| 222 | if ((szFileName == NULL) || (szFileName[0] == 0) || (ppIUnk == NULL)) | 
|---|
| 223 | IfFailGo(E_INVALIDARG); | 
|---|
| 224 |  | 
|---|
| 225 | *ppIUnk = NULL; | 
|---|
| 226 | IfFailGo(OpenRawScope(szFileName, dwOpenFlags, IID_IMDCommon, (IUnknown**)&pMDCommon)); | 
|---|
| 227 | IfFailGo(DeliverScope(pMDCommon, riid, dwOpenFlags, ppIUnk)); | 
|---|
| 228 | ErrExit: | 
|---|
| 229 | if (pMDCommon) | 
|---|
| 230 | pMDCommon->Release(); | 
|---|
| 231 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 232 | return hr; | 
|---|
| 233 | } | 
|---|
| 234 |  | 
|---|
| 235 |  | 
|---|
| 236 | //***************************************************************************** | 
|---|
| 237 | // Open a raw view of existing scope. | 
|---|
| 238 | //***************************************************************************** | 
|---|
| 239 | __checkReturn | 
|---|
| 240 | HRESULT | 
|---|
| 241 | Disp::OpenRawScope( | 
|---|
| 242 | LPCWSTR    szFileName,      // [in] The scope to open. | 
|---|
| 243 | DWORD      dwOpenFlags,     // [in] Open mode flags. | 
|---|
| 244 | REFIID     riid,            // [in] The interface desired. | 
|---|
| 245 | IUnknown **ppIUnk)          // [out] Return interface on success. | 
|---|
| 246 | { | 
|---|
| 247 | HRESULT hr; | 
|---|
| 248 |  | 
|---|
| 249 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 250 |  | 
|---|
| 251 | _ASSERTE(szFileName != NULL); | 
|---|
| 252 | _ASSERTE(ppIUnk != NULL); | 
|---|
| 253 | RegMeta *pMeta = NULL; | 
|---|
| 254 |  | 
|---|
| 255 | #ifdef FEATURE_METADATA_LOAD_TRUSTED_IMAGES | 
|---|
| 256 | // Don't assert for code:ofTrustedImage (reserved) flag if the feature is supported | 
|---|
| 257 | _ASSERTE(!IsOfReserved(dwOpenFlags & ~ofTrustedImage)); | 
|---|
| 258 | #else | 
|---|
| 259 | _ASSERTE(!IsOfReserved(dwOpenFlags)); | 
|---|
| 260 | #endif //!FEATURE_METADATA_LOAD_TRUSTED_IMAGES | 
|---|
| 261 |  | 
|---|
| 262 | { | 
|---|
| 263 | } | 
|---|
| 264 |  | 
|---|
| 265 | if (IsOfReadOnly(dwOpenFlags) && IsOfReadWrite(dwOpenFlags)) | 
|---|
| 266 | {   // Invalid combination of flags - ofReadOnly & ofWrite | 
|---|
| 267 | IfFailGo(E_INVALIDARG); | 
|---|
| 268 | } | 
|---|
| 269 | // If open-for-read, and there is already an open-for-read copy, return it. | 
|---|
| 270 | if (IsOfReadOnly(dwOpenFlags)) | 
|---|
| 271 | { | 
|---|
| 272 | RegMeta::FindCachedReadOnlyEntry(szFileName, dwOpenFlags, &pMeta); | 
|---|
| 273 | if (pMeta != NULL) | 
|---|
| 274 | { | 
|---|
| 275 | // Return the requested interface. | 
|---|
| 276 | hr = pMeta->QueryInterface(riid, (void **) ppIUnk); | 
|---|
| 277 | if (FAILED(hr)) | 
|---|
| 278 | { | 
|---|
| 279 | pMeta = NULL; // Don't delete cached RegMeta! | 
|---|
| 280 | } | 
|---|
| 281 | else | 
|---|
| 282 | { | 
|---|
| 283 | pMeta->Release(); // Give back refcount from QI | 
|---|
| 284 | LOG((LOGMD, "{%08x} Found in cache '%S'\n", pMeta, MDSTR(szFileName))); | 
|---|
| 285 | } | 
|---|
| 286 |  | 
|---|
| 287 | goto ErrExit; | 
|---|
| 288 | } | 
|---|
| 289 | } | 
|---|
| 290 | // Create a new coclass for this guy. | 
|---|
| 291 | pMeta = new (nothrow) RegMeta(); | 
|---|
| 292 | IfNullGo(pMeta); | 
|---|
| 293 |  | 
|---|
| 294 | IfFailGo(pMeta->SetOption(&m_OptionValue)); | 
|---|
| 295 |  | 
|---|
| 296 | // Always initialize the RegMeta's stgdb. | 
|---|
| 297 | // <TODO>@FUTURE: there are some cleanup for the open code!!</TODO> | 
|---|
| 298 | if (memcmp(szFileName, W( "file:"), 10) == 0) | 
|---|
| 299 | { | 
|---|
| 300 | szFileName = &szFileName[5]; | 
|---|
| 301 | } | 
|---|
| 302 |  | 
|---|
| 303 | // Try to open the MiniMd-style scope. | 
|---|
| 304 | IfFailGo(pMeta->OpenExistingMD(szFileName, 0 /* pbData */,0 /* cbData */, dwOpenFlags)); | 
|---|
| 305 |  | 
|---|
| 306 | // Obtain the requested interface. | 
|---|
| 307 | IfFailGo(pMeta->QueryInterface(riid, (void **)ppIUnk) ); | 
|---|
| 308 |  | 
|---|
| 309 | // Add the new RegMeta to the cache.  If this is read-only, any future opens will | 
|---|
| 310 | //  find this entry.  If, due to another thread concurrently opening the same file, | 
|---|
| 311 | //  there is already another copy in the cache, well, then there will be two | 
|---|
| 312 | //  read-only copies in the cache.  This is considered to be somewhat of a corner | 
|---|
| 313 | //  case, and the only harm is temporary memory usage.  All requests will be | 
|---|
| 314 | //  satisfied by one or the other (depending on search algorithm), and eventually, | 
|---|
| 315 | //  the "other" copy will be released. | 
|---|
| 316 | IfFailGo(pMeta->AddToCache()); | 
|---|
| 317 |  | 
|---|
| 318 | LOG((LOGMD, "{%08x} Successfully opened '%S'\n", pMeta, MDSTR(szFileName))); | 
|---|
| 319 |  | 
|---|
| 320 | #if defined(_DEBUG) | 
|---|
| 321 | if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_RegMetaDump)) | 
|---|
| 322 | { | 
|---|
| 323 | int DumpMD_impl(RegMeta *pMD); | 
|---|
| 324 | DumpMD_impl(pMeta); | 
|---|
| 325 | } | 
|---|
| 326 | #endif // _DEBUG | 
|---|
| 327 |  | 
|---|
| 328 |  | 
|---|
| 329 | ErrExit: | 
|---|
| 330 | if (FAILED(hr)) | 
|---|
| 331 | { | 
|---|
| 332 | if (pMeta != NULL) | 
|---|
| 333 | delete pMeta; | 
|---|
| 334 | *ppIUnk = NULL; | 
|---|
| 335 | } | 
|---|
| 336 |  | 
|---|
| 337 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 338 |  | 
|---|
| 339 | return hr; | 
|---|
| 340 | } // Disp::OpenScope | 
|---|
| 341 |  | 
|---|
| 342 |  | 
|---|
| 343 | //***************************************************************************** | 
|---|
| 344 | // Open an existing scope. | 
|---|
| 345 | //***************************************************************************** | 
|---|
| 346 | HRESULT Disp::OpenScopeOnMemory(        // Return code. | 
|---|
| 347 | LPCVOID     pData,                  // [in] Location of scope data. | 
|---|
| 348 | ULONG       cbData,                 // [in] Size of the data pointed to by pData. | 
|---|
| 349 | DWORD       dwOpenFlags,            // [in] Open mode flags. | 
|---|
| 350 | REFIID      riid,                   // [in] The interface desired. | 
|---|
| 351 | IUnknown    **ppIUnk)               // [out] Return interface on success. | 
|---|
| 352 | { | 
|---|
| 353 | HRESULT     hr; | 
|---|
| 354 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 355 | LOG((LF_METADATA, LL_INFO10, "Disp::OpenScopeOnMemory(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", pData, cbData, dwOpenFlags, riid, ppIUnk)); | 
|---|
| 356 |  | 
|---|
| 357 | IMDCommon *pMDCommon = NULL; | 
|---|
| 358 |  | 
|---|
| 359 | _ASSERTE(!IsOfReserved(dwOpenFlags)); | 
|---|
| 360 | if (ppIUnk == NULL) | 
|---|
| 361 | IfFailGo(E_INVALIDARG); | 
|---|
| 362 | *ppIUnk = NULL; | 
|---|
| 363 | IfFailGo(OpenRawScopeOnMemory(pData, cbData, dwOpenFlags, IID_IMDCommon, (IUnknown**)&pMDCommon)); | 
|---|
| 364 | IfFailGo(DeliverScope(pMDCommon, riid, dwOpenFlags, ppIUnk)); | 
|---|
| 365 | ErrExit: | 
|---|
| 366 | if (pMDCommon) | 
|---|
| 367 | pMDCommon->Release(); | 
|---|
| 368 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 369 | return hr; | 
|---|
| 370 | } | 
|---|
| 371 |  | 
|---|
| 372 | //***************************************************************************** | 
|---|
| 373 | // Open a raw voew of existing scope. | 
|---|
| 374 | //***************************************************************************** | 
|---|
| 375 | HRESULT Disp::OpenRawScopeOnMemory(        // Return code. | 
|---|
| 376 | LPCVOID     pData,                  // [in] Location of scope data. | 
|---|
| 377 | ULONG       cbData,                 // [in] Size of the data pointed to by pData. | 
|---|
| 378 | DWORD       dwOpenFlags,            // [in] Open mode flags. | 
|---|
| 379 | REFIID      riid,                   // [in] The interface desired. | 
|---|
| 380 | IUnknown    **ppIUnk)               // [out] Return interface on success. | 
|---|
| 381 | { | 
|---|
| 382 | HRESULT     hr; | 
|---|
| 383 |  | 
|---|
| 384 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 385 |  | 
|---|
| 386 | RegMeta     *pMeta = 0; | 
|---|
| 387 |  | 
|---|
| 388 | _ASSERTE(!IsOfReserved(dwOpenFlags)); | 
|---|
| 389 |  | 
|---|
| 390 | // Create a new coclass for this guy. | 
|---|
| 391 | pMeta = new (nothrow) RegMeta(); | 
|---|
| 392 | IfNullGo(pMeta); | 
|---|
| 393 | IfFailGo(pMeta->SetOption(&m_OptionValue)); | 
|---|
| 394 |  | 
|---|
| 395 |  | 
|---|
| 396 | PREFIX_ASSUME(pMeta != NULL); | 
|---|
| 397 | // Always initialize the RegMeta's stgdb. | 
|---|
| 398 | IfFailGo(pMeta->OpenExistingMD(0 /* szFileName */, const_cast<void*>(pData), cbData, dwOpenFlags)); | 
|---|
| 399 |  | 
|---|
| 400 | LOG((LOGMD, "{%08x} Opened new scope on memory, pData: %08x    cbData: %08x\n", pMeta, pData, cbData)); | 
|---|
| 401 |  | 
|---|
| 402 | // Return the requested interface. | 
|---|
| 403 | IfFailGo( pMeta->QueryInterface(riid, (void **) ppIUnk) ); | 
|---|
| 404 |  | 
|---|
| 405 | // Add the new RegMeta to the cache. | 
|---|
| 406 | IfFailGo(pMeta->AddToCache()); | 
|---|
| 407 |  | 
|---|
| 408 | #if defined(_DEBUG) | 
|---|
| 409 | if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_RegMetaDump)) | 
|---|
| 410 | { | 
|---|
| 411 | int DumpMD_impl(RegMeta *pMD); | 
|---|
| 412 | DumpMD_impl(pMeta); | 
|---|
| 413 | } | 
|---|
| 414 | #endif // _DEBUG | 
|---|
| 415 |  | 
|---|
| 416 | ErrExit: | 
|---|
| 417 | if (FAILED(hr)) | 
|---|
| 418 | { | 
|---|
| 419 | if (pMeta) delete pMeta; | 
|---|
| 420 | *ppIUnk = 0; | 
|---|
| 421 | } | 
|---|
| 422 |  | 
|---|
| 423 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 424 |  | 
|---|
| 425 | return hr; | 
|---|
| 426 | } // Disp::OpenScopeOnMemory | 
|---|
| 427 |  | 
|---|
| 428 |  | 
|---|
| 429 | //***************************************************************************** | 
|---|
| 430 | // Get the directory where the CLR system resides. | 
|---|
| 431 | // | 
|---|
| 432 | // Implements public API code:IMetaDataDispenserEx::GetCORSystemDirectory. | 
|---|
| 433 | //***************************************************************************** | 
|---|
| 434 | HRESULT | 
|---|
| 435 | Disp::GetCORSystemDirectory( | 
|---|
| 436 | __out_ecount (cchBuffer) LPWSTR szBuffer,      // [out] Buffer for the directory name | 
|---|
| 437 | DWORD                           cchBuffer,     // [in] Size of the buffer | 
|---|
| 438 | DWORD                          *pcchBuffer)    // [out] Number of characters returned | 
|---|
| 439 | { | 
|---|
| 440 |  | 
|---|
| 441 | UNREACHABLE_MSG( "Calling IMetaDataDispenser::GetCORSystemDirectory!  This code should not be " | 
|---|
| 442 | "reachable or needs to be reimplemented for CoreCLR!"); | 
|---|
| 443 |  | 
|---|
| 444 | return E_NOTIMPL; | 
|---|
| 445 | } // Disp::GetCORSystemDirectory | 
|---|
| 446 |  | 
|---|
| 447 | HRESULT Disp::FindAssembly(             // S_OK or error | 
|---|
| 448 | LPCWSTR     szAppBase,              // [IN] optional - can be NULL | 
|---|
| 449 | LPCWSTR     szPrivateBin,           // [IN] optional - can be NULL | 
|---|
| 450 | LPCWSTR     szGlobalBin,            // [IN] optional - can be NULL | 
|---|
| 451 | LPCWSTR     szAssemblyName,         // [IN] required - this is the assembly you are requesting | 
|---|
| 452 | LPCWSTR     szName,                 // [OUT] buffer - to hold name | 
|---|
| 453 | ULONG       cchName,                // [IN] the name buffer's size | 
|---|
| 454 | ULONG       *pcName)                // [OUT] the number of characters returend in the buffer | 
|---|
| 455 | { | 
|---|
| 456 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 457 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 458 |  | 
|---|
| 459 | return E_NOTIMPL; | 
|---|
| 460 | } // Disp::FindAssembly | 
|---|
| 461 |  | 
|---|
| 462 | HRESULT Disp::FindAssemblyModule(           // S_OK or error | 
|---|
| 463 | LPCWSTR     szAppBase,                  // [IN] optional - can be NULL | 
|---|
| 464 | LPCWSTR     szPrivateBin,               // [IN] optional - can be NULL | 
|---|
| 465 | LPCWSTR     szGlobalBin,                // [IN] optional - can be NULL | 
|---|
| 466 | LPCWSTR     szAssemblyName,             // [IN] The assembly name or code base of the assembly | 
|---|
| 467 | LPCWSTR     szModuleName,               // [IN] required - the name of the module | 
|---|
| 468 | __out_ecount (cchName) LPWSTR  szName,  // [OUT] buffer - to hold name | 
|---|
| 469 | ULONG       cchName,                    // [IN]  the name buffer's size | 
|---|
| 470 | ULONG       *pcName)                    // [OUT] the number of characters returend in the buffer | 
|---|
| 471 | { | 
|---|
| 472 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 473 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 474 |  | 
|---|
| 475 | return E_NOTIMPL; | 
|---|
| 476 | } // Disp::FindAssemblyModule | 
|---|
| 477 |  | 
|---|
| 478 | //***************************************************************************** | 
|---|
| 479 | // Open a scope on an ITypeInfo | 
|---|
| 480 | //***************************************************************************** | 
|---|
| 481 | HRESULT Disp::OpenScopeOnITypeInfo(     // Return code. | 
|---|
| 482 | ITypeInfo   *pITI,                  // [in] ITypeInfo to open. | 
|---|
| 483 | DWORD       dwOpenFlags,            // [in] Open mode flags. | 
|---|
| 484 | REFIID      riid,                   // [in] The interface desired. | 
|---|
| 485 | IUnknown    **ppIUnk)               // [out] Return interface on success. | 
|---|
| 486 | { | 
|---|
| 487 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 488 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 489 |  | 
|---|
| 490 | return E_NOTIMPL; | 
|---|
| 491 | } // Disp::OpenScopeOnITypeInfo | 
|---|
| 492 |  | 
|---|
| 493 | #ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE | 
|---|
| 494 |  | 
|---|
| 495 | //***************************************************************************** | 
|---|
| 496 | // IMetaDataDispenserCustom | 
|---|
| 497 | //***************************************************************************** | 
|---|
| 498 |  | 
|---|
| 499 | HRESULT Disp::OpenScopeOnCustomDataSource(  // S_OK or error | 
|---|
| 500 | IMDCustomDataSource  *pCustomSource, // [in] The scope to open. | 
|---|
| 501 | DWORD                dwOpenFlags,    // [in] Open mode flags. | 
|---|
| 502 | REFIID               riid,           // [in] The interface desired. | 
|---|
| 503 | IUnknown             **ppIUnk)       // [out] Return interface on success. | 
|---|
| 504 | { | 
|---|
| 505 | HRESULT     hr; | 
|---|
| 506 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 507 | LOG((LF_METADATA, LL_INFO10, "Disp::OpenScopeOnCustomDataSource(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", pCustomSource, dwOpenFlags, riid, ppIUnk)); | 
|---|
| 508 |  | 
|---|
| 509 | IMDCommon *pMDCommon = NULL; | 
|---|
| 510 |  | 
|---|
| 511 | _ASSERTE(!IsOfReserved(dwOpenFlags)); | 
|---|
| 512 | if (ppIUnk == NULL) | 
|---|
| 513 | IfFailGo(E_INVALIDARG); | 
|---|
| 514 | *ppIUnk = NULL; | 
|---|
| 515 | IfFailGo(OpenRawScopeOnCustomDataSource(pCustomSource, dwOpenFlags, IID_IMDCommon, (IUnknown**)&pMDCommon)); | 
|---|
| 516 | IfFailGo(DeliverScope(pMDCommon, riid, dwOpenFlags, ppIUnk)); | 
|---|
| 517 | ErrExit: | 
|---|
| 518 | if (pMDCommon) | 
|---|
| 519 | pMDCommon->Release(); | 
|---|
| 520 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 521 | return hr; | 
|---|
| 522 | } | 
|---|
| 523 |  | 
|---|
| 524 |  | 
|---|
| 525 | //***************************************************************************** | 
|---|
| 526 | // Open a raw view of existing scope. | 
|---|
| 527 | //***************************************************************************** | 
|---|
| 528 | HRESULT Disp::OpenRawScopeOnCustomDataSource(        // Return code. | 
|---|
| 529 | IMDCustomDataSource*  pDataSource,  // [in] scope data. | 
|---|
| 530 | DWORD       dwOpenFlags,            // [in] Open mode flags. | 
|---|
| 531 | REFIID      riid,                   // [in] The interface desired. | 
|---|
| 532 | IUnknown    **ppIUnk)               // [out] Return interface on success. | 
|---|
| 533 | { | 
|---|
| 534 | HRESULT     hr; | 
|---|
| 535 |  | 
|---|
| 536 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 537 |  | 
|---|
| 538 | RegMeta     *pMeta = 0; | 
|---|
| 539 |  | 
|---|
| 540 | _ASSERTE(!IsOfReserved(dwOpenFlags)); | 
|---|
| 541 |  | 
|---|
| 542 | // Create a new coclass for this guy. | 
|---|
| 543 | pMeta = new (nothrow)RegMeta(); | 
|---|
| 544 | IfNullGo(pMeta); | 
|---|
| 545 | IfFailGo(pMeta->SetOption(&m_OptionValue)); | 
|---|
| 546 |  | 
|---|
| 547 |  | 
|---|
| 548 | PREFIX_ASSUME(pMeta != NULL); | 
|---|
| 549 | // Always initialize the RegMeta's stgdb. | 
|---|
| 550 | // TODO | 
|---|
| 551 | IfFailGo(pMeta->OpenExistingMD(pDataSource, dwOpenFlags)); | 
|---|
| 552 |  | 
|---|
| 553 | LOG((LOGMD, "{%08x} Opened new scope on custom data source, pDataSource: %08x\n", pMeta, pDataSource)); | 
|---|
| 554 |  | 
|---|
| 555 | // Return the requested interface. | 
|---|
| 556 | IfFailGo(pMeta->QueryInterface(riid, (void **)ppIUnk)); | 
|---|
| 557 |  | 
|---|
| 558 | // Add the new RegMeta to the cache. | 
|---|
| 559 | IfFailGo(pMeta->AddToCache()); | 
|---|
| 560 |  | 
|---|
| 561 | #if defined(_DEBUG) | 
|---|
| 562 | if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_RegMetaDump)) | 
|---|
| 563 | { | 
|---|
| 564 | int DumpMD_impl(RegMeta *pMD); | 
|---|
| 565 | DumpMD_impl(pMeta); | 
|---|
| 566 | } | 
|---|
| 567 | #endif // _DEBUG | 
|---|
| 568 |  | 
|---|
| 569 | ErrExit: | 
|---|
| 570 | if (FAILED(hr)) | 
|---|
| 571 | { | 
|---|
| 572 | if (pMeta) delete pMeta; | 
|---|
| 573 | *ppIUnk = 0; | 
|---|
| 574 | } | 
|---|
| 575 |  | 
|---|
| 576 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 577 |  | 
|---|
| 578 | return hr; | 
|---|
| 579 | } // Disp::OpenRawScopeOnCustomDataSource | 
|---|
| 580 |  | 
|---|
| 581 | #endif | 
|---|
| 582 |  | 
|---|
| 583 | //***************************************************************************** | 
|---|
| 584 | // IUnknown | 
|---|
| 585 | //***************************************************************************** | 
|---|
| 586 |  | 
|---|
| 587 | ULONG Disp::AddRef() | 
|---|
| 588 | { | 
|---|
| 589 | return InterlockedIncrement(&m_cRef); | 
|---|
| 590 | } // Disp::AddRef | 
|---|
| 591 |  | 
|---|
| 592 | ULONG Disp::Release() | 
|---|
| 593 | { | 
|---|
| 594 | ULONG cRef = InterlockedDecrement(&m_cRef); | 
|---|
| 595 | if (cRef == 0) | 
|---|
| 596 | delete this; | 
|---|
| 597 | return cRef; | 
|---|
| 598 | } // Disp::Release | 
|---|
| 599 |  | 
|---|
| 600 | HRESULT Disp::QueryInterface(REFIID riid, void **ppUnk) | 
|---|
| 601 | { | 
|---|
| 602 | *ppUnk = 0; | 
|---|
| 603 |  | 
|---|
| 604 | if (riid == IID_IUnknown) | 
|---|
| 605 | *ppUnk = (IUnknown *) (IMetaDataDispenser *) this; | 
|---|
| 606 | else if (riid == IID_IMetaDataDispenser) | 
|---|
| 607 | *ppUnk = (IMetaDataDispenser *) this; | 
|---|
| 608 | else if (riid == IID_IMetaDataDispenserEx) | 
|---|
| 609 | *ppUnk = (IMetaDataDispenserEx *) this; | 
|---|
| 610 | #ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE | 
|---|
| 611 | else if (riid == IID_IMetaDataDispenserCustom) | 
|---|
| 612 | *ppUnk = static_cast<IMetaDataDispenserCustom*>(this); | 
|---|
| 613 | #endif | 
|---|
| 614 | else | 
|---|
| 615 | return E_NOINTERFACE; | 
|---|
| 616 | AddRef(); | 
|---|
| 617 | return S_OK; | 
|---|
| 618 | } // Disp::QueryInterface | 
|---|
| 619 |  | 
|---|
| 620 |  | 
|---|
| 621 | //***************************************************************************** | 
|---|
| 622 | // Called by the class factory template to create a new instance of this object. | 
|---|
| 623 | //***************************************************************************** | 
|---|
| 624 | HRESULT Disp::CreateObject(REFIID riid, void **ppUnk) | 
|---|
| 625 | { | 
|---|
| 626 | HRESULT     hr; | 
|---|
| 627 | Disp *pDisp = new (nothrow) Disp(); | 
|---|
| 628 |  | 
|---|
| 629 | if (pDisp == 0) | 
|---|
| 630 | return (E_OUTOFMEMORY); | 
|---|
| 631 |  | 
|---|
| 632 | hr = pDisp->QueryInterface(riid, ppUnk); | 
|---|
| 633 | if (FAILED(hr)) | 
|---|
| 634 | delete pDisp; | 
|---|
| 635 | return hr; | 
|---|
| 636 | } // Disp::CreateObject | 
|---|
| 637 |  | 
|---|
| 638 | //***************************************************************************** | 
|---|
| 639 | // This routine provides the user a way to set certain properties on the | 
|---|
| 640 | // Dispenser. | 
|---|
| 641 | // | 
|---|
| 642 | // Implements public API code:IMetaDataDispenserEx::SetOption. | 
|---|
| 643 | //***************************************************************************** | 
|---|
| 644 | __checkReturn | 
|---|
| 645 | HRESULT | 
|---|
| 646 | Disp::SetOption( | 
|---|
| 647 | REFGUID        optionid,    // [in] GUID for the option to be set. | 
|---|
| 648 | const VARIANT *pvalue)      // [in] Value to which the option is to be set. | 
|---|
| 649 | { | 
|---|
| 650 | HRESULT hr = S_OK; | 
|---|
| 651 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 652 |  | 
|---|
| 653 | LOG((LF_METADATA, LL_INFO10, "Disp::SetOption(0x%08x, 0x%08x)\n", optionid, pvalue)); | 
|---|
| 654 |  | 
|---|
| 655 | if (optionid == MetaDataCheckDuplicatesFor) | 
|---|
| 656 | { | 
|---|
| 657 | if (V_VT(pvalue) != VT_UI4) | 
|---|
| 658 | { | 
|---|
| 659 | _ASSERTE(! "Invalid Variant Type value!"); | 
|---|
| 660 | IfFailGo(E_INVALIDARG); | 
|---|
| 661 | } | 
|---|
| 662 | m_OptionValue.m_DupCheck = (CorCheckDuplicatesFor) V_UI4(pvalue); | 
|---|
| 663 | } | 
|---|
| 664 | else if (optionid == MetaDataRefToDefCheck) | 
|---|
| 665 | { | 
|---|
| 666 | if (V_VT(pvalue) != VT_UI4) | 
|---|
| 667 | { | 
|---|
| 668 | _ASSERTE(! "Invalid Variant Type value!"); | 
|---|
| 669 | IfFailGo(E_INVALIDARG); | 
|---|
| 670 | } | 
|---|
| 671 | m_OptionValue.m_RefToDefCheck = (CorRefToDefCheck) V_UI4(pvalue); | 
|---|
| 672 | } | 
|---|
| 673 | else if (optionid == MetaDataErrorIfEmitOutOfOrder) | 
|---|
| 674 | { | 
|---|
| 675 | if (V_VT(pvalue) != VT_UI4) | 
|---|
| 676 | { | 
|---|
| 677 | _ASSERTE(! "Invalid Variant Type value!"); | 
|---|
| 678 | IfFailGo(E_INVALIDARG); | 
|---|
| 679 | } | 
|---|
| 680 | m_OptionValue.m_ErrorIfEmitOutOfOrder = (CorErrorIfEmitOutOfOrder) V_UI4(pvalue); | 
|---|
| 681 | } | 
|---|
| 682 | else if (optionid == MetaDataThreadSafetyOptions) | 
|---|
| 683 | { | 
|---|
| 684 | if (V_VT(pvalue) != VT_UI4) | 
|---|
| 685 | { | 
|---|
| 686 | _ASSERTE(! "Invalid Variant Type value!"); | 
|---|
| 687 | IfFailGo(E_INVALIDARG); | 
|---|
| 688 | } | 
|---|
| 689 | m_OptionValue.m_ThreadSafetyOptions = (CorThreadSafetyOptions) V_UI4(pvalue); | 
|---|
| 690 | } | 
|---|
| 691 | // Note: mscordbi had all these options accessible in 3.5/4.0 RTM, let's keep it this way for AppCompat. | 
|---|
| 692 | #if defined(FEATURE_METADATA_EMIT_ALL) || defined(FEATURE_METADATA_EMIT_IN_DEBUGGER) | 
|---|
| 693 | else if (optionid == MetaDataNotificationForTokenMovement) | 
|---|
| 694 | {   // Note: This is not used in CLR sources anymore, but we store the value and return it back in | 
|---|
| 695 | // IMetaDataDispenserEx::GetOption (code:RegMeta::GetOption), so we keep it here for backward-compat. | 
|---|
| 696 | if (V_VT(pvalue) != VT_UI4) | 
|---|
| 697 | { | 
|---|
| 698 | _ASSERTE(! "Invalid Variant Type value!"); | 
|---|
| 699 | IfFailGo(E_INVALIDARG); | 
|---|
| 700 | } | 
|---|
| 701 | m_OptionValue.m_NotifyRemap = (CorNotificationForTokenMovement)V_UI4(pvalue); | 
|---|
| 702 | } | 
|---|
| 703 | else if (optionid == MetaDataSetENC) | 
|---|
| 704 | {   // EnC update mode (also aliased as code:MetaDataSetUpdate) | 
|---|
| 705 | if (V_VT(pvalue) != VT_UI4) | 
|---|
| 706 | { | 
|---|
| 707 | _ASSERTE(! "Invalid Variant Type value!"); | 
|---|
| 708 | IfFailGo(E_INVALIDARG); | 
|---|
| 709 | } | 
|---|
| 710 | m_OptionValue.m_UpdateMode = V_UI4(pvalue); | 
|---|
| 711 | } | 
|---|
| 712 | else if (optionid == MetaDataImportOption) | 
|---|
| 713 | {   // Allows enumeration of EnC deleted items by Import API | 
|---|
| 714 | if (V_VT(pvalue) != VT_UI4) | 
|---|
| 715 | { | 
|---|
| 716 | _ASSERTE(! "Invalid Variant Type value!"); | 
|---|
| 717 | IfFailGo(E_INVALIDARG); | 
|---|
| 718 | } | 
|---|
| 719 | m_OptionValue.m_ImportOption = (CorImportOptions) V_UI4(pvalue); | 
|---|
| 720 | } | 
|---|
| 721 | else if (optionid == MetaDataLinkerOptions) | 
|---|
| 722 | {   // Used only by code:RegMeta::UnmarkAll (code:IMetaDataFilter::UnmarkAll) | 
|---|
| 723 | if (V_VT(pvalue) != VT_UI4) | 
|---|
| 724 | { | 
|---|
| 725 | _ASSERTE(! "Invalid Variant Type value!"); | 
|---|
| 726 | IfFailGo(E_INVALIDARG); | 
|---|
| 727 | } | 
|---|
| 728 | m_OptionValue.m_LinkerOption = (CorLinkerOptions) V_UI4(pvalue); | 
|---|
| 729 | } | 
|---|
| 730 | else if (optionid == MetaDataMergerOptions) | 
|---|
| 731 | { | 
|---|
| 732 | if (V_VT(pvalue) != VT_UI4) | 
|---|
| 733 | { | 
|---|
| 734 | _ASSERTE(! "Invalid Variant Type value!"); | 
|---|
| 735 | IfFailGo(E_INVALIDARG); | 
|---|
| 736 | } | 
|---|
| 737 | m_OptionValue.m_MergeOptions = (MergeFlags) V_UI4(pvalue); | 
|---|
| 738 | } | 
|---|
| 739 | else if (optionid == MetaDataGenerateTCEAdapters) | 
|---|
| 740 | {   // Note: This is not used in CLR sources anymore, but we store the value and return it back in | 
|---|
| 741 | // IMetaDataDispenserEx::GetOption (code:RegMeta::GetOption), so we keep it for backward-compat. | 
|---|
| 742 | if (V_VT(pvalue) != VT_BOOL) | 
|---|
| 743 | { | 
|---|
| 744 | _ASSERTE(! "Invalid Variant Type value!"); | 
|---|
| 745 | IfFailGo(E_INVALIDARG); | 
|---|
| 746 | } | 
|---|
| 747 | m_OptionValue.m_GenerateTCEAdapters = V_BOOL(pvalue); | 
|---|
| 748 | } | 
|---|
| 749 | else if (optionid == MetaDataTypeLibImportNamespace) | 
|---|
| 750 | {   // Note: This is not used in CLR sources anymore, keep it here for backward-compat | 
|---|
| 751 | if (V_VT(pvalue) != VT_BSTR && V_VT(pvalue) != VT_EMPTY && V_VT(pvalue) != VT_NULL) | 
|---|
| 752 | { | 
|---|
| 753 | _ASSERTE(! "Invalid Variant Type value for namespace."); | 
|---|
| 754 | IfFailGo(E_INVALIDARG); | 
|---|
| 755 | } | 
|---|
| 756 | } | 
|---|
| 757 | #endif //FEATURE_METADATA_EMIT_ALL || FEATURE_METADATA_EMIT_IN_DEBUGGER | 
|---|
| 758 | else if (optionid == MetaDataRuntimeVersion) | 
|---|
| 759 | { | 
|---|
| 760 | if (V_VT(pvalue) != VT_BSTR && V_VT(pvalue) != VT_EMPTY && V_VT(pvalue) != VT_NULL) | 
|---|
| 761 | { | 
|---|
| 762 | _ASSERTE(! "Invalid Variant Type value for version."); | 
|---|
| 763 | IfFailGo(E_INVALIDARG); | 
|---|
| 764 | } | 
|---|
| 765 | if (m_OptionValue.m_RuntimeVersion) | 
|---|
| 766 | delete [] m_OptionValue.m_RuntimeVersion; | 
|---|
| 767 |  | 
|---|
| 768 | if ((V_VT(pvalue) == VT_EMPTY) || (V_VT(pvalue) == VT_NULL) || (*V_BSTR(pvalue) == 0)) | 
|---|
| 769 | { | 
|---|
| 770 | m_OptionValue.m_RuntimeVersion = NULL; | 
|---|
| 771 | } | 
|---|
| 772 | else | 
|---|
| 773 | { | 
|---|
| 774 | INT32 len = WszWideCharToMultiByte(CP_UTF8, 0, V_BSTR(pvalue), -1, NULL, 0, NULL, NULL); | 
|---|
| 775 | m_OptionValue.m_RuntimeVersion = new (nothrow) char[len]; | 
|---|
| 776 | if (m_OptionValue.m_RuntimeVersion == NULL) | 
|---|
| 777 | IfFailGo(E_INVALIDARG); | 
|---|
| 778 | WszWideCharToMultiByte(CP_UTF8, 0, V_BSTR(pvalue), -1, m_OptionValue.m_RuntimeVersion, len, NULL, NULL); | 
|---|
| 779 | } | 
|---|
| 780 | } | 
|---|
| 781 | else if (optionid == MetaDataInitialSize) | 
|---|
| 782 | { | 
|---|
| 783 | if (V_VT(pvalue) != VT_UI4) | 
|---|
| 784 | { | 
|---|
| 785 | _ASSERTE(! "Invalid Variant Type value!"); | 
|---|
| 786 | IfFailGo(E_INVALIDARG); | 
|---|
| 787 | } | 
|---|
| 788 | m_OptionValue.m_InitialSize = V_UI4(pvalue); | 
|---|
| 789 | } | 
|---|
| 790 | else if (optionid == MetaDataPreserveLocalRefs) | 
|---|
| 791 | { | 
|---|
| 792 | if (V_VT(pvalue) != VT_UI4) | 
|---|
| 793 | { | 
|---|
| 794 | _ASSERTE(! "Invalid Variant Type value!"); | 
|---|
| 795 | IfFailGo(E_INVALIDARG); | 
|---|
| 796 | } | 
|---|
| 797 |  | 
|---|
| 798 | m_OptionValue.m_LocalRefPreservation = (CorLocalRefPreservation) V_UI4(pvalue); | 
|---|
| 799 | } | 
|---|
| 800 | else | 
|---|
| 801 | { | 
|---|
| 802 | _ASSERTE(! "Invalid GUID"); | 
|---|
| 803 | IfFailGo(E_INVALIDARG); | 
|---|
| 804 | } | 
|---|
| 805 |  | 
|---|
| 806 | ErrExit: | 
|---|
| 807 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 808 | return hr; | 
|---|
| 809 | } // Disp::SetOption | 
|---|
| 810 |  | 
|---|
| 811 | //***************************************************************************** | 
|---|
| 812 | // This routine provides the user a way to set certain properties on the | 
|---|
| 813 | // Dispenser. | 
|---|
| 814 | // | 
|---|
| 815 | // Implements public API code:IMetaDataDispenserEx::GetOption. | 
|---|
| 816 | //***************************************************************************** | 
|---|
| 817 | HRESULT Disp::GetOption(                // Return code. | 
|---|
| 818 | REFGUID     optionid,               // [in] GUID for the option to be set. | 
|---|
| 819 | VARIANT *pvalue)                    // [out] Value to which the option is currently set. | 
|---|
| 820 | { | 
|---|
| 821 | HRESULT hr = S_OK; | 
|---|
| 822 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 823 |  | 
|---|
| 824 | LOG((LF_METADATA, LL_INFO10, "Disp::GetOption(0x%08x, 0x%08x)\n", optionid, pvalue)); | 
|---|
| 825 |  | 
|---|
| 826 | _ASSERTE(pvalue); | 
|---|
| 827 | if (optionid == MetaDataCheckDuplicatesFor) | 
|---|
| 828 | { | 
|---|
| 829 | V_VT(pvalue) = VT_UI4; | 
|---|
| 830 | V_UI4(pvalue) = m_OptionValue.m_DupCheck; | 
|---|
| 831 | } | 
|---|
| 832 | else if (optionid == MetaDataRefToDefCheck) | 
|---|
| 833 | { | 
|---|
| 834 | V_VT(pvalue) = VT_UI4; | 
|---|
| 835 | V_UI4(pvalue) = m_OptionValue.m_RefToDefCheck; | 
|---|
| 836 | } | 
|---|
| 837 | else if (optionid == MetaDataErrorIfEmitOutOfOrder) | 
|---|
| 838 | { | 
|---|
| 839 | V_VT(pvalue) = VT_UI4; | 
|---|
| 840 | V_UI4(pvalue) = m_OptionValue.m_ErrorIfEmitOutOfOrder; | 
|---|
| 841 | } | 
|---|
| 842 | // Note: mscordbi had all these options accessible in 3.5/4.0 RTM, let's keep it this way for AppCompat. | 
|---|
| 843 | #if defined(FEATURE_METADATA_EMIT_ALL) || defined(FEATURE_METADATA_EMIT_IN_DEBUGGER) | 
|---|
| 844 | else if (optionid == MetaDataNotificationForTokenMovement) | 
|---|
| 845 | {   // Note: This is not used in CLR sources anymore, but we store the value and return it here, | 
|---|
| 846 | // so we keep it for backward-compat. | 
|---|
| 847 | V_VT(pvalue) = VT_UI4; | 
|---|
| 848 | V_UI4(pvalue) = m_OptionValue.m_NotifyRemap; | 
|---|
| 849 | } | 
|---|
| 850 | else if (optionid == MetaDataSetENC) | 
|---|
| 851 | {   // EnC update mode (also aliased as code:MetaDataSetUpdate) | 
|---|
| 852 | V_VT(pvalue) = VT_UI4; | 
|---|
| 853 | V_UI4(pvalue) = m_OptionValue.m_UpdateMode; | 
|---|
| 854 | } | 
|---|
| 855 | else if (optionid == MetaDataLinkerOptions) | 
|---|
| 856 | {   // Allows enumeration of EnC deleted items by Import API | 
|---|
| 857 | V_VT(pvalue) = VT_BOOL; | 
|---|
| 858 | V_UI4(pvalue) = m_OptionValue.m_LinkerOption; | 
|---|
| 859 | } | 
|---|
| 860 | else if (optionid == MetaDataGenerateTCEAdapters) | 
|---|
| 861 | {   // Note: This is not used in CLR sources anymore, but we store the value and return it here, | 
|---|
| 862 | // so we keep it for backward-compat. | 
|---|
| 863 | V_VT(pvalue) = VT_BOOL; | 
|---|
| 864 | V_BOOL(pvalue) = m_OptionValue.m_GenerateTCEAdapters; | 
|---|
| 865 | } | 
|---|
| 866 | #endif //FEATURE_METADATA_EMIT_ALL || FEATURE_METADATA_EMIT_IN_DEBUGGER | 
|---|
| 867 | else | 
|---|
| 868 | { | 
|---|
| 869 | _ASSERTE(! "Invalid GUID"); | 
|---|
| 870 | IfFailGo(E_INVALIDARG); | 
|---|
| 871 | } | 
|---|
| 872 | ErrExit: | 
|---|
| 873 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 874 |  | 
|---|
| 875 | return hr; | 
|---|
| 876 | } // Disp::GetOption | 
|---|
| 877 |  | 
|---|
| 878 | #if defined(FEATURE_METADATA_IN_VM) | 
|---|
| 879 |  | 
|---|
| 880 | //--------------------------------------------------------------------------------------- | 
|---|
| 881 | // | 
|---|
| 882 | // Process detach destruction. | 
|---|
| 883 | // Called from DllMain of clr.dll/RoMetadata.dll/MidlrtMd.dll. | 
|---|
| 884 | // | 
|---|
| 885 | void DeleteMetaData() | 
|---|
| 886 | { | 
|---|
| 887 | LOADEDMODULES::DeleteStatics(); | 
|---|
| 888 | } | 
|---|
| 889 |  | 
|---|
| 890 | #endif //FEATURE_METADATA_IN_VM | 
|---|
| 891 |  | 
|---|
| 892 | // | 
|---|
| 893 | // This is the entrypoint for usages of MetaData that need to start with the dispenser (e.g. | 
|---|
| 894 | // mscordbi.dll and profiling API). | 
|---|
| 895 | // | 
|---|
| 896 | // Notes: | 
|---|
| 897 | //    This could be merged with the class factory support. | 
|---|
| 898 | HRESULT InternalCreateMetaDataDispenser(REFIID riid, void ** pMetaDataDispenserOut) | 
|---|
| 899 | { | 
|---|
| 900 | _ASSERTE(pMetaDataDispenserOut != NULL); | 
|---|
| 901 | return Disp::CreateObject(riid, pMetaDataDispenserOut); | 
|---|
| 902 | } | 
|---|
| 903 |  | 
|---|