Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DNMD API to create a new metadata handle and implement IMetaDataDispenser::DefineScope #49

Merged
merged 10 commits into from
Jan 18, 2024
Merged
83 changes: 83 additions & 0 deletions src/dnmd/entry.c
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,89 @@ 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)
{
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;
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved

const char* name = "";
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
if (1 != md_set_column_value_as_utf8(module_cursor, mdtModule_Name, 1, &name))
return false;

md_commit_row_add(module_cursor);

mdcursor_t global_type_cursor;
if (!md_append_row(cxt, mdtid_TypeDef, &global_type_cursor))
return false;
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved

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

const char* global_type_name = "<Module>";
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
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;

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 = 2;
cxt.minor_ver = 0;
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;
}

jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved

bool md_apply_delta(mdhandle_t handle, void const* data, size_t data_len)
{
mdcxt_t* base = extract_mdcxt(handle);
Expand Down
7 changes: 7 additions & 0 deletions src/inc/dnmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ 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 v2.0 metadata format,
// use the "v4.0.30319" version string,
// and have an MVID of all zeros.
mdhandle_t md_create_new_handle();

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

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);