Skip to content

Commit

Permalink
Add DNMD API to create a new metadata handle and implement IMetaDataD…
Browse files Browse the repository at this point in the history
…ispenser::DefineScope (#49)

Co-authored-by: Aaron Robinson <[email protected]>
  • Loading branch information
jkoritzinsky and AaronRobinsonMSFT authored Jan 18, 2024
1 parent e727af4 commit 56371fb
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 5 deletions.
113 changes: 113 additions & 0 deletions src/dnmd/entry.c
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,119 @@ bool md_create_handle(void const* data, size_t data_len, mdhandle_t* handle)
return true;
}

// Initialize the minimal set of tables required for a valid metadata image.
// Every image must have a row in the Module table
// for module identity information
// and a row in the TypeDef table for the global type.
static bool initialize_minimal_table_rows(mdcxt_t* cxt)
{
// Add the Module row for module identity
mdcursor_t module_cursor;
if (!md_append_row(cxt, mdtid_Module, &module_cursor))
return false;

// Set the Generation to 0
uint32_t generation = 0;
if (1 != md_set_column_value_as_constant(module_cursor, mdtModule_Generation, 1, &generation))
return false;

// Use the 0 index to specify the NULL guid as the guids for the image.
uint32_t guid_heap_offset = 0;
if (1 != set_column_value_as_heap_offset(module_cursor, mdtModule_Mvid, 1, &guid_heap_offset)
|| 1 != set_column_value_as_heap_offset(module_cursor, mdtModule_EncBaseId, 1, &guid_heap_offset)
|| 1 != set_column_value_as_heap_offset(module_cursor, mdtModule_EncId, 1, &guid_heap_offset))
{
return false;
}

char const* name = "";
if (1 != md_set_column_value_as_utf8(module_cursor, mdtModule_Name, 1, &name))
return false;

// Mark that we're done adding the Module row.
md_commit_row_add(module_cursor);

// Add a row for the global <Module> type.
mdcursor_t global_type_cursor;
if (!md_append_row(cxt, mdtid_TypeDef, &global_type_cursor))
return false;

uint32_t flags = 0;
if (1 != md_set_column_value_as_constant(global_type_cursor, mdtTypeDef_Flags, 1, &flags))
return false;

char const* global_type_name = "<Module>"; // Defined in ECMA-335 II.10.8
if (1 != md_set_column_value_as_utf8(global_type_cursor, mdtTypeDef_TypeName, 1, &global_type_name))
return false;

char const* namespace = "";
if (1 != md_set_column_value_as_utf8(global_type_cursor, mdtTypeDef_TypeNamespace, 1, &namespace))
return false;

mdToken nil_typedef = CreateTokenType(mdtTypeDef);
if (1 != md_set_column_value_as_token(global_type_cursor, mdtTypeDef_Extends, 1, &nil_typedef))
return false;

// Mark that we're done adding the TypeDef row.
md_commit_row_add(global_type_cursor);

return true;
}

mdhandle_t md_create_new_handle()
{
mdcxt_t cxt;

memset(&cxt, 0, sizeof(mdcxt_t));
cxt.magic = MDLIB_MAGIC_NUMBER;
cxt.context_flags = mdc_none;
cxt.major_ver = 1;
cxt.minor_ver = 1;
cxt.flags = 0;
cxt.version = "v4.0.30319";
cxt.editor = NULL;
cxt.mem = NULL;

// Allocate and initialize a full context
// with the correctly-sized trailing memory.
mdcxt_t* pcxt = allocate_full_context(&cxt);
if (pcxt == NULL)
return NULL;

if (!initialize_minimal_table_rows(pcxt))
{
free(pcxt);
return NULL;
}

return pcxt;
}

#ifdef DNMD_PORTABLE_PDB
mdhandle_t md_create_new_pdb_handle()
{
mdcxt_t cxt;

memset(&cxt, 0, sizeof(mdcxt_t));
cxt.magic = MDLIB_MAGIC_NUMBER;
cxt.context_flags = mdc_none;
cxt.major_ver = 1;
cxt.minor_ver = 1;
cxt.flags = 0;
cxt.version = "PDB v1.0";
cxt.editor = NULL;
cxt.mem = NULL;

// Allocate and initialize a full context
// with the correctly-sized trailing memory.
mdcxt_t* pcxt = allocate_full_context(&cxt);
if (pcxt == NULL)
return NULL;

return pcxt;
}
#endif // DNMD_PORTABLE_PDB

bool md_apply_delta(mdhandle_t handle, void const* data, size_t data_len)
{
mdcxt_t* base = extract_mdcxt(handle);
Expand Down
17 changes: 17 additions & 0 deletions src/inc/dnmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,21 @@ typedef void* mdhandle_t;
// If modifications are made, the data will not be updated in place.
bool md_create_handle(void const* data, size_t data_len, mdhandle_t* handle);

// Create a new metadata handle for a new image.
// Returns a handle for the new image, or NULL if the handle could not be created.
// The image will always be in the v1.1 ECMA-355 metadata format,
// use the "v4.0.30319" version string,
// and have an MVID of all zeros.
mdhandle_t md_create_new_handle();

#ifdef DNMD_PORTABLE_PDB
// Create a new metadata handle for a new Portable PDB image.
// Returns a handle for the new image, or NULL if the handle could not be created.
// The image will always be in the v1.1 metadata format
// and use the "PDB v1.0" version string.
mdhandle_t md_create_new_pdb_handle();
#endif // DNMD_PORTABLE_PDB

// Apply delta data to the current metadata.
bool md_apply_delta(mdhandle_t handle, void const* data, size_t data_len);

Expand Down Expand Up @@ -528,6 +543,8 @@ void md_commit_row_add(mdcursor_t row);
// Add a user string to the #US heap.
mduserstringcursor_t md_add_userstring_to_heap(mdhandle_t handle, char16_t const* userstring);

// Write the metadata represented by the handle to the supplied buffer.
// The metadata is always written with the v2.0 table schema.
bool md_write_to_buffer(mdhandle_t handle, uint8_t* buffer, size_t* len);
#ifdef __cplusplus
}
Expand Down
49 changes: 44 additions & 5 deletions src/interfaces/dispenser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,50 @@ namespace
REFIID riid,
IUnknown** ppIUnk)
{
UNREFERENCED_PARAMETER(rclsid);
UNREFERENCED_PARAMETER(dwCreateFlags);
UNREFERENCED_PARAMETER(riid);
UNREFERENCED_PARAMETER(ppIUnk);
return E_NOTIMPL;
if (rclsid != CLSID_CLR_v2_MetaData)
{
// DNMD::Interfaces only creating v2 metadata images.
return CLDB_E_FILE_OLDVER;
}

if (dwCreateFlags != 0)
{
return E_INVALIDARG;
}

mdhandle_ptr md_ptr { md_create_new_handle() };
if (md_ptr == nullptr)
return E_OUTOFMEMORY;

// Initialize the MVID of the new image.
mdcursor_t moduleCursor;
if (!md_token_to_cursor(md_ptr.get(), TokenFromRid(1, mdtModule), &moduleCursor))
return E_FAIL;

mdguid_t mvid;
HRESULT hr = PAL_CoCreateGuid(reinterpret_cast<GUID*>(&mvid));
if (FAILED(hr))
return hr;

if (1 != md_set_column_value_as_guid(moduleCursor, mdtModule_Mvid, 1, &mvid))
return E_OUTOFMEMORY;

dncp::com_ptr<ControllingIUnknown> obj;
obj.Attach(new (std::nothrow) ControllingIUnknown());
if (obj == nullptr)
return E_OUTOFMEMORY;

try
{
mdhandle_view handle_view{ obj->CreateAndAddTearOff<DNMDOwner>(std::move(md_ptr)) };
(void)obj->CreateAndAddTearOff<MetadataImportRO>(std::move(handle_view));
}
catch(std::bad_alloc const&)
{
return E_OUTOFMEMORY;
}

return obj->QueryInterface(riid, (void**)ppIUnk);
}

STDMETHOD(OpenScope)(
Expand Down
7 changes: 7 additions & 0 deletions src/interfaces/dnmdowner.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ class DNMDOwner final : public TearOffBase<IDNMDOwner>
}

public:
DNMDOwner(IUnknown* controllingUnknown, mdhandle_ptr md_ptr)
: TearOffBase(controllingUnknown)
, _handle{ std::move(md_ptr) }
, _malloc_to_free{ nullptr }
, _cotaskmem_to_free{ nullptr }
{ }

DNMDOwner(IUnknown* controllingUnknown, mdhandle_ptr md_ptr, malloc_ptr<void> mallocMem, dncp::cotaskmem_ptr<void> cotaskmemMem)
: TearOffBase(controllingUnknown)
, _handle{ std::move(md_ptr) }
Expand Down
3 changes: 3 additions & 0 deletions src/interfaces/iids.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,8 @@ MIDL_DEFINE_GUID(IID_IMetaDataEmit2, 0xf5dd9950, 0xf693, 0x42e6, 0x83, 0xe, 0x7b
// Define the ISymUnmanaged* IIDs here - corsym.h provides the declaration.
MIDL_DEFINE_GUID(IID_ISymUnmanagedBinder, 0xaa544d42, 0x28cb, 0x11d3, 0xbd, 0x22, 0x00, 0x00, 0xf8, 0x08, 0x49, 0xbd);

// Define option IIDs here - cor.h provides the declaration.
MIDL_DEFINE_GUID(CLSID_CLR_v2_MetaData, 0xefea471a, 0x44fd, 0x4862, 0x92, 0x92, 0xc, 0x58, 0xd4, 0x6e, 0x1f, 0x3a);

// Define an IID for our own marker interface
MIDL_DEFINE_GUID(IID_IDNMDOwner, 0x250ebc02, 0x1a92, 0x4638, 0xaa, 0x6c, 0x3d, 0x0f, 0x98, 0xb3, 0xa6, 0xfb);

0 comments on commit 56371fb

Please sign in to comment.