-- v2: dlls/rometadata: Add stub for IMetaDataTables.
From: Vibhav Pant vibhavp@gmail.com
--- tools/makedep.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/tools/makedep.c b/tools/makedep.c index 7e33df2432a..99a33f08dfe 100644 --- a/tools/makedep.c +++ b/tools/makedep.c @@ -1513,6 +1513,7 @@ static struct file *open_include_file( const struct makefile *make, struct incl_ if ((file = open_local_generated_file( make, pFile, ".ico", ".svg" ))) return file; } if ((file = open_local_generated_file( make, pFile, "-client-protocol.h", ".xml" ))) return file; + if ((file = open_local_generated_file( make, pFile, ".winmd", ".idl" ))) return file;
/* check for extra targets */ if (strarray_exists( make->extra_targets, pFile->name ))
From: Vibhav Pant vibhavp@gmail.com
--- dlls/rometadata/Makefile.in | 3 +- dlls/rometadata/main.c | 18 +- dlls/rometadata/mdtables.c | 230 ++++++++++++++++ dlls/rometadata/rometadatapriv.h | 24 ++ dlls/rometadata/tests/Makefile.in | 4 +- dlls/rometadata/tests/rometadata.c | 380 ++++++++++++++++++++++++++ dlls/rometadata/tests/rsrc.rc | 20 ++ dlls/rometadata/tests/test-simple.idl | 51 ++++ include/Makefile.in | 1 + include/rometadataapi.idl | 69 +++++ 10 files changed, 796 insertions(+), 4 deletions(-) create mode 100644 dlls/rometadata/mdtables.c create mode 100644 dlls/rometadata/rometadatapriv.h create mode 100644 dlls/rometadata/tests/rsrc.rc create mode 100644 dlls/rometadata/tests/test-simple.idl create mode 100644 include/rometadataapi.idl
diff --git a/dlls/rometadata/Makefile.in b/dlls/rometadata/Makefile.in index 7a9940a79d1..52c39ba8f87 100644 --- a/dlls/rometadata/Makefile.in +++ b/dlls/rometadata/Makefile.in @@ -3,4 +3,5 @@ IMPORTLIB = rometadata IMPORTS = combase
SOURCES = \ - main.c + main.c \ + mdtables.c diff --git a/dlls/rometadata/main.c b/dlls/rometadata/main.c index 2530cdf84e0..6cded07c11f 100644 --- a/dlls/rometadata/main.c +++ b/dlls/rometadata/main.c @@ -21,8 +21,11 @@ #include "objbase.h" #include "cor.h" #include "rometadata.h" +#include "rometadataapi.h" #include "wine/debug.h"
+#include "rometadatapriv.h" + WINE_DEFAULT_DEBUG_CHANNEL(rometadata);
struct metadata_dispenser @@ -87,8 +90,19 @@ static HRESULT WINAPI MetaDataDispenser_DefineScope(IMetaDataDispenserEx *iface, static HRESULT WINAPI MetaDataDispenser_OpenScope(IMetaDataDispenserEx *iface, const WCHAR *scope, DWORD open_flags, REFIID riid, IUnknown **obj) { - FIXME("%p %s %lx %s %p\n", iface, debugstr_w(scope), open_flags, debugstr_guid(riid), obj); - return E_NOTIMPL; + IMetaDataTables *tables; + HRESULT hr; + + FIXME("%p %s %lx %s %p semi-stub!\n", iface, debugstr_w(scope), open_flags, debugstr_guid(riid), obj); + + *obj = NULL; + hr = IMetaDataTables_create(&tables); + if (FAILED(hr)) + return hr; + + hr = IMetaDataTables_QueryInterface(tables, riid, (void **)obj); + IMetaDataTables_Release(tables); + return hr; }
static HRESULT WINAPI MetaDataDispenser_OpenScopeOnMemory(IMetaDataDispenserEx *iface, const void *data, diff --git a/dlls/rometadata/mdtables.c b/dlls/rometadata/mdtables.c new file mode 100644 index 00000000000..d3ba77a91ba --- /dev/null +++ b/dlls/rometadata/mdtables.c @@ -0,0 +1,230 @@ +/* + * IMetaDataTables implementation + * + * Copyright 2025 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS +#include "objbase.h" +#include "cor.h" +#include "rometadataapi.h" +#include "wine/debug.h" + +#include "rometadatapriv.h" + +WINE_DEFAULT_DEBUG_CHANNEL(rometadata); + +struct metadata_tables +{ + IMetaDataTables IMetaDataTables_iface; + LONG ref; +}; + +static inline struct metadata_tables *impl_from_IMetaDataTables(IMetaDataTables *iface) +{ + return CONTAINING_RECORD(iface, struct metadata_tables, IMetaDataTables_iface); +} + +static HRESULT WINAPI tables_QueryInterface(IMetaDataTables *iface, REFIID iid, void **out) +{ + TRACE("(%p, %s, %p)\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(&IID_IUnknown, iid) || IsEqualGUID(&IID_IMetaDataTables, iid)) + { + IMetaDataTables_AddRef((*out = iface)); + return S_OK; + } + + FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI tables_AddRef(IMetaDataTables *iface) +{ + struct metadata_tables *impl = impl_from_IMetaDataTables(iface); + ULONG ref = InterlockedIncrement(&impl->ref); + + TRACE("(%p)\n", impl); + + return ref; +} + +static ULONG WINAPI tables_Release(IMetaDataTables *iface) +{ + struct metadata_tables *impl = impl_from_IMetaDataTables(iface); + ULONG ref = InterlockedDecrement(&impl->ref); + + TRACE("(%p)\n", iface); + + if (!ref) free(impl); + return ref; +} + +static HRESULT WINAPI tables_GetStringHeapSize(IMetaDataTables *iface, ULONG *size) +{ + FIXME("(%p, %p): stub!\n", iface, size); + return E_NOTIMPL; +} + +static HRESULT WINAPI tables_GetBlobHeapSize(IMetaDataTables *iface, ULONG *size) +{ + FIXME("(%p, %p): stub!\n", iface, size); + return E_NOTIMPL; +} + +static HRESULT WINAPI tables_GetGuidHeapSize(IMetaDataTables *iface, ULONG *size) +{ + FIXME("(%p, %p): stub!\n", iface, size); + return E_NOTIMPL; +} + +static HRESULT WINAPI tables_GetUserStringHeapSize(IMetaDataTables *iface, ULONG *size) +{ + FIXME("(%p, %p): stub!\n", iface, size); + return E_NOTIMPL; +} + +static HRESULT WINAPI tables_GetNumTables(IMetaDataTables *iface, ULONG *size) +{ + FIXME("(%p, %p): stub!\n", iface, size); + return E_NOTIMPL; +} + +static HRESULT WINAPI tables_GetTableIndex(IMetaDataTables *iface, ULONG token, ULONG *idx) +{ + FIXME("(%p %lu %p): stub!\n", iface, token, idx); + return E_NOTIMPL; +} + +static HRESULT WINAPI tables_GetTableInfo(IMetaDataTables *iface, ULONG idx_tbl, ULONG *row_size, ULONG *num_rows, + ULONG *num_cols, ULONG *idx_key, const char **name) +{ + FIXME("(%p, %lu, %p, %p, %p, %p, %p): stub!\n", iface, idx_tbl, row_size, num_rows, num_cols, idx_key, name); + return E_NOTIMPL; +} + +static HRESULT WINAPI tables_GetColumnInfo(IMetaDataTables *iface, ULONG idx_tbl, ULONG idx_col, ULONG *offset, + ULONG *col_size, ULONG *type, const char **name) +{ + FIXME("(%p, %lu, %lu, %p, %p, %p, %p) stub!\n", iface, idx_tbl, idx_col, offset, col_size, type, name); + return E_NOTIMPL; +} + +static HRESULT WINAPI tables_GetCodedTokenInfo(IMetaDataTables *iface, ULONG type, ULONG *tokens_len, + const ULONG **tokens, const char **name) +{ + FIXME("(%p, %lu, %p, %p, %p) stub!\n", iface, type, tokens_len, tokens, name); + return E_NOTIMPL; +} + +static HRESULT WINAPI tables_GetRow(IMetaDataTables *iface, ULONG idx_tbl, ULONG idx_row, const BYTE *row) +{ + FIXME("(%p, %lu, %lu, %p): stub!\n", iface, idx_tbl, idx_row, row); + return E_NOTIMPL; +} + +static HRESULT WINAPI tables_GetColumn(IMetaDataTables *iface, ULONG idx_tbl, ULONG idx_col, ULONG idx_row, ULONG *val) +{ + FIXME("(%p, %lu, %lu, %lu, %p): stub!\n", iface, idx_tbl, idx_col, idx_row, val); + return E_NOTIMPL; +} + +static HRESULT WINAPI tables_GetString(IMetaDataTables *iface, ULONG idx, const char **str) +{ + FIXME("(%p, %lu, %p): stub!\n", iface, idx, str); + return E_NOTIMPL; +} + +static HRESULT WINAPI tables_GetBlob(IMetaDataTables *iface, ULONG idx, ULONG *size, const BYTE **blob) +{ + FIXME("(%p, %lu, %p, %p): stub!\n", iface, idx, size, blob); + return E_NOTIMPL; +} + +static HRESULT WINAPI tables_GetGuid(IMetaDataTables *iface, ULONG idx, const GUID **guid) +{ + FIXME("(%p, %lu, %p): stub!\n", iface, idx, guid); + return E_NOTIMPL; +} + +static HRESULT WINAPI tables_GetUserString(IMetaDataTables *iface, ULONG idx, ULONG *size, const BYTE **string) +{ + FIXME("%p %lu %p %p stub!\n", iface, idx, size, string); + return E_NOTIMPL; +} + +static HRESULT WINAPI tables_GetNextString(IMetaDataTables *iface, ULONG idx, ULONG *next) +{ + FIXME("(%p, %lu, %p): stub!\n", iface, idx, next); + return E_NOTIMPL; +} + +static HRESULT WINAPI tables_GetNextBlob(IMetaDataTables *iface, ULONG idx, ULONG *next) +{ + FIXME("(%p, %lu, %p): stub!\n", iface, idx, next); + return E_NOTIMPL; +} + +static HRESULT WINAPI tables_GetNextGuid(IMetaDataTables *iface, ULONG idx, ULONG *next) +{ + FIXME("(%p, %lu, %p): stub!\n", iface, idx, next); + return E_NOTIMPL; +} + +static HRESULT WINAPI tables_GetNextUserString(IMetaDataTables *iface, ULONG idx, ULONG *next) +{ + FIXME("(%p, %lu, %p): stub!\n", iface, idx, next); + return E_NOTIMPL; +} + +static const struct IMetaDataTablesVtbl tables_vtbl = +{ + tables_QueryInterface, + tables_AddRef, + tables_Release, + tables_GetStringHeapSize, + tables_GetBlobHeapSize, + tables_GetGuidHeapSize, + tables_GetUserStringHeapSize, + tables_GetNumTables, + tables_GetTableIndex, + tables_GetTableInfo, + tables_GetColumnInfo, + tables_GetCodedTokenInfo, + tables_GetRow, + tables_GetColumn, + tables_GetString, + tables_GetBlob, + tables_GetGuid, + tables_GetUserString, + tables_GetNextString, + tables_GetNextBlob, + tables_GetNextGuid, + tables_GetNextUserString, +}; + +HRESULT IMetaDataTables_create( IMetaDataTables **iface ) +{ + struct metadata_tables *impl; + + impl = calloc( 1, sizeof( *impl ) ); + if (!impl) return E_OUTOFMEMORY; + impl->IMetaDataTables_iface.lpVtbl = &tables_vtbl; + impl->ref = 1; + *iface = &impl->IMetaDataTables_iface; + return S_OK; +} diff --git a/dlls/rometadata/rometadatapriv.h b/dlls/rometadata/rometadatapriv.h new file mode 100644 index 00000000000..e6ff2ada18a --- /dev/null +++ b/dlls/rometadata/rometadatapriv.h @@ -0,0 +1,24 @@ +/* + * Copyright 2025 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_ROMETADATA_PRIVATE__ +#define __WINE_ROMETADATA_PRIVATE__ + +extern HRESULT IMetaDataTables_create(IMetaDataTables **iface); + +#endif /* __WINE_ROMETADATA_PRIVATE__ */ diff --git a/dlls/rometadata/tests/Makefile.in b/dlls/rometadata/tests/Makefile.in index 58813aefc54..d70008507b6 100644 --- a/dlls/rometadata/tests/Makefile.in +++ b/dlls/rometadata/tests/Makefile.in @@ -2,4 +2,6 @@ TESTDLL = rometadata.dll IMPORTS = combase rometadata
SOURCES = \ - rometadata.c + rometadata.c \ + rsrc.rc \ + test-simple.idl \ No newline at end of file diff --git a/dlls/rometadata/tests/rometadata.c b/dlls/rometadata/tests/rometadata.c index b4adcd90286..53fc2c415d4 100644 --- a/dlls/rometadata/tests/rometadata.c +++ b/dlls/rometadata/tests/rometadata.c @@ -22,8 +22,12 @@ #include "cor.h" #include "roapi.h" #include "rometadata.h" +#include "rometadataapi.h" #include "wine/test.h"
+#define WIDL_using_Wine_Test +#include "test-simple.h" + DEFINE_GUID(GUID_NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
static void test_MetaDataGetDispenser(void) @@ -57,6 +61,381 @@ static void test_MetaDataGetDispenser(void) IMetaDataDispenserEx_Release(dispenser_ex); }
+static WCHAR *load_resource(const WCHAR *name) +{ + static WCHAR pathW[MAX_PATH]; + DWORD written; + HANDLE file; + HRSRC res; + void *ptr; + + GetTempPathW(ARRAY_SIZE(pathW), pathW); + wcscat(pathW, name); + + file = CreateFileW(pathW, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "Failed to create file %s, error %lu.\n", + wine_dbgstr_w(pathW), GetLastError()); + + res = FindResourceW(NULL, name, (LPCWSTR)RT_RCDATA); + ok(!!res, "Failed to load resource, error %lu.\n", GetLastError()); + ptr = LockResource(LoadResource(GetModuleHandleA(NULL), res)); + WriteFile(file, ptr, SizeofResource( GetModuleHandleA(NULL), res), &written, NULL); + ok(written == SizeofResource(GetModuleHandleA(NULL), res), "Failed to write resource.\n"); + CloseHandle(file); + + return pathW; +} + +struct row_module +{ + WORD Generation; + WORD Name; + WORD Mvid; + WORD EncId; + WORD EncBaseId; +}; + +struct row_typeref +{ + WORD ResolutionScope; + WORD Name; + WORD Namespace; +}; + +struct row_typedef +{ + DWORD Flags; + WORD Name; + WORD Namespace; + WORD Extends; + WORD FieldList; + WORD MethodList; +}; + +struct row_memberref +{ + WORD Class; + WORD Name; + WORD Signature; +}; + +struct row_custom_attribute +{ + WORD Parent; + WORD Type; + WORD Value; +}; + +#define TYPE_VISIBILITY_PUBLIC 0x00000001 + +#define TYPE_SEMANTICS_CLASS 0x00000000 +#define TYPE_SEMANTICS_INTERFACE 0x00000020 + +#define TYPE_ABSTRACT 0x00000080 +#define TYPE_SEALED 0x00000100 +#define TYPE_IMPORTED 0x00001000 +#define TYPE_WINRT 0x00004000 + +enum class_semantics +{ + CLASS_SEMANTICS_CLASS = 0, + CLASS_SEMANTICS_INTERFACE = 0x00000020, +}; + +struct table_info +{ + ULONG exp_row_size; + ULONG exp_rows; + ULONG exp_cols; + ULONG exp_key_idx; + const char *exp_name; +}; + +struct type_info +{ + DWORD exp_flags; + const char *exp_name; + const char *exp_namespace; +}; + +#define TableFromToken(tk) (TypeFromToken(tk) >> 24) + +static void test_MetaDataDispenser_OpenScope(void) +{ + static const struct table_info tables[45] = { + {10, 1, 5, -1, "Module"}, + {6, 10, 3, -1, "TypeRef"}, + {14, 3, 6, -1, "TypeDef"}, + {2, 0, 1, -1, "FieldPtr"}, + {6, 0, 3, -1, "Field"}, + {2, 0, 1, -1, "MethodPtr"}, + {14, 2, 6, -1, "Method"}, + {2, 0, 1, -1, "ParamPtr"}, + {6, 0, 3, -1, "Param"}, + {4, 1, 2, 0, "InterfaceImpl"}, + {6, 6, 3, -1, "MemberRef"}, + {6, 0, 3, 1, "Constant"}, + {6, 7, 3, 0, "CustomAttribute"}, + {4, 0, 2, 0, "FieldMarshal"}, + {6, 0, 3, 1, "DeclSecurity"}, + {8, 0, 3, 2, "ClassLayout"}, + {6, 0, 2, 1, "FieldLayout"}, + {2, 0, 1, -1, "StandAloneSig"}, + {4, 0, 2, -1, "EventMap"}, + {2, 0, 1, -1, "EventPtr"}, + {6, 0, 3, -1, "Event"}, + {4, 0, 2, -1, "PropertyMap"}, + {2, 0, 1, -1, "PropertyPtr"}, + {6, 0, 3, -1, "Property"}, + {6, 0, 3, 2, "MethodSemantics"}, + {6, 1, 3, 0, "MethodImpl"}, + {2, 0, 1, -1, "ModuleRef"}, + {2, 0, 1, -1, "TypeSpec"}, + {8, 0, 4, 1, "ImplMap"}, + {6, 0, 2, 1, "FieldRVA"}, + {8, 0, 2, -1, "ENCLog"}, + {4, 0, 1, -1, "ENCMap"}, + {22, 1, 9, -1, "Assembly"}, + {4, 0, 1, -1, "AssemblyProcessor"}, + {12, 0, 3, -1, "AssemblyOS"}, + {20, 3, 9, -1, "AssemblyRef"}, + {6, 0, 2, -1, "AssemblyRefProcessor"}, + {14, 0, 4, -1, "AssemblyRefOS"}, + {8, 0, 3, -1, "File"}, + {14, 0, 5, -1, "ExportedType"}, + {12, 0, 4, -1, "ManifestResource"}, + {4, 0, 2, 0, "NestedClass"}, + {8, 0, 4, 2, "GenericParam"}, + {4, 0, 2, -1, "MethodSpec"}, + {4, 0, 2, 0, "GenericParamConstraint"}, + }; + static const struct type_info type_defs[3] = + { + { 0, "<Module>", NULL }, + { TYPE_SEMANTICS_INTERFACE | TYPE_ABSTRACT | TYPE_WINRT, "ITest1", "Wine.Test" }, + { TYPE_VISIBILITY_PUBLIC | TYPE_SEALED | TYPE_WINRT, "Test1", "Wine.Test" }, + }; + const WCHAR *filename = load_resource(L"test-simple.winmd"); + ULONG val = 0, i, guid_ctor_idx = 0, itest1_def_idx = 0; + const struct row_typedef *type_def = NULL; + const struct row_module *module = NULL; + IMetaDataDispenser *dispenser; + IMetaDataTables *md_tables; + const GUID *guid = NULL; + const char *str; + HRESULT hr; + + hr = MetaDataGetDispenser(&CLSID_CorMetaDataDispenser, &IID_IMetaDataDispenser, (void **)&dispenser); + ok(hr == S_OK, "got hr %#lx\n", hr); + + hr = IMetaDataDispenser_OpenScope(dispenser, filename, 0, &IID_IMetaDataTables, (IUnknown **)&md_tables); + ok(hr == S_OK, "got hr %#lx\n", hr); + IMetaDataDispenser_Release(dispenser); + + hr = IMetaDataTables_GetStringHeapSize(md_tables, &val); + todo_wine + ok(hr == S_OK, "got hr %#lx\n", hr); + todo_wine + ok(val == 329, "got val %lu\n", val); + + val = 0; + hr = IMetaDataTables_GetBlobHeapSize(md_tables, &val); + todo_wine + ok(hr == S_OK, "got hr %#lx\n", hr); + todo_wine + ok(val == 156, "got val %lu\n", val); + + val = 0; + hr = IMetaDataTables_GetGuidHeapSize(md_tables, &val); + todo_wine + ok(hr == S_OK, "got hr %#lx\n", hr); + todo_wine + ok(val == 16, "got val %lu\n", val); + + val = 0; + hr = IMetaDataTables_GetUserStringHeapSize(md_tables, &val); + todo_wine + ok(hr == S_OK, "got hr %#lx\n", hr); + todo_wine + ok(val == 8, "got val %lu\n", val); + + val = 0; + hr = IMetaDataTables_GetNumTables(md_tables, &val); + todo_wine + ok(hr == S_OK, "got hr %#lx\n", hr); + todo_wine + ok(val == 45, "got val %lu\n", val); + + for (i = 0; i < 45; i++) + { + const struct table_info *table = &tables[i]; + ULONG row_size, rows, cols, key_idx; + const char *name; + + winetest_push_context("tables[%lu]", i); + + hr = IMetaDataTables_GetTableInfo(md_tables, i, &row_size, &rows, &cols, &key_idx, &name); + todo_wine + ok(hr == S_OK, "got hr %#lx\n", hr); + if (FAILED(hr)) + { + winetest_pop_context(); + continue; + } + + todo_wine + ok(row_size == table->exp_row_size, "got row_size %lu != %lu\n", row_size, table->exp_row_size); + todo_wine + ok(rows == table->exp_rows, "got rows %lu != %lu\n", rows, table->exp_rows); + todo_wine + ok(cols == table->exp_cols, "got cols %lu != %lu\n", cols, table->exp_cols); + todo_wine + ok(key_idx == table->exp_key_idx, "got key_idx %lu != %lu\n", key_idx, table->exp_key_idx); + todo_wine + ok(!strcmp(name, table->exp_name), "got name %s != %s\n", debugstr_a(name), debugstr_a(table->exp_name)); + + winetest_pop_context(); + } + + /* Read module information */ + hr = IMetaDataTables_GetRow(md_tables, 0, 1, (BYTE *)&module); + todo_wine + ok(hr == S_OK, "got hr %#lx\n", hr); + todo_wine + ok(!!module, "got module=%p\n", module); + + if (SUCCEEDED(hr)) + { + str = NULL; + hr = IMetaDataTables_GetString(md_tables, module->Name, &str); + ok(hr == S_OK, "got hr %#lx\n", hr); + ok(str &&!strcmp(str, "dlls/rometadata/tests/test-simple.winmd"), "got str %s\n", debugstr_a(str)); + + hr = IMetaDataTables_GetGuid(md_tables, module->Mvid, &guid); + ok(hr == S_OK, "got hr %#lx\n", hr); + ok(!!guid, "got guid %p\n", guid); + } + + /* Read defined types. */ + for (i = 0; i < ARRAY_SIZE(type_defs); i++) + { + const struct type_info *type_info = &type_defs[i]; + + winetest_push_context("type_info[%lu]", i); + + type_def = NULL; + hr = IMetaDataTables_GetRow(md_tables, 2, i + 1, (BYTE *)&type_def); + todo_wine + ok(hr == S_OK, "got hr %#lx\n", hr); + todo_wine + ok(!!type_def, "got type_def=%p\n", type_def); + if (FAILED(hr)) + { + winetest_pop_context(); + continue; + } + + ok(type_def->Flags == type_info->exp_flags, "got Flags %#lx != %#lx\n", type_def->Flags, type_info->exp_flags); + str = NULL; + hr = IMetaDataTables_GetString(md_tables, type_def->Name, &str); + ok(hr == S_OK, "got hr %#lx\n", hr); + ok(str && !strcmp(str, type_info->exp_name), "got str %s != %s\n", debugstr_a(str), + debugstr_a(type_info->exp_name)); + if (type_info->exp_namespace) + { + str = NULL; + hr = IMetaDataTables_GetString(md_tables, type_def->Namespace, &str); + ok(str && !strcmp(str, type_info->exp_namespace), "got str %s != %s\n", debugstr_a(str), + debugstr_a(type_info->exp_namespace)); + if (!strcmp(type_info->exp_name, "ITest1") && !strcmp(type_info->exp_namespace, "Wine.Test")) + itest1_def_idx = ((i + 1) << 5) | 3; + } + + winetest_pop_context(); + } + + /* Get the MemberRef row for the GuidAttribute constructor */ + for (i = 0; i < tables[TableFromToken(mdtMemberRef)].exp_rows; i++) + { + const struct row_memberref *ref = NULL; + + winetest_push_context("i=%lu", i); + + hr = IMetaDataTables_GetRow(md_tables, TableFromToken(mdtMemberRef), i + 1, (BYTE *)&ref); + todo_wine + ok(hr == S_OK, "got hr %#lx\n", hr); + if (FAILED(hr)) + { + winetest_pop_context(); + continue; + } + + hr = IMetaDataTables_GetString(md_tables, ref->Name, &str); + ok(hr == S_OK, "got hr %#lx\n", hr); + if (str && !strcmp(str, ".ctor")) + { + const struct row_typeref *typeref = NULL; + + /* All MemberRefParent coded indices in test-simple.winmd point to TypeRef entries. */ + hr = IMetaDataTables_GetRow(md_tables, TableFromToken(mdtTypeRef), (ref->Class & ~7) >> 3, (BYTE *)&typeref); + ok(hr == S_OK, "got hr %#lx\n", hr); + hr = IMetaDataTables_GetString(md_tables, typeref->Name, &str); + ok(hr == S_OK, "got hr %#lx\n", hr); + if (!strcmp(str, "GuidAttribute")) + { + hr = IMetaDataTables_GetString(md_tables, typeref->Namespace, &str); + ok(hr == S_OK, "got hr %#lx\n", hr); + if (!strcmp(str, "Windows.Foundation.Metadata")) + { + guid_ctor_idx = ((i + 1) << 3) | 3; + winetest_pop_context(); + break; + } + } + } + + winetest_pop_context(); + } + + todo_wine + ok(!!guid_ctor_idx, "got guid_ctor_coded_idx %lu\n", guid_ctor_idx); + + /* Verify ITest1 has the correct GuidAttribute value. */ + for (i = 0; i < tables[TableFromToken(mdtCustomAttribute)].exp_rows; i++) + { + const struct row_custom_attribute *attr = NULL; + + winetest_push_context("i=%lu", i); + + attr = NULL; + hr = IMetaDataTables_GetRow(md_tables, 12, i + 1, (BYTE *)&attr); + todo_wine + ok(hr == S_OK, "got hr %#lx\n", hr); + if (FAILED(hr)) + { + winetest_pop_context(); + continue; + } + + if (attr->Type == guid_ctor_idx && attr->Parent == itest1_def_idx) + { + const BYTE *value = NULL; + const GUID *guid; + ULONG size = 0; + + hr = IMetaDataTables_GetBlob(md_tables, attr->Value, &size, &value); + ok(hr == S_OK, "got hr %#lx\n", hr); + ok(size == sizeof(GUID) + 4, "got size %lu\n", size); + guid = (GUID *)&value[2]; + ok(IsEqualGUID(guid, &IID_ITest1), "got guid %s\n", debugstr_guid(guid)); + } + + winetest_pop_context(); + } + + IMetaDataTables_Release(md_tables); +} + START_TEST(rometadata) { HRESULT hr; @@ -65,6 +444,7 @@ START_TEST(rometadata) ok(hr == S_OK, "RoInitialize failed, hr %#lx\n", hr);
test_MetaDataGetDispenser(); + test_MetaDataDispenser_OpenScope();
RoUninitialize(); } diff --git a/dlls/rometadata/tests/rsrc.rc b/dlls/rometadata/tests/rsrc.rc new file mode 100644 index 00000000000..9b2c6daded3 --- /dev/null +++ b/dlls/rometadata/tests/rsrc.rc @@ -0,0 +1,20 @@ +/* + * Copyright 2025 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* @makedep: test-simple.winmd */ +test-simple.winmd RCDATA "test-simple.winmd" diff --git a/dlls/rometadata/tests/test-simple.idl b/dlls/rometadata/tests/test-simple.idl new file mode 100644 index 00000000000..8722945f8df --- /dev/null +++ b/dlls/rometadata/tests/test-simple.idl @@ -0,0 +1,51 @@ +/* + * Copyright 2025 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef __WIDL__ +#pragma makedep header +#pragma makedep winmd +#pragma winrt ns_prefix +#endif + +import "inspectable.idl"; +import "windowscontracts.idl"; + +namespace Wine.Test { + interface ITest1; + + runtimeclass Test1; + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Wine.Test.Test1), + uuid(deadbeef-dead-beef-dead-deadbeef0001) + ] + interface ITest1 : IInspectable + { + HRESULT Foo(); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(agile) + ] + runtimeclass Test1 + { + [default] interface Wine.Test.ITest1; + } +} diff --git a/include/Makefile.in b/include/Makefile.in index 351de1be8a1..a43168baf1f 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -689,6 +689,7 @@ SOURCES = \ robuffer.idl \ roerrorapi.h \ rometadata.h \ + rometadataapi.idl \ rometadataresolution.h \ roparameterizediid.idl \ row.idl \ diff --git a/include/rometadataapi.idl b/include/rometadataapi.idl new file mode 100644 index 00000000000..22e7a0d2085 --- /dev/null +++ b/include/rometadataapi.idl @@ -0,0 +1,69 @@ +/* + * Copyright 2025 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +import "unknwn.idl"; +import "cor.idl"; + +[ + local, + object, + uuid(d8f579ab-402d-4b8e-82d9-5d63b1065c68) +] +interface IMetaDataTables : IUnknown +{ + HRESULT GetStringHeapSize([out] ULONG *size); + + HRESULT GetBlobHeapSize([out] ULONG *size); + + HRESULT GetGuidHeapSize([out] ULONG *size); + + HRESULT GetUserStringHeapSize([out] ULONG *size); + + HRESULT GetNumTables([out] ULONG *tables); + + HRESULT GetTableIndex([in] ULONG token, [out] ULONG *idx); + + HRESULT GetTableInfo([in] ULONG idx, [out] ULONG *row_size, [out] ULONG *rows, [out] ULONG *cols, + [out] ULONG *key_idx, [out, string] const char **name); + + HRESULT GetColumnInfo([in] ULONG idx_tbl, [in] ULONG idx_col, [out] ULONG *offset, [out] ULONG *col_size, + [out] ULONG *type, [out, string] const char **name); + + HRESULT GetCodedTokenInfo([in] ULONG type, [out] ULONG *tokens_len, [out] const ULONG **tokens, + [out, string] const char **name); + + HRESULT GetRow([in] ULONG idx_tbl, [in] ULONG idx_row, [out] const BYTE *row); + + HRESULT GetColumn([in] ULONG idx_tbl, [in] ULONG idx_col, [in] ULONG idx_row, [out] ULONG *val); + + HRESULT GetString([in] ULONG idx, [out] const char **str); + + HRESULT GetBlob([in] ULONG idx, [out] ULONG *size, [out] const BYTE **blob); + + HRESULT GetGuid([in] ULONG idx, [out] const GUID **guid); + + HRESULT GetUserString([in] ULONG idx, [out] ULONG *size, [out] const BYTE **blob); + + HRESULT GetNextString([in] ULONG idx, [out] ULONG *next); + + HRESULT GetNextBlob([in] ULONG idx, [out] ULONG *next); + + HRESULT GetNextGuid([in] ULONG idx, [out] ULONG *next); + + HRESULT GetNextUserString([in] ULONG idx, [out] ULONG *next); +}