diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9ef481f --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ + +/target +/**/*.rs.bk +/Cargo.lock +.DS_Store +.vs + +[Bb]in/ +[Oo]bj/ \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..4768290 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/windows-runtime.iml b/.idea/windows-runtime.iml new file mode 100644 index 0000000..0f4b92c --- /dev/null +++ b/.idea/windows-runtime.iml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100755 index 0000000..bac9d82 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[workspace] + +members = ["core", "core-bindings"] + +[profile.release] +panic = "abort" +codegen-units = 1 +lto = true +#opt-level = 3 +opt-level = "z" +debug = false +incremental = false \ No newline at end of file diff --git a/TestApp/TestApp.sln b/TestApp/TestApp.sln new file mode 100755 index 0000000..91b6f5e --- /dev/null +++ b/TestApp/TestApp.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31321.278 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApp", "TestApp\TestApp.csproj", "{BF77710B-81A6-4F79-9608-B9D8A7C2DF55}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BF77710B-81A6-4F79-9608-B9D8A7C2DF55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BF77710B-81A6-4F79-9608-B9D8A7C2DF55}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BF77710B-81A6-4F79-9608-B9D8A7C2DF55}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BF77710B-81A6-4F79-9608-B9D8A7C2DF55}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {D42E46BA-4BE0-4971-ADDF-4D22BFD6F2C8} + EndGlobalSection +EndGlobal diff --git a/TestApp/TestApp/App/main.js b/TestApp/TestApp/App/main.js new file mode 100755 index 0000000..98fb8fd --- /dev/null +++ b/TestApp/TestApp/App/main.js @@ -0,0 +1,7 @@ +console.log("me"); + +console.log(Date.now(), time(), performance.now()); + +const MessageDialog = $("Windows.UI.Popups.MessageDialog"); +const dialog = new MessageDialog("Hello, World!"); +dialog.ShowAsync(); \ No newline at end of file diff --git a/TestApp/TestApp/Program.cs b/TestApp/TestApp/Program.cs new file mode 100755 index 0000000..dda9bc3 --- /dev/null +++ b/TestApp/TestApp/Program.cs @@ -0,0 +1,29 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; +namespace TestApp +{ + class Program + + { + + + + [DllImport("nativescript.dll")] + public static extern void hello(); + + [DllImport("nativescript.dll")] + public static extern Int64 runtime_init([MarshalAs(UnmanagedType.LPUTF8Str)] string entry); + + [DllImport("nativescript.dll")] + public static extern void runtime_runscript(Int64 runtime, [MarshalAs(UnmanagedType.LPUTF8Str)] string entry); + + static void Main(string[] args) + { + + string entry = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "App\\main.js"); + Int64 runtime = runtime_init(AppContext.BaseDirectory); + runtime_runscript(runtime, File.ReadAllText(Path.GetFullPath(entry))); + } + } +} diff --git a/TestApp/TestApp/Properties/launchSettings.json b/TestApp/TestApp/Properties/launchSettings.json new file mode 100755 index 0000000..ce70851 --- /dev/null +++ b/TestApp/TestApp/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "TestApp": { + "commandName": "Project", + "nativeDebugging": true + } + } +} \ No newline at end of file diff --git a/TestApp/TestApp/TestApp.csproj b/TestApp/TestApp/TestApp.csproj new file mode 100755 index 0000000..cc7892f --- /dev/null +++ b/TestApp/TestApp/TestApp.csproj @@ -0,0 +1,21 @@ + + + + Exe + net5.0 + + + + + Always + + + Always + + + + + + + + diff --git a/core-bindings/Cargo.toml b/core-bindings/Cargo.toml new file mode 100644 index 0000000..4abc516 --- /dev/null +++ b/core-bindings/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "core_bindings" +version = "0.1.0" +edition = "2018" +build = "build.rs" + +[dependencies] +windows = "0.10.0" + +[build-dependencies] +windows = "0.10.0" +cc = "1.0" +bindgen = "0.53.1" \ No newline at end of file diff --git a/core-bindings/build.rs b/core-bindings/build.rs new file mode 100644 index 0000000..ca42594 --- /dev/null +++ b/core-bindings/build.rs @@ -0,0 +1,64 @@ +use std::env; + +use std::path::PathBuf; +use bindgen::EnumVariation; + + +fn main() { + windows::build!( + Windows::Win32::System::Console::WriteConsoleA, + Windows::Win32::System::WindowsProgramming::STD_OUTPUT_HANDLE, + Windows::Win32::System::WindowsProgramming::GetStdHandle, + Windows::Win32::System::SystemServices::GetProcAddress, + Windows::Win32::System::SystemServices::LoadLibraryA, + Windows::Win32::System::SystemServices::FARPROC + ); + + let mut build = cc::Build::default() ; + build.file("src/bindings.cpp") + .cpp(true) + .include("C:\\Program Files (x86)\\Windows Kits\\NETFXSDK\\4.8\\Include\\um") + .static_crt(true) + .compile("libcorebindings"); + + println!("cargo:rerun-if-changed=src/bindings.cpp"); + + + + let bindgen = bindgen::builder() + .generate_comments(false) + .default_enum_style( + EnumVariation::Rust { + non_exhaustive: false + } + ) + .size_t_is_usize(true) + .use_core() + .clang_arg("-std=c++17") + .clang_args(&["-x", "c++"]) + .clang_arg("-v") + .whitelist_function("RoResolveNamespace") + .whitelist_function("Rometadataresolution_.*") + .whitelist_function("IMetaDataImport2_.*") + .whitelist_function("Enums_.*") + .whitelist_function("Helpers_.*") + .whitelist_function("IRoSimpleMetaDataBuilder_.*") + .whitelist_var("Helpers_.*") + //.blacklist_type("HSTRING") + //.raw_line("pub type HSTRING = windows::HSTRING;") + .clang_args(&["-I", "C:\\Program Files (x86)\\Windows Kits\\NETFXSDK\\4.8\\Include\\um"]) + .header("src/bindings.cpp") + // Tell cargo to invalidate the built crate whenever any of the + // included header files changed. + .parse_callbacks(Box::new(bindgen::CargoCallbacks)) + // Finish the builder and generate the bindings. + .generate() + // Unwrap the Result and panic on failure. + .expect("Unable to generate bindings"); + + // Write the bindings to the $OUT_DIR/bindings.rs file. + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + bindgen + .write_to_file(out_path.join("bindings.rs")) + .expect("Couldn't write bindings!"); +} \ No newline at end of file diff --git a/core-bindings/src/bindings.cpp b/core-bindings/src/bindings.cpp new file mode 100644 index 0000000..8443b59 --- /dev/null +++ b/core-bindings/src/bindings.cpp @@ -0,0 +1,691 @@ +#include "headers.h" + + +typedef HRESULT (__cdecl *ProcRoGetMetaDataFile)(const HSTRING name, IMetaDataDispenserEx *, HSTRING *, + IMetaDataImport2 **, mdTypeDef *typeDefToken); + + +typedef HRESULT(__cdecl *ProcRoParseTypeName)(const HSTRING typeName, DWORD *partsCount, HSTRING **typeNameParts); + +typedef HRESULT(__cdecl *ProcRoGetParameterizedTypeInstanceIID)(UINT32 nameElementCount, + PCWSTR *nameElements, + const IRoMetaDataLocator &metaDataLocator, + GUID *iid, + ROPARAMIIDHANDLE *pExtra); + + +extern "C" HRESULT +Rometadataresolution_RoGetMetaDataFile(const HSTRING name, void *metaDataDispenser, void *metaDataFilePath, + void **metaDataImport, mdTypeDef *typeDefToken) { + auto dispenser = reinterpret_cast(metaDataDispenser); + auto filePath = reinterpret_cast(metaDataFilePath); + auto import = (IMetaDataImport2 * *)(metaDataImport); + + /* auto proc = (ProcRoGetMetaDataFile)GetProcAddress( + LoadLibraryA("api-ms-win-ro-typeresolution-l1-1-0.dll"), + "RoGetMetaDataFile"); + + return proc(name, dispenser, filePath, import, typeDefToken); + */ + return RoGetMetaDataFile(name, dispenser, filePath, import, typeDefToken); +} + + +extern "C" HRESULT +Rometadataresolution_RoParseTypeName(const HSTRING typeName, DWORD *partsCount, HSTRING **typeNameParts) { + /*auto proc = (ProcRoParseTypeName)GetProcAddress( + LoadLibraryA("api-ms-win-ro-typeresolution-l1-1-0.dll"), + "RoParseTypeName"); + + return proc(typeName, partsCount, typeNameParts);*/ + return RoParseTypeName(typeName, partsCount, typeNameParts); +} + + + +extern "C" HRESULT Rometadataresolution_RoGetParameterizedTypeInstanceIID(UINT32 nameElementCount, + PCWSTR *nameElements, + HRESULT(*fn)(PCWSTR name, IRoSimpleMetaDataBuilder & builder), + GUID *iid, + ROPARAMIIDHANDLE *pExtra) { + + + + auto locatorImpl{ [&](PCWSTR name, IRoSimpleMetaDataBuilder& builder) { + return fn(name, builder); + } }; + + + //auto const locator = locatorImpl; + + return RoGetParameterizedTypeInstanceIID(nameElementCount, nameElements, Ro::Locator(locatorImpl), iid, pExtra); +} + +//typedef HRESULT(void* RoLocator)(PCWSTR name, iro_simple_meta_data_builder& builder); + + +//typedef HRESULT(*RoLocator)(PCWSTR name, iro_simple_meta_data_builder& builder); + +struct _locator { + Ro::detail::_Locator locator; +}; + + +extern "C" void +Rometadataresolution_Ro_Locator(HRESULT(*fn)(PCWSTR name, IRoSimpleMetaDataBuilder &builder), Locator *locator) { + /*auto proc = (ProcRoGetParameterizedTypeInstanceIID)GetProcAddress( + LoadLibraryA("api-ms-win-ro-typeresolution-l1-1-0.dll"), + "ro_get_parameterized_type_instance_iid"); + + return proc(nameElementCount, nameElements, metaDataLocator, iid, pExtra); */ + locator->locator = Ro::Locator(fn); +} + +/* +extern "C" void +Rometadataresolution_RoResolveNamespace(const HSTRING name, + const HSTRING windowsMetaDataDir, + const DWORD packageGraphDirsCount, + const HSTRING * packageGraphDirs, + DWORD * metaDataFilePathsCount, + HSTRING * *metaDataFilePaths, + DWORD * subNamespacesCount, + HSTRING * *subNamespaces) { + RoResolveNamespace() +} + + +*/ + +extern "C" HRESULT IMetaDataImport2_GetMethodProps(IMetaDataImport2 *metadata, + mdMethodDef tkMethodDef, + mdTypeDef *ptkClass, + LPWSTR szMethod, + ULONG cchMethod, + ULONG *pchMethod, + DWORD *pdwAttr, + PCCOR_SIGNATURE *ppvSigBlob, + ULONG *pcbSigBlob, + ULONG *pulCodeRVA, + DWORD *pdwImplFlags) { + return metadata->GetMethodProps(tkMethodDef, ptkClass, szMethod, cchMethod, pchMethod, pdwAttr, ppvSigBlob, pcbSigBlob, + pulCodeRVA, pdwImplFlags); +} + +extern "C" HRESULT IMetaDataImport2_GetPropertyProps(IMetaDataImport2 *metadata, mdProperty prop, + mdTypeDef *pClass, + LPCWSTR szProperty, + ULONG cchProperty, + ULONG *pchProperty, + DWORD *pdwPropFlags, + PCCOR_SIGNATURE *ppvSig, + ULONG *pbSig, + DWORD *pdwCPlusTypeFlag, + UVCP_CONSTANT *ppDefaultValue, + ULONG *pcchDefaultValue, + mdMethodDef *pmdSetter, + mdMethodDef *pmdGetter, + mdMethodDef *rmdOtherMethod, + ULONG cMax, + ULONG *pcOtherMethod) { + return metadata->GetPropertyProps(prop, pClass, szProperty, cchProperty, pchProperty, pdwPropFlags, ppvSig, pbSig, + pdwCPlusTypeFlag, + ppDefaultValue, pcchDefaultValue, pmdSetter, pmdGetter, rmdOtherMethod, cMax, + pcOtherMethod); +} + + + +extern "C" HRESULT +IMetaDataImport2_GetFieldProps(IMetaDataImport2 *metadata, + mdFieldDef mb, + mdTypeDef *pClass, + LPWSTR szField, + ULONG cchField, + ULONG *pchField, + DWORD *pdwAttr, + PCCOR_SIGNATURE *ppvSigBlob, + ULONG *pcbSigBlob, + DWORD *pdwCPlusTypeFlag, + UVCP_CONSTANT *ppValue, + ULONG *pcchValue) { + + return metadata->GetFieldProps(mb, pClass, szField, cchField, pchField, pdwAttr, ppvSigBlob, pcbSigBlob, + pdwCPlusTypeFlag, ppValue, pcchValue); +} + +extern "C" HRESULT +IMetaDataImport2_GetTypeDefProps(IMetaDataImport2 *metadata, uint32_t mdTypeDef, LPWSTR szTypeDef, ULONG cchTypeDef, + ULONG *pchTypeDef, DWORD *pdwTypeDefFlags, mdToken *ptkExtends) { + + return metadata->GetTypeDefProps(mdTypeDef, szTypeDef, cchTypeDef, pchTypeDef, pdwTypeDefFlags, ptkExtends); +} + +extern "C" HRESULT IMetaDataImport2_GetTypeDefPropsNameSize(IMetaDataImport2 *metadata, uint32_t token, ULONG *pchTypeDef) { + + auto size = reinterpret_cast(&pchTypeDef); + return metadata->GetTypeDefProps(token, 0, 0, size, 0, 0); +} + +extern "C" HRESULT IMetaDataImport2_EnumParams(IMetaDataImport2 *metadata, HCORENUM *phEnum, + mdMethodDef mb, + mdParamDef *rParams, + ULONG cMax, + ULONG *pcTokens) { + + return metadata->EnumParams(phEnum, mb, rParams, cMax, pcTokens); +} + +extern "C" void IMetaDataImport2_CloseEnum(IMetaDataImport2 *metadata, HCORENUM phEnum) { + + metadata->CloseEnum(phEnum); +} + + + +extern "C" HRESULT IMetaDataImport2_GetParamProps(IMetaDataImport2 *metadata, + mdParamDef tk, + mdMethodDef *pmd, + ULONG *pulSequence, + LPWSTR szName, + ULONG cchName, + ULONG *pchName, + DWORD *pdwAttr, + DWORD *pdwCPlusTypeFlag, + UVCP_CONSTANT *ppValue, + ULONG *pcchValue) { + + return metadata->GetParamProps(tk, pmd, pulSequence, szName, cchName, pchName, pdwAttr, pdwCPlusTypeFlag, ppValue, + pcchValue); +} + +extern "C" HRESULT IMetaDataImport2_GetCustomAttributeByName(IMetaDataImport2 *metadata, + mdToken tkObj, + LPCWSTR szName, + const void **ppData, + ULONG *pcbData) { + + return metadata->GetCustomAttributeByName(tkObj, szName, ppData, pcbData); +} + +extern "C" HRESULT IMetaDataImport2_EnumInterfaceImpls(IMetaDataImport2 *metadata, HCORENUM *phEnum, + mdTypeDef td, + mdInterfaceImpl *rImpls, + ULONG cMax, + ULONG *pcImpls) { + + return metadata->EnumInterfaceImpls(phEnum, td, rImpls, cMax, pcImpls); +} + +extern "C" HRESULT IMetaDataImport2_GetTypeRefProps(IMetaDataImport2 *metadata, mdTypeRef tr, + mdToken *ptkResolutionScope, + LPWSTR szName, + ULONG cchName, + ULONG *pchName) { + + return metadata->GetTypeRefProps(tr, ptkResolutionScope, szName, cchName, pchName); +} + +extern "C" HRESULT IMetaDataImport2_FindMethod(IMetaDataImport2 *metadata, mdTypeDef td, + LPCWSTR szName, + PCCOR_SIGNATURE pvSigBlob, + ULONG cbSigBlob, + mdMethodDef *pmb) { + + return metadata->FindMethod(td, szName, pvSigBlob, cbSigBlob, pmb); +} + +extern "C" HRESULT IMetaDataImport2_EnumGenericParams(IMetaDataImport2 *metadata, HCORENUM *phEnum, + mdToken tk, + mdGenericParam rGenericParams[], + ULONG cMax, + ULONG *pcGenericParams) { + + return metadata->EnumGenericParams(phEnum, tk, rGenericParams, cMax, pcGenericParams); +} + + +extern "C" HRESULT IMetaDataImport2_CountEnum(IMetaDataImport2 *metadata, HCORENUM hEnum, ULONG *pulCount) { + + return metadata->CountEnum(hEnum, pulCount); +} + +extern "C" HRESULT IMetaDataImport2_GetTypeSpecFromToken(IMetaDataImport2 *metadata, mdTypeSpec typespec, + PCCOR_SIGNATURE *ppvSig, + ULONG *pcbSig) { + + return metadata->GetTypeSpecFromToken(typespec, ppvSig, pcbSig); +} + + +extern "C" HRESULT IMetaDataImport2_EnumFields(IMetaDataImport2 *metadata, HCORENUM *phEnum, + mdTypeDef tkTypeDef, + mdFieldDef rgFields[], + ULONG cMax, + ULONG *pcTokens) { + + return metadata->EnumFields(phEnum, tkTypeDef, rgFields, cMax, pcTokens); +} + + +extern "C" HRESULT IMetaDataImport2_EnumMethodsWithName(IMetaDataImport2 *metadata, HCORENUM *phEnum, + mdTypeDef tkTypeDef, + LPCWSTR szName, + mdMethodDef rgMethods[], + ULONG cMax, + ULONG *pcTokens) { + + return metadata->EnumMethodsWithName(phEnum, tkTypeDef, szName, rgMethods, cMax, pcTokens); +} + +extern "C" HRESULT IMetaDataImport2_GetInterfaceImplProps(IMetaDataImport2 *metadata, mdInterfaceImpl tkInterfaceImpl, + mdTypeDef *ptkClass, + mdToken *ptkIface) { + + return metadata->GetInterfaceImplProps(tkInterfaceImpl, ptkClass, ptkIface); +} + +extern "C" HRESULT IMetaDataImport2_EnumMethods(IMetaDataImport2 *metadata, HCORENUM *phEnum, + mdTypeDef tkTypeDef, + mdMethodDef rgMethods[], + ULONG cMax, + ULONG *pcTokens) { + + return metadata->EnumMethods(phEnum, tkTypeDef, rgMethods, cMax, pcTokens); +} + + +extern "C" HRESULT IMetaDataImport2_EnumProperties(IMetaDataImport2 *metadata, HCORENUM *phEnum, + mdTypeDef tkTypDef, + mdProperty rgProperties[], + ULONG cMax, + ULONG *pcProperties) { + + return metadata->EnumProperties(phEnum, tkTypDef, rgProperties, cMax, pcProperties); +} + +extern "C" HRESULT IMetaDataImport2_EnumEvents(IMetaDataImport2 *metadata, HCORENUM *phEnum, + mdTypeDef tkTypDef, + mdEvent rgEvents[], + ULONG cMax, + ULONG *pcEvents) { + + return metadata->EnumEvents(phEnum, tkTypDef, rgEvents, cMax, pcEvents); +} + +extern "C" HRESULT IMetaDataImport2_GetEventProps(IMetaDataImport2 *metadata, mdEvent ev, + mdTypeDef *pClass, + LPCWSTR szEvent, + ULONG cchEvent, + ULONG *pchEvent, + DWORD *pdwEventFlags, + mdToken *ptkEventType, + mdMethodDef *pmdAddOn, + mdMethodDef *pmdRemoveOn, + mdMethodDef *pmdFire, + mdMethodDef rmdOtherMethod[], + ULONG cMax, + ULONG *pcOtherMethod) { + + return metadata->GetEventProps(ev, pClass, szEvent, cchEvent, pchEvent, pdwEventFlags, ptkEventType, pmdAddOn, + pmdRemoveOn, pmdFire, rmdOtherMethod, cMax, pcOtherMethod); +} + + +extern "C" HRESULT IMetaDataImport2_FindField(IMetaDataImport2* metadata, mdTypeDef td, + LPCWSTR szName, + PCCOR_SIGNATURE pvSigBlob, + ULONG cbSigBlob, + mdFieldDef * pmb) { + return metadata->FindField(td, szName, pvSigBlob, cbSigBlob, pmb); +} + +extern "C" HRESULT IMetaDataImport2_GetMemberRefProps(IMetaDataImport2* metadata, mdMemberRef tkMemberRef, + mdToken * ptk, + LPWSTR szMember, + ULONG cchMember, + ULONG * pchMember, + PCCOR_SIGNATURE * ppvSigBlob, + ULONG * pcbSigBlob) { + return metadata->GetMemberRefProps(tkMemberRef, ptk, szMember, cchMember, pchMember, ppvSigBlob, pcbSigBlob); +} + +extern "C" HRESULT IMetaDataImport2_GetCustomAttributeProps(IMetaDataImport2* metadata, mdCustomAttribute cv, + mdToken * ptkObj, + mdToken * ptkType, + const BYTE * *ppBlob, + ULONG * pcbBlob) { + auto blob = reinterpret_cast(ppBlob); + return metadata->GetCustomAttributeProps(cv, ptkObj, ptkType, blob, pcbBlob); +} + +extern "C" HRESULT IMetaDataImport2_EnumCustomAttributes(IMetaDataImport2 * metadata, HCORENUM * phEnum, + mdToken tk, + mdToken tkType, + mdCustomAttribute rgCustomAttributes[], + ULONG cMax, + ULONG * pcCustomAttributes) { + return metadata->EnumCustomAttributes(phEnum, tk, tkType, rgCustomAttributes, cMax, pcCustomAttributes); +} + +extern "C" HRESULT IMetaDataImport2_FindTypeDefByName(IMetaDataImport2 * metadata, LPCWSTR szTypeDef, + mdToken tkEnclosingClass, + mdTypeDef * ptkTypeDef) { + return metadata->FindTypeDefByName(szTypeDef, tkEnclosingClass, ptkTypeDef); +} + +extern "C" HRESULT IMetaDataImport2_EnumMethodImpls(IMetaDataImport2 * metadata, HCORENUM * phEnum, + mdTypeDef tkTypeDef, + mdToken rMethodBody[], + mdToken rMethodDecl[], + ULONG cMax, + ULONG * pcTokens) { + return metadata->EnumMethodImpls(phEnum, tkTypeDef, rMethodBody, rMethodDecl, cMax, pcTokens); +} + + + +extern "C" HRESULT IRoSimpleMetaDataBuilder_SetRuntimeClassSimpleDefault(IRoSimpleMetaDataBuilder* builder, PCWSTR name, + PCWSTR defaultInterfaceName, + const GUID * defaultInterfaceIID) { + return builder->SetRuntimeClassSimpleDefault(name, defaultInterfaceName, defaultInterfaceIID); +} + +extern "C" HRESULT IRoSimpleMetaDataBuilder_SetWinRtInterface(IRoSimpleMetaDataBuilder * builder, GUID iid) { + return builder->SetWinRtInterface(iid); +} + +extern "C" HRESULT IRoSimpleMetaDataBuilder_SetParameterizedInterface(IRoSimpleMetaDataBuilder* builder, GUID piid, + UINT32 numArgs) { + return builder->SetParameterizedInterface(piid,numArgs); +} + +extern "C" HRESULT IRoSimpleMetaDataBuilder_SetEnum(IRoSimpleMetaDataBuilder * builder, PCWSTR name, + PCWSTR baseType) { + return builder->SetEnum(name, baseType); +} + + +extern "C" HRESULT IRoSimpleMetaDataBuilder_SetStruct(IRoSimpleMetaDataBuilder * builder, PCWSTR name, + UINT32 numFields, + const PCWSTR * fieldTypeNames) { + return builder->SetStruct(name, numFields, fieldTypeNames); +} + + +extern "C" HRESULT IRoSimpleMetaDataBuilder_SetDelegate(IRoSimpleMetaDataBuilder * builder, GUID iid) { + return builder->SetDelegate(iid); +} + + +extern "C" HRESULT IRoSimpleMetaDataBuilder_SetParameterizedDelegate(IRoSimpleMetaDataBuilder * builder, GUID piid, + UINT32 numArgs) { + return builder->SetParameterizedDelegate(piid, numArgs); +} + + + +extern "C" ULONG32 Enums_TypeFromToken(mdToken token) { + return TypeFromToken(token); +} + + +extern "C" ULONG Helpers_Get_Type_Name(IMetaDataImport2 *metadata, mdToken token, uint16_t *nameData, ULONG nameSize) { + + ULONG nameLength{0}; + auto data = reinterpret_cast(nameData); + + switch (TypeFromToken(token)) { + case CorTokenType::mdtTypeDef: { + metadata->GetTypeDefProps(token, data, nameSize, &nameLength, nullptr, nullptr); + break; + } + case CorTokenType::mdtTypeRef: { + metadata->GetTypeRefProps(token, nullptr, data, nameSize, &nameLength); + break; + } + default: + assert(false); + break; + } + + return nameLength - 1; +} + +extern "C" BOOL Helpers_IsTdPublic(DWORD value) { + return IsTdPublic(value); +} + +extern "C" BOOL Helpers_IsTdSpecialName(DWORD value) { + return IsTdSpecialName(value); +} + +extern "C" ULONG Helpers_CorSigUncompressCallingConv(PCCOR_SIGNATURE pData) { + return CorSigUncompressCallingConv(pData); +} + + +extern "C" ULONG Helpers_CorSigUncompressData(PCCOR_SIGNATURE pData) { + return CorSigUncompressData(pData); +} + +extern "C" CorElementType Helpers_CorSigUncompressElementType(PCCOR_SIGNATURE pData) { + return CorSigUncompressElementType(pData); +} + +extern "C" mdToken Helpers_CorSigUncompressToken(PCCOR_SIGNATURE pData) { + return CorSigUncompressToken(pData); +} + +extern "C" size_t Helpers_to_wstring(ULONG index, wchar_t *text) { + using namespace std; + auto str = to_wstring(index); + auto txt = std::wstring(text); + txt += str; + wcscpy(text, txt.c_str()); + return str.length() - 1; +} + +extern "C" BOOL Helpers_IsMdPublic(DWORD value) { + return IsMdPublic(value); +} + +extern "C" BOOL Helpers_IsMdFamily(DWORD value) { + return IsMdFamily(value); +} + +extern "C" BOOL Helpers_IsMdFamORAssem(DWORD value) { + return IsMdFamORAssem(value); +} + +extern "C" BOOL Helpers_IsMdSpecialName(DWORD value) { + return IsMdSpecialName(value); +} + +extern "C" BOOL Helpers_IsMdStatic(DWORD value) { + return IsMdStatic(value); +} + +extern "C" BOOL Helpers_IsMdFinal(DWORD value) { + return IsMdFinal(value); +} + +extern "C" BOOL Helpers_IsMdInstanceInitializerW(DWORD flags, const wchar_t *nameData) { + return IsMdInstanceInitializerW(flags, nameData); +} + +extern "C" BOOL Helpers_IsPrSpecialName(DWORD value) { + return IsPrSpecialName(value); +} + + +extern "C" void Helpers_bytesToGuid(uint8_t *data, GUID *iid) { + *iid = *reinterpret_cast(data); +} + +extern "C" PCWSTR Helpers_WindowsGetStringRawBuffer(HSTRING string, + UINT32 *length) { + return WindowsGetStringRawBuffer(string, length); +} + +extern "C" BOOL Helpers_IsTdInterface(DWORD value) { + return IsTdInterface(value); +} + +extern "C" BOOL Helpers_IsTdClass(DWORD value) { + return IsTdClass(value); +} + +extern "C" BOOL Helpers_IsEvSpecialName(DWORD value) { + return IsEvSpecialName(value); +} + +extern "C" void Helpers_generate_id_name(PCWSTR* namePartsW, wchar_t* declarationFullName, DWORD * namePartsCount) { + using namespace Microsoft::WRL::Wrappers; + HSTRING* nameParts{ nullptr }; + RoParseTypeName(HStringReference(declarationFullName).Get(), namePartsCount, &nameParts); + + size_t count = (size_t)(namePartsCount); + for (size_t i = 0; i < count; ++i) { + namePartsW[i] = WindowsGetStringRawBuffer(nameParts[i], nullptr); + } + + +} + +extern "C" void Helpers_toString_length(PCWSTR value, size_t * count) { + using namespace Microsoft::WRL::Wrappers; + *count = wcslen(value); +} + + +extern "C" BOOL Helpers_IsTdSealed(DWORD value) { + return IsTdSealed(value); +} + + +/* +extern "C" HRESULT GenericInstanceIdBuilder_locatorImpl(PCWSTR name, iro_simple_meta_data_builder & builder) { + shared_ptr declaration{ metadataReader.findByName(name) }; + ASSERT(declaration); + + DeclarationKind kind{ declaration->kind() }; + switch (kind) { + case DeclarationKind::Class: { + ClassDeclaration* classDeclaration{ static_cast(declaration.get()) }; + const InterfaceDeclaration& defaultInterface{ classDeclaration->defaultInterface() }; + IID defaultInterfaceId = defaultInterface.id(); + ASSERT_SUCCESS(builder.set_runtime_class_simple_default(name, defaultInterface.fullName().data(), &defaultInterfaceId)); + return S_OK; + } + + case DeclarationKind::Interface: { + InterfaceDeclaration* interfaceDeclaration{ static_cast(declaration.get()) }; + ASSERT_SUCCESS(builder.set_win_rt_interface(interfaceDeclaration->id())); + return S_OK; + } + + case DeclarationKind::GenericInterface: { + GenericInterfaceDeclaration* genericInterfaceDeclaration{ static_cast(declaration.get()) }; + ASSERT_SUCCESS(builder.set_parameterized_interface(genericInterfaceDeclaration->id(), genericInterfaceDeclaration->number_of_generic_parameters())); + return S_OK; + } + + case DeclarationKind::Enum: { + EnumDeclaration* enumDeclaration{ static_cast(declaration.get()) }; + ASSERT_SUCCESS(builder.set_enum(enumDeclaration->fullName().data(), Signature::toString(nullptr, enumDeclaration->type()).data())); + return S_OK; + } + + case DeclarationKind::Struct: { + StructDeclaration* structDeclaration{ static_cast(declaration.get()) }; + + vector fieldNames; + for (const StructFieldDeclaration& field : *structDeclaration) { + fieldNames.push_back(Signature::toString(field._metadata.Get(), field.type())); + } + + vector fieldNamesW; + for (wstring& fieldName : fieldNames) { + fieldNamesW.push_back(const_cast(fieldName.data())); + } + + ASSERT_SUCCESS(builder.set_struct(structDeclaration->fullName().data(), structDeclaration->size(), fieldNamesW.data())); + return S_OK; + } + + case DeclarationKind::Delegate: { + DelegateDeclaration* delegateDeclaration{ static_cast(declaration.get()) }; + ASSERT_SUCCESS(builder.set_delegate(delegateDeclaration->id())); + return S_OK; + } + + case DeclarationKind::GenericDelegate: { + GenericDelegateDeclaration* genericDelegateDeclaration{ static_cast(declaration.get()) }; + ASSERT_SUCCESS(builder.set_parameterized_delegate(genericDelegateDeclaration->id(), genericDelegateDeclaration->number_of_generic_parameters())); + return S_OK; + } + + default: + ASSERT_NOT_REACHED(); + } +} + + +extern "C" void GenericInstanceIdBuilder_generateId(wchar_t * fullName, GUID * iid) { + wstring declarationFullName = std::wstring(fullName); + + HSTRING* nameParts{ nullptr }; + DWORD namePartsCount{ 0 }; + ASSERT_SUCCESS(RoParseTypeName(HStringReference(declarationFullName.data()).Get(), &namePartsCount, &nameParts)); + + array namePartsW; + ASSERT(namePartsCount < namePartsW.size()); + + for (size_t i = 0; i < namePartsCount; ++i) { + namePartsW[i] = WindowsGetStringRawBuffer(nameParts[i], nullptr); + } + + + ASSERT_SUCCESS(ro_get_parameterized_type_instance_iid(namePartsCount, namePartsW.data(), Ro::Locator(&GenericInstanceIdBuilder_locatorImpl), &guid, nullptr)); + + for (size_t i = 0; i < namePartsCount; ++i) { + ASSERT_SUCCESS(WindowsDeleteString(nameParts[i])); + } + + CoTaskMemFree(nameParts); + + return guid; +} + +*/ + +extern "C" HRESULT Helpers_RO_E_METADATA_NAME_IS_NAMESPACE = RO_E_METADATA_NAME_IS_NAMESPACE; + +extern "C" mdToken Helpers_mdTokenNil = mdTokenNil; +extern "C" mdToken Helpers_mdModuleNil = mdModuleNil; +extern "C" mdToken Helpers_mdTypeRefNil = mdTypeRefNil; +extern "C" mdToken Helpers_mdTypeDefNil = mdTypeDefNil; +extern "C" mdToken Helpers_mdFieldDefNil = mdFieldDefNil; +extern "C" mdToken Helpers_mdMethodDefNil = mdMethodDefNil; +extern "C" mdToken Helpers_mdParamDefNil = mdParamDefNil; +extern "C" mdToken Helpers_mdInterfaceImplNil = mdInterfaceImplNil; +extern "C" mdToken Helpers_mdMemberRefNil = mdMemberRefNil; +extern "C" mdToken Helpers_mdCustomAttributeNil = mdCustomAttributeNil; +extern "C" mdToken Helpers_mdPermissionNil = mdPermissionNil; +extern "C" mdToken Helpers_mdSignatureNil = mdSignatureNil; +extern "C" mdToken Helpers_mdEventNil = mdEventNil; +extern "C" mdToken Helpers_mdPropertyNil = mdPropertyNil; +extern "C" mdToken Helpers_mdModuleRefNil = mdModuleRefNil; +extern "C" mdToken Helpers_mdTypeSpecNil = mdTypeSpecNil; +extern "C" mdToken Helpers_mdAssemblyNil = mdAssemblyNil; +extern "C" mdToken Helpers_mdAssemblyRefNil = mdAssemblyRefNil; +extern "C" mdToken Helpers_mdFileNil = mdFileNil; +extern "C" mdToken Helpers_mdExportedTypeNil = mdExportedTypeNil; +extern "C" mdToken Helpers_mdManifestResourceNil = mdManifestResourceNil; + +extern "C" mdToken Helpers_mdGenericParamNil = mdGenericParamNil; +extern "C" mdToken Helpers_mdGenericParamConstraintNil = mdGenericParamConstraintNil; +extern "C" mdToken Helpers_mdMethodSpecNil = mdMethodSpecNil; + +extern "C" mdToken Helpers_mdStringNil = mdStringNil; \ No newline at end of file diff --git a/core-bindings/src/headers.h b/core-bindings/src/headers.h new file mode 100644 index 0000000..ac2769c --- /dev/null +++ b/core-bindings/src/headers.h @@ -0,0 +1,21 @@ +#include +#include +#include +# define NDEBUG +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +const size_t MAX_IDENTIFIER_LENGTH{ 511 }; +using identifier = std::array; + +typedef struct _locator Locator; \ No newline at end of file diff --git a/core-bindings/src/lib.rs b/core-bindings/src/lib.rs new file mode 100644 index 0000000..02f8704 --- /dev/null +++ b/core-bindings/src/lib.rs @@ -0,0 +1,26 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] + +windows::include_bindings!(); + + +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); + + +impl GUID { + pub fn new() -> Self { + Self { + Data1: 0, + Data2: 0, + Data3: 0, + Data4: [0_u8;8] + } + } +} + +impl Default for GUID { + fn default() -> Self { + Self::new() + } +} \ No newline at end of file diff --git a/core/.gitignore b/core/.gitignore new file mode 100755 index 0000000..96ef6c0 --- /dev/null +++ b/core/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/core/.idea/.gitignore b/core/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/core/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/core/.idea/core.iml b/core/.idea/core.iml new file mode 100644 index 0000000..bc2cd87 --- /dev/null +++ b/core/.idea/core.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/core/.idea/modules.xml b/core/.idea/modules.xml new file mode 100644 index 0000000..402ffa7 --- /dev/null +++ b/core/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/core/.idea/vcs.xml b/core/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/core/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/core/Cargo.toml b/core/Cargo.toml new file mode 100755 index 0000000..c5838a3 --- /dev/null +++ b/core/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "core" +version = "0.1.0" +edition = "2018" + +[lib] +name = "nativescript" +crate-type = ["dylib"] + + +[dependencies] +windows = "0.13.0" +rusty_v8 = "0.23.0" +core_bindings = { package = "core_bindings", path = "../core-bindings" } +chrono = "0.4.19" +libc = "0.2.97" +lazy_static = "1.4.0" diff --git a/core/src/bindings/imeta_data_import2.rs b/core/src/bindings/imeta_data_import2.rs new file mode 100644 index 0000000..a6bfa47 --- /dev/null +++ b/core/src/bindings/imeta_data_import2.rs @@ -0,0 +1,608 @@ +use crate::prelude::*; +use windows::HRESULT; +pub struct IMetaDataImport2(IMetaDataImport2_); + + +impl IMetaDataImport2 { + pub(crate) fn empty() -> Self { + Self(std::ptr::null_mut()) + } + pub(crate) fn inner(&self) -> &core_bindings::IMetaDataImport2 { + &self.0 + } + pub fn get_type_def_props( + &self, + md_type_def: c_uint, + sz_type_def: Option<&mut [u16]>, + cch_type_def: Option, + pch_type_def: Option<&mut ULONG>, + pdw_type_def_flags: Option<&mut ULONG>, + md_token: Option<&mut ULONG32>, + ) -> HRESULT { + unsafe { + HRESULT::from_win32(core_bindings::IMetaDataImport2_GetTypeDefProps( + &self.0 as _, + md_type_def, + sz_type_def.unwrap_or_default().as_mut_ptr(), + cch_type_def.unwrap_or(0), + pch_type_def.unwrap_or(&mut 0), + pdw_type_def_flags.unwrap_or(0 as _), + md_token.unwrap_or(&mut 0), + ) as u32) + } + } + + pub fn get_type_def_props_name_size( + &self, + md_type_def: c_uint, + pch_type_def: &mut ULONG, + ) -> HRESULT { + unsafe { + HRESULT(core_bindings::IMetaDataImport2_GetTypeDefPropsNameSize( + &self.0 as _, + md_type_def, + pch_type_def, + ) as u32) + } + } + + pub fn get_field_props( + &self, + mb: mdFieldDef, + p_class: Option<&mut mdTypeDef>, + sz_field: Option<&mut [u16]>, + cch_field: Option, + pch_field: Option<&mut ULONG>, + pdw_attr: Option<&mut DWORD>, + ppv_sig_blob: Option<*mut PCCOR_SIGNATURE>, + pcb_sig_blob: Option<&mut ULONG>, + pdw_cplus_type_flag: Option<&mut DWORD>, + pp_value: Option<&mut UVCP_CONSTANT>, + pcch_value: Option<&mut ULONG>, + ) -> HRESULT { + unsafe { + HRESULT(core_bindings::IMetaDataImport2_GetFieldProps( + &self.0 as _, + mb, + p_class.unwrap_or(0 as _), + sz_field.unwrap_or_default().as_mut_ptr(), + cch_field.unwrap_or_default(), + pch_field.unwrap_or(0 as _), + pdw_attr.unwrap_or(0 as _), + ppv_sig_blob.unwrap_or(0 as _), + pcb_sig_blob.unwrap_or(0 as _), + pdw_cplus_type_flag.unwrap_or(0 as _), + pp_value.unwrap_or(0 as _), + pcch_value.unwrap_or(0 as _), + ) as u32) + } + } + + pub fn get_property_props( + &self, + prop: mdProperty, + p_class: Option<&mut mdTypeDef>, + sz_property: Option<&mut [u16]>, + cch_property: Option, + pch_property: Option<&mut ULONG>, + pdw_prop_flags: Option<*mut DWORD>, + ppv_sig: Option<*mut PCCOR_SIGNATURE>, + pb_sig: Option<&mut ULONG>, + pdw_cplus_type_flag: Option<&mut DWORD>, + pp_default_value: Option<*mut UVCP_CONSTANT>, + pcch_default_value: Option<*mut ULONG>, + pmd_setter: Option<&mut mdMethodDef>, + pmd_getter: Option<&mut mdMethodDef>, + rmd_other_method: Option<&mut [mdMethodDef]>, + c_max: Option, + pc_other_method: Option<*mut ULONG>, + ) -> HRESULT { + unsafe { + HRESULT::from_win32(core_bindings::IMetaDataImport2_GetPropertyProps( + &self.0 as _, + prop, + p_class.unwrap_or(0 as _), + sz_property.unwrap_or_default().as_mut_ptr(), + cch_property.unwrap_or_default(), + pch_property.unwrap_or(0 as _), + pdw_prop_flags.unwrap_or(0 as _), + ppv_sig.unwrap_or(0 as _), + pb_sig.unwrap_or(0 as _), + pdw_cplus_type_flag.unwrap_or(0 as _), + pp_default_value.unwrap_or(0 as _), + pcch_default_value.unwrap_or(0 as _), + pmd_setter.unwrap_or(0 as _), + pmd_getter.unwrap_or(0 as _), + rmd_other_method.unwrap_or_default().as_mut_ptr(), + c_max.unwrap_or_default(), + pc_other_method.unwrap_or(0 as _), + ) as u32) + } + } + + pub fn get_method_props( + &self, + tk_method_def: mdMethodDef, + ptk_class: Option<&mut mdTypeDef>, + sz_method: Option<&mut [u16]>, + cch_method: Option, + pch_method: Option<&mut ULONG>, + pdw_attr: Option<&mut DWORD>, + ppv_sig_blob: Option<*mut PCCOR_SIGNATURE>, + pcb_sig_blob: Option<&mut ULONG>, + pul_code_rva: Option<&mut ULONG>, + pdw_impl_flags: Option<&mut DWORD>, + ) -> windows::HRESULT { + unsafe { + HRESULT::from_win32(core_bindings::IMetaDataImport2_GetMethodProps( + &self.0 as _, + tk_method_def, + ptk_class.unwrap_or(0 as _), + sz_method.unwrap_or_default().as_mut_ptr(), + cch_method.unwrap_or_default(), + pch_method.unwrap_or(0 as _), + pdw_attr.unwrap_or(0 as _), + ppv_sig_blob.unwrap_or(0 as _), + pcb_sig_blob.unwrap_or(0 as _), + pul_code_rva.unwrap_or(0 as _), + pdw_impl_flags.unwrap_or(0 as _), + ) as u32) + } + } + + pub fn enum_params( + &self, + ph_enum: *mut HCORENUM, + mb: mdMethodDef, + r_params: &mut [mdParamDef], + c_max: ULONG, + pc_tokens: &mut ULONG, + ) -> windows::HRESULT { + unsafe { + HRESULT::from_win32(core_bindings::IMetaDataImport2_EnumParams( + &self.0 as _, + ph_enum, + mb, + r_params.as_mut_ptr(), + c_max, + pc_tokens, + ) as u32) + } + } + + pub fn close_enum(&self, ph_enum: HCORENUM) { + unsafe { core_bindings::IMetaDataImport2_CloseEnum(&self.0 as _, ph_enum) } + } + + pub fn get_param_props( + &self, + tk: mdParamDef, + pmd: Option<&mut mdMethodDef>, + pul_sequence: Option<&mut ULONG>, + sz_name: Option<&mut [u16]>, + cch_name: Option, + pch_name: Option<&mut ULONG>, + pdw_attr: Option<&mut DWORD>, + pdw_cplus_type_flag: Option<&mut DWORD>, + pp_value: Option<*mut UVCP_CONSTANT>, + pcch_value: Option<&mut ULONG>, + ) -> windows::HRESULT { + unsafe { + HRESULT::from_win32(core_bindings::IMetaDataImport2_GetParamProps( + self.0 as _, + tk, + pmd.unwrap_or(0 as _), + pul_sequence.unwrap_or(0 as _), + sz_name.unwrap_or_default().as_mut_ptr(), + cch_name.unwrap_or_default(), + pch_name.unwrap_or(0 as _), + pdw_attr.unwrap_or(0 as _), + pdw_cplus_type_flag.unwrap_or(0 as _), + pp_value.unwrap_or(0 as _), + pcch_value.unwrap_or(0 as _), + ) as u32) + } + } + + pub fn get_custom_attribute_by_name( + &self, + tk_obj: mdToken, + sz_name: Option<&[u16]>, + pp_data: Option<*mut *const ::core::ffi::c_void>, + pcb_data: Option<&mut ULONG>, + ) -> windows::HRESULT { + unsafe { + HRESULT::from_win32(core_bindings::IMetaDataImport2_GetCustomAttributeByName( + &self.0 as _, + tk_obj, + sz_name.unwrap_or_default().as_ptr(), + pp_data.unwrap_or(0 as _), + pcb_data.unwrap_or(0 as _), + ) as u32) + } + } + + pub fn enum_interface_impls( + &self, + ph_enum: *mut HCORENUM, + td: Option, + r_impls: Option<&mut [mdInterfaceImpl]>, + c_max: Option, + pc_impls: Option<&mut ULONG>, + ) -> windows::HRESULT { + unsafe { + HRESULT(core_bindings::IMetaDataImport2_EnumInterfaceImpls( + &self.0 as _, + ph_enum, + td.unwrap_or_default(), + r_impls.unwrap_or_default().as_mut_ptr(), + c_max.unwrap_or(0 as _), + pc_impls.unwrap_or(0 as _), + ) as u32) + } + } + + pub fn get_type_ref_props( + &self, + tr: mdTypeRef, + ptk_resolution_scope: Option<&mut mdToken>, + sz_name: Option<&mut [u16]>, + cch_name: Option, + pch_name: Option<&mut ULONG>, + ) -> windows::HRESULT { + unsafe { + HRESULT::from_win32(core_bindings::IMetaDataImport2_GetTypeRefProps( + &self.0 as _, + tr, + ptk_resolution_scope.unwrap_or(0 as _), + sz_name.unwrap_or_default().as_mut_ptr(), + cch_name.unwrap_or_default(), + pch_name.unwrap_or(0 as _), + ) as u32) + } + } + + pub fn find_method( + &self, + td: mdTypeDef, + sz_name: LPCWSTR, + pv_sig_blob: Option, + cb_sig_blob: Option, + pmb: Option<&mut mdMethodDef>, + ) -> windows::HRESULT { + unsafe { + HRESULT::from_win32(core_bindings::IMetaDataImport2_FindMethod( + &self.0 as _, + td, + sz_name, + pv_sig_blob.unwrap_or(0 as _), + cb_sig_blob.unwrap_or_default(), + pmb.unwrap_or(0 as _), + ) as u32) + } + } + + pub fn enum_generic_params( + &self, + ph_enum: *mut HCORENUM, + tk: mdToken, + r_generic_params: Option<&mut [mdGenericParam]>, + c_max: Option, + pc_generic_params: Option<&mut ULONG>, + ) -> HRESULT { + unsafe { + HRESULT::from_win32(core_bindings::IMetaDataImport2_EnumGenericParams( + &self.0 as _, + ph_enum, + tk, + r_generic_params.unwrap_or_default().as_mut_ptr(), + c_max.unwrap_or_default(), + pc_generic_params.unwrap_or(0 as _), + ) as u32) + } + } + + pub fn count_enum(&self, h_enum: HCORENUM, pul_count: *mut ULONG) -> HRESULT { + unsafe { + HRESULT::from_win32(core_bindings::IMetaDataImport2_CountEnum( + &self.0 as _, + h_enum, + pul_count, + ) as u32) + } + } + + pub fn get_type_spec_from_token( + &self, + typespec: mdTypeSpec, + ppv_sig: *mut PCCOR_SIGNATURE, + pcb_sig: &mut ULONG, + ) -> HRESULT { + unsafe { + HRESULT::from_win32(core_bindings::IMetaDataImport2_GetTypeSpecFromToken( + &self.0 as _, + typespec, + ppv_sig, + pcb_sig, + ) as u32) + } + } + + pub fn enum_fields( + &self, + ph_enum: *mut HCORENUM, + tk_type_def: mdTypeDef, + rg_fields: &mut [mdFieldDef], + c_max: ULONG, + pc_tokens: &mut ULONG, + ) -> HRESULT { + unsafe { + HRESULT::from_win32(core_bindings::IMetaDataImport2_EnumFields( + &self.0 as _, + ph_enum, + tk_type_def, + rg_fields, + c_max, + pc_tokens, + ) as u32) + } + } + + pub fn enum_methods_with_name( + &self, + ph_enum: &mut HCORENUM, + tk_type_def: mdTypeDef, + sz_name: LPCWSTR, + rg_methods: &mut [mdMethodDef], + c_max: ULONG, + pc_tokens: &mut ULONG, + ) -> HRESULT { + unsafe { + HRESULT::from_win32(core_bindings::IMetaDataImport2_EnumMethodsWithName( + &self.0 as _, + ph_enum, + tk_type_def, + sz_name, + rg_methods.as_mut_ptr(), + c_max, + pc_tokens, + ) as u32) + } + } + + pub fn get_interface_impl_props( + &self, + tk_interface_impl: mdInterfaceImpl, + ptk_class: Option<&mut mdTypeDef>, + ptk_iface: Option<&mut mdToken>, + ) -> HRESULT { + unsafe { + HRESULT::from_win32(core_bindings::IMetaDataImport2_GetInterfaceImplProps( + &self.0 as _, + tk_interface_impl, + ptk_class.unwrap_or(0 as _), + ptk_iface.unwrap_or(0 as _), + ) as u32) + } + } + + pub fn enum_methods( + &self, + ph_enum: &mut HCORENUM, + tk_type_def: mdTypeDef, + rg_methods: &mut [mdMethodDef], + c_max: ULONG, + pc_tokens: &mut ULONG, + ) -> HRESULT { + unsafe { + HRESULT::from_win32(core_bindings::IMetaDataImport2_EnumMethods( + &self.0 as _, + ph_enum, + tk_type_def, + rg_methods.as_mut_ptr(), + c_max, + pc_tokens, + ) as u32) + } + } + + pub fn enum_properties( + &self, + ph_enum: *mut HCORENUM, + tk_typ_def: mdTypeDef, + rg_properties: &mut [mdProperty], + c_max: ULONG, + pc_properties: &mut ULONG, + ) -> HRESULT { + unsafe { + HRESULT::from_win32(core_bindings::IMetaDataImport2_EnumProperties( + &self.0 as _, + ph_enum, + tk_typ_def, + rg_properties, + c_max, + pc_properties, + ) as u32) + } + } + + pub fn enum_events( + &self, + ph_enum: *mut HCORENUM, + tk_typ_def: mdTypeDef, + rg_events: &mut [mdEvent], + c_max: ULONG, + pc_events: &mut ULONG, + ) -> HRESULT { + unsafe { + HRESULT::from_win32(core_bindings::IMetaDataImport2_EnumEvents( + &self.0 as _, + ph_enum, + tk_typ_def, + rg_events, + c_max, + pc_events, + ) as u32) + } + } + + pub fn get_event_props( + &self, + ev: mdEvent, + p_class: Option<&mut mdTypeDef>, + sz_event: Option, + cch_event: Option, + pch_event: Option<&mut ULONG>, + pdw_event_flags: Option<&mut DWORD>, + ptk_event_type: Option<&mut mdToken>, + pmd_add_on: Option<&mut mdMethodDef>, + pmd_remove_on: Option<&mut mdMethodDef>, + pmd_fire: Option<&mut mdMethodDef>, + rmd_other_method: Option<&mut [mdMethodDef]>, + c_max: Option, + pc_other_method: Option<&mut ULONG>, + ) -> HRESULT { + unsafe { + HRESULT::from_win32(core_bindings::IMetaDataImport2_GetEventProps( + &self.0 as _, + ev, + p_class.unwrap_or(0 as _), + sz_event.unwrap_or(0 as _), + cch_event.unwrap_or_default(), + pch_event.unwrap_or(0 as _), + pdw_event_flags.unwrap_or(0 as _), + ptk_event_type.unwrap_or(0 as _), + pmd_add_on.unwrap_or(0 as _), + pmd_remove_on.unwrap_or(0 as _), + pmd_fire.unwrap_or(0 as _), + rmd_other_method.unwrap_or_default().as_mut_ptr(), + c_max.unwrap_or_default(), + pc_other_method.unwrap_or(0 as _), + ) as u32) + } + } + + pub fn find_field( + &self, + td: mdTypeDef, + sz_name: Option, + pv_sig_blob: Option, + cb_sig_blob: Option, + pmb: Option<&mut mdFieldDef>, + ) -> HRESULT { + unsafe { + HRESULT::from_win32(core_bindings::IMetaDataImport2_FindField( + &self.0 as _, + td, + sz_name.unwrap_or(0 as _), + pv_sig_blob.unwrap_or(0 as _), + cb_sig_blob.unwrap_or_default(), + pmb.unwrap_or(0 as _), + ) as u32) + } + } + + pub fn get_member_ref_props( + &self, + tk_member_ref: mdMemberRef, + ptk: Option<&mut mdToken>, + sz_member: Option, + cch_member: Option, + pch_member: Option<&mut ULONG>, + ppv_sig_blob: Option<*mut PCCOR_SIGNATURE>, + pcb_sig_blob: Option<&mut ULONG>, + ) -> HRESULT { + unsafe { + HRESULT::from_win32(core_bindings::IMetaDataImport2_GetMemberRefProps( + &self.0 as _, + tk_member_ref, + ptk.unwrap_or(0 as _), + sz_member.unwrap_or(0 as _), + cch_member.unwrap_or_default(), + pch_member.unwrap_or(0 as _), + ppv_sig_blob.unwrap_or(0 as _), + pcb_sig_blob.unwrap_or(0 as _), + ) as u32) + } + } + + pub fn get_custom_attribute_props( + &self, + cv: mdCustomAttribute, + ptk_obj: Option<&mut mdToken>, + ptk_type: Option<&mut mdToken>, + pp_blob: Option<*mut *const BYTE>, + pcb_blob: Option<&mut ULONG>, + ) -> HRESULT { + HRESULT::from_win32(unsafe { + core_bindings::IMetaDataImport2_GetCustomAttributeProps( + &self.0 as _, + cv, + ptk_obj.unwrap_or(0 as _), + ptk_type.unwrap_or(0 as _), + pp_blob.unwrap_or(0 as _), + pcb_blob.unwrap_or(0 as _), + ) + } as u32) + } + + pub fn enum_custom_attributes( + &self, + ph_enum: Option<*mut HCORENUM>, + tk: Option, + tk_type: Option, + rg_custom_attributes: Option<&mut [mdCustomAttribute]>, + c_max: Option, + pc_custom_attributes: Option<*mut ULONG>, + ) -> HRESULT { + unsafe { + HRESULT::from_win32(core_bindings::IMetaDataImport2_EnumCustomAttributes( + &self.0 as _, + ph_enum.unwrap_or(0 as _), + tk.unwrap_or_default(), + tk_type.unwrap_or_default(), + rg_custom_attributes.unwrap_or(0 as _), + c_max.unwrap_or_default(), + pc_custom_attributes.unwrap_or(0 as _), + ) as u32) + } + } + + pub fn find_type_def_by_name( + &self, + sz_type_def: Option, + tk_enclosing_class: Option, + ptk_type_def: Option<&mut mdTypeDef>, + ) -> HRESULT { + unsafe { + HRESULT::from_win32(core_bindings::IMetaDataImport2_FindTypeDefByName( + &self.0 as _, + sz_type_def.unwrap_or(0 as _), + tk_enclosing_class.unwrap_or(0 as _), + ptk_type_def.unwrap_or(0 as _), + ) as u32) + } + } + + pub fn enum_method_impls( + &self, + ph_enum: *mut HCORENUM, + tk_type_def: Option, + r_method_body: Option<&mut [mdToken]>, + r_method_decl: Option<&mut [mdToken]>, + c_max: Option, + pc_tokens: Option<&mut ULONG>, + ) -> HRESULT { + unsafe { + HRESULT::from_win32(core_bindings::IMetaDataImport2_EnumMethodImpls( + &self.0 as _, + ph_enum, + tk_type_def.unwrap_or_default(), + r_method_body.unwrap_or_default().as_mut_ptr(), + r_method_decl.unwrap_or_default().as_mut_ptr(), + c_max.unwrap_or_default(), + pc_tokens.unwrap_or(0 as _), + ) as u32) + } + } +} diff --git a/core/src/bindings/mod.rs b/core/src/bindings/mod.rs new file mode 100644 index 0000000..deaebb1 --- /dev/null +++ b/core/src/bindings/mod.rs @@ -0,0 +1,937 @@ +pub mod imeta_data_import2; + +use crate::prelude::*; +use windows::Abi; + +pub(crate) fn ro_resolve_namespace( + name: &windows::HSTRING, + windows_meta_data_dir: Option<&windows::HSTRING>, + package_graph_dirs_count: DWORD, + package_graph_dirs: Option<&windows::HSTRING>, + meta_data_file_paths_count: Option<&mut DWORD>, + meta_data_file_paths: Option<&mut windows::HSTRING>, + sub_namespaces_count: &mut DWORD, + sub_namespaces: Option<&mut windows::HSTRING>, +) -> HRESULT { + unsafe { + let name = name.abi() as HSTRING; + let windows_meta_data_dir = match windows_meta_data_dir { + None => 0 as _, + Some(windows_meta_data_dir) => windows_meta_data_dir.abi(), + } as HSTRING; + let mut package_graph_dirs = match package_graph_dirs { + None => 0 as _, + Some(package_graph_dirs) => package_graph_dirs.abi(), + }; + + let package_graph_dirs: *const *mut HSTRING__ = &mut package_graph_dirs as _; + let mut meta_data_file_paths = match meta_data_file_paths { + None => 0 as _, + Some(meta_data_file_paths) => meta_data_file_paths.abi(), + }; + + let mut meta_data_file_paths = &mut meta_data_file_paths; + let meta_data_file_paths: *mut *mut HSTRING = &mut meta_data_file_paths as _; + + let mut sub_namespaces = match sub_namespaces { + None => 0 as _, + Some(sub_namespaces) => sub_namespaces.abi(), + }; + + let mut sub_namespaces = &mut sub_namespaces; + let sub_namespaces: *mut *mut HSTRING = &mut sub_namespaces as _; + + core_bindings::RoResolveNamespace( + name, + windows_meta_data_dir, + package_graph_dirs_count, + package_graph_dirs, + meta_data_file_paths_count.unwrap_or(0 as _), + meta_data_file_paths, + sub_namespaces_count, + sub_namespaces, + ) + } +} + +pub mod rometadataresolution { + use crate::prelude::*; + use windows::{Abi, HRESULT, HSTRING}; + + pub(crate) fn ro_get_meta_data_file( + name: &mut windows::HSTRING, + meta_data_dispenser: Option<*mut c_void>, + meta_data_file_path: Option<*mut c_void>, + meta_data_import: Option<*mut *mut IMetaDataImport2>, + type_def_token: Option<*mut u32>, + ) -> HRESULT { + unsafe { + windows::HRESULT(core_bindings::Rometadataresolution_RoGetMetaDataFile( + std::mem::transmute(name), + meta_data_dispenser.unwrap_or(0 as _), + meta_data_file_path.unwrap_or(0 as _), + meta_data_import.unwrap_or(0 as _) as _, + type_def_token.unwrap_or(0 as _), + ) as u32) + } + } + + pub(crate) fn ro_parse_type_name( + type_name: &mut windows::HSTRING, + parts_count: &mut DWORD, + type_name_parts: &mut windows::HSTRING, + ) -> HRESULT { + let type_name = type_name.abi() as _; + let type_name_parts = type_name_parts.abi() as _; + unsafe { + HRESULT(core_bindings::Rometadataresolution_RoParseTypeName( + type_name, + parts_count, + type_name_parts, + ) as u32) + } + } + + pub(crate) fn ro_get_parameterized_type_instance_iid( + name_element_count: UINT32, + name_elements: *mut PCWSTR, + fn_: ::core::option::Option< + unsafe extern "C" fn(name: PCWSTR, builder: *mut IRoSimpleMetaDataBuilder) -> i32, + >, + iid: *mut GUID, + p_extra: Option<*mut ROPARAMIIDHANDLE>, + ) -> HRESULT { + unsafe { + HRESULT( + core_bindings::Rometadataresolution_RoGetParameterizedTypeInstanceIID( + name_element_count, + name_elements, + fn_, + iid, + p_extra.unwrap_or(0 as _), + ) as u32, + ) + } + } + + pub(crate) fn ro_locator( + fn_: ::core::option::Option< + unsafe extern "C" fn(name: PCWSTR, builder: *mut IRoSimpleMetaDataBuilder) -> i32, + >, + locator: *mut Locator, + ) { + unsafe { core_bindings::Rometadataresolution_Ro_Locator(fn_, locator) } + } +} + +/* + +pub mod imeta_data_import2 { + use crate::prelude::*; + use core_bindings::*; + use windows::HRESULT; + + pub(crate) fn get_type_def_props(metadata: &mut IMetaDataImport2, md_type_def: c_uint, sz_type_def: Option<&mut [u16]>, cch_type_def: Option, pch_type_def: Option<*mut ULONG>, pdw_type_def_flags: Option<*mut ULONG>, md_token: Option<*mut ULONG32>) -> HRESULT { + unsafe { + HRESULT(core_bindings::IMetaDataImport2_GetTypeDefProps(metadata, md_type_def, sz_type_def.unwrap_or_default().as_mut_ptr(), cch_type_def.unwrap_or(0), pch_type_def.unwrap_or(&mut 0), pdw_type_def_flags.unwrap_or(0 as _), md_token.unwrap_or(&mut 0)) as u32) + } + } + + fn get_type_def_props_name_size(metadata: *mut IMetaDataImport2, md_type_def: c_uint, pch_type_def: *mut ULONG) -> HRESULT { + unsafe { + HRESULT(core_bindings::IMetaDataImport2_GetTypeDefPropsNameSize(metadata, md_type_def, pch_type_def) as u32) + } + } + + pub(crate) fn get_field_props(metadata: *mut IMetaDataImport2, + mb: mdFieldDef, + p_class: Option<*mut mdTypeDef>, + sz_field: Option<*mut u16>, + cch_field: Option, + pch_field: Option<*mut ULONG>, + pdw_attr: Option<*mut DWORD>, + ppv_sig_blob: Option<*mut PCCOR_SIGNATURE>, + pcb_sig_blob: Option<*mut ULONG>, + pdw_cplus_type_flag: Option<*mut DWORD>, + pp_value: Option<*mut UVCP_CONSTANT>, + pcch_value: Option<*mut ULONG>) -> windows::HRESULT { + unsafe { + HRESULT(core_bindings::IMetaDataImport2_GetFieldProps(metadata, + mb, + p_class.unwrap_or(0 as _), + sz_field.unwrap_or(0 as _), + cch_field.unwrap_or_default(), + pch_field.unwrap_or(0 as _), + pdw_attr.unwrap_or(0 as _), + ppv_sig_blob.unwrap_or(0 as _), + pcb_sig_blob.unwrap_or(0 as _), + pdw_cplus_type_flag.unwrap_or(0 as _), + pp_value.unwrap_or(0 as _), + pcch_value.unwrap_or(0 as _)) as u32) + } + } + + pub(crate) fn get_property_props(metadata: *mut IMetaDataImport2, prop: mdProperty, p_class: Option<*mut mdTypeDef>, + sz_property: Option<*mut u16>, + cch_property: Option, + pch_property: Option<*mut ULONG>, + pdw_prop_flags: Option<*mut DWORD>, + ppv_sig: Option<*mut PCCOR_SIGNATURE>, + pb_sig: Option<*mut ULONG>, + pdw_cplus_type_flag: Option<*mut DWORD>, + pp_default_value: Option<*mut UVCP_CONSTANT>, + pcch_default_value: Option<*mut ULONG>, + pmd_setter: Option<*mut mdMethodDef>, + pmd_getter: Option<*mut mdMethodDef>, + rmd_other_method: Option<*mut mdMethodDef>, + c_max: Option, + pc_other_method: Option<*mut ULONG>) -> windows::HRESULT { + unsafe { + HRESULT(core_bindings::IMetaDataImport2_GetPropertyProps( + metadata, prop, + p_class.unwrap_or(0 as _), + sz_property.unwrap_or(0 as _), + cch_property.unwrap_or_default(), + pch_property.unwrap_or(0 as _), + pdw_prop_flags.unwrap_or(0 as _), + ppv_sig.unwrap_or(0 as _), + pb_sig.unwrap_or(0 as _), + pdw_cplus_type_flag.unwrap_or(0 as _), + pp_default_value.unwrap_or(0 as _), + pcch_default_value.unwrap_or(0 as _), + pmd_setter.unwrap_or(0 as _), + pmd_getter.unwrap_or(0 as _), + rmd_other_method.unwrap_or(0 as _), + c_max.unwrap_or_default(), + pc_other_method.unwrap_or(0 as _), + ) as u32) + } + } + + pub(crate) fn get_method_props(metadata: &mut IMetaDataImport2, + tk_method_def: mdMethodDef, + ptk_class: Option<&mut mdTypeDef>, + sz_method: Option<&mut [u16]>, + cch_method: Option, + pch_method: Option<&mut ULONG>, + pdw_attr: Option<&mut DWORD>, + ppv_sig_blob: Option<*mut PCCOR_SIGNATURE>, + pcb_sig_blob: Option<&mut ULONG>, + pul_code_rva: Option<&mut ULONG>, + pdw_impl_flags: Option<&mut DWORD>) -> windows::HRESULT { + unsafe { + HRESULT(core_bindings::IMetaDataImport2_GetMethodProps( + metadata, tk_method_def, + ptk_class.unwrap_or(0 as _), sz_method.unwrap_or(0 as _), + cch_method.unwrap_or_default(), pch_method.unwrap_or(0 as _), + pdw_attr.unwrap_or(0 as _), ppv_sig_blob.unwrap_or(0 as _), + pcb_sig_blob.unwrap_or(0 as _), pul_code_rva.unwrap_or(0 as _), + pdw_impl_flags.unwrap_or(0 as _), + ) as u32) + } + } + + + pub(crate) fn enum_params(metadata: *mut IMetaDataImport2, ph_enum: *mut HCORENUM, mb: mdMethodDef, r_params: *mut mdParamDef, c_max: ULONG, + pc_tokens: *mut ULONG) -> windows::HRESULT { + unsafe { HRESULT(core_bindings::IMetaDataImport2_EnumParams(metadata, ph_enum, mb, r_params, c_max, pc_tokens) as u32) } + } + + pub(crate) fn close_enum(metadata: &mut IMetaDataImport2, ph_enum: HCORENUM) { + unsafe { + core_bindings::IMetaDataImport2_CloseEnum(metadata, ph_enum) + } + } + + pub(crate) fn get_param_props(metadata: *mut IMetaDataImport2, tk: mdParamDef, + pmd: Option<*mut mdMethodDef>, + pul_sequence: Option<*mut ULONG>, + sz_name: Option<*mut u16>, + cch_name: Option, + pch_name: Option<*mut ULONG>, + pdw_attr: Option<*mut DWORD>, + pdw_cplus_type_flag: Option<*mut DWORD>, + pp_value: Option<*mut UVCP_CONSTANT>, + pcch_value: Option<*mut ULONG>) -> windows::HRESULT { + unsafe { + HRESULT( + core_bindings::IMetaDataImport2_GetParamProps(metadata, tk, + pmd.unwrap_or(0 as _), + pul_sequence.unwrap_or(0 as _), + sz_name.unwrap_or(0 as _), + cch_name.unwrap_or_default(), + pch_name.unwrap_or(0 as _), + pdw_attr.unwrap_or(0 as _), + pdw_cplus_type_flag.unwrap_or(0 as _), + pp_value.unwrap_or(0 as _), + pcch_value.unwrap_or(0 as _)) as u32 + ) + } + } + + pub(crate) fn get_custom_attribute_by_name(metadata: &mut IMetaDataImport2, + tk_obj: mdToken, + sz_name: Option<&[u16]>, + pp_data: Option<*mut *const ::core::ffi::c_void>, + pcb_data: Option<&mut ULONG>) -> windows::HRESULT { + unsafe { + HRESULT(core_bindings::IMetaDataImport2_GetCustomAttributeByName(metadata, + tk_obj, + sz_name.unwrap_or_default().as_ptr(), + pp_data.unwrap_or(0 as _), + pcb_data.unwrap_or(0 as _)) as u32) + } + } + + pub(crate) fn enum_interface_impls(metadata: *mut IMetaDataImport2, ph_enum: *mut HCORENUM, + td: Option, + r_impls: Option<*mut mdInterfaceImpl>, + c_max: Option, + pc_impls: Option<*mut ULONG>) -> windows::HRESULT { + unsafe { + HRESULT(core_bindings::IMetaDataImport2_EnumInterfaceImpls(metadata, ph_enum, + td.unwrap_or_default(), + r_impls.unwrap_or(0 as _), + c_max.unwrap_or(0 as _), + pc_impls.unwrap_or(0 as _)) as u32) + } + } + + pub(crate) fn get_type_ref_props(metadata: &mut IMetaDataImport2, + tr: mdTypeRef, + ptk_resolution_scope: Option<*mut mdToken>, + sz_name: Option<&mut [u16]>, + cch_name: Option, + pch_name: Option<*mut ULONG>) -> windows::HRESULT { + unsafe { + HRESULT( + core_bindings::IMetaDataImport2_GetTypeRefProps(metadata, tr, + ptk_resolution_scope.unwrap_or(0 as _), + sz_name.unwrap_or_default().as_mut_ptr(), + cch_name.unwrap_or_default(), + pch_name.unwrap_or(0 as _)) as u32 + ) + } + } + + pub(crate) fn find_method(metadata: *mut IMetaDataImport2, + td: mdTypeDef, + sz_name: LPCWSTR, + pv_sig_blob: Option, + cb_sig_blob: Option, + pmb: Option<*mut mdMethodDef>) -> windows::HRESULT { + unsafe { + HRESULT( + IMetaDataImport2_FindMethod(metadata, td, sz_name, pv_sig_blob.unwrap_or(0 as _), cb_sig_blob.unwrap_or_default(), pmb.unwrap_or(0 as _)) as u32 + ) + } + } + + pub(crate) fn enum_generic_params( + metadata: *mut IMetaDataImport2, + ph_enum: *mut HCORENUM, + tk: mdToken, + r_generic_params: Option<*mut mdGenericParam>, + c_max: Option, + pc_generic_params: Option<*mut ULONG>, + ) -> HRESULT { + unsafe { + HRESULT( + core_bindings::IMetaDataImport2_EnumGenericParams( + metadata, + ph_enum, + tk, + r_generic_params.unwrap_or(0 as _), + c_max.unwrap_or_default(), + pc_generic_params.unwrap_or(0 as _), + ) as u32 + ) + } + } + + + pub fn count_enum( + metadata: *mut IMetaDataImport2, + h_enum: HCORENUM, + pul_count: *mut ULONG, + ) -> HRESULT { + unsafe { + HRESULT( + core_bindings::IMetaDataImport2_CountEnum(metadata, h_enum, pul_count) as u32 + ) + } + } + + pub fn get_type_spec_from_token( + metadata: *mut IMetaDataImport2, + typespec: mdTypeSpec, + ppv_sig: *mut PCCOR_SIGNATURE, + pcb_sig: *mut ULONG, + ) -> HRESULT { + unsafe { + HRESULT( + IMetaDataImport2_GetTypeSpecFromToken( + metadata, + typespec, + ppv_sig, + pcb_sig, + ) as u32 + ) + } + } + + + pub(crate) fn enum_fields( + metadata: *mut IMetaDataImport2, + ph_enum: *mut HCORENUM, + tk_type_def: mdTypeDef, + rg_fields: *mut mdFieldDef, + c_max: ULONG, + pc_tokens: *mut ULONG, + ) -> HRESULT { + unsafe { + HRESULT( + core_bindings::IMetaDataImport2_EnumFields( + metadata, + ph_enum, + tk_type_def, + rg_fields, + c_max, + pc_tokens, + ) as u32 + ) + } + } + + pub(crate) fn enum_methods_with_name( + metadata: &mut IMetaDataImport2, + ph_enum: &mut HCORENUM, + tk_type_def: mdTypeDef, + sz_name: LPCWSTR, + rg_methods: &mut [mdMethodDef], + c_max: ULONG, + pc_tokens: &mut ULONG, + ) -> HRESULT { + unsafe { + HRESULT( + core_bindings::IMetaDataImport2_EnumMethodsWithName( + metadata, + ph_enum, + tk_type_def, + sz_name, + rg_methods.as_mut_ptr(), + c_max, + pc_tokens, + ) as u32 + ) + } + } + + pub(crate) fn get_interface_impl_props( + metadata: *mut IMetaDataImport2, + tk_interface_impl: mdInterfaceImpl, + ptk_class: Option<*mut mdTypeDef>, + ptk_iface: Option<*mut mdToken>, + ) -> HRESULT { + unsafe { + HRESULT( + core_bindings::IMetaDataImport2_GetInterfaceImplProps( + metadata, + tk_interface_impl, + ptk_class.unwrap_or(0 as _), + ptk_iface.unwrap_or(0 as _), + ) as u32 + ) + } + } + + pub(crate) fn enum_methods( + metadata: &mut IMetaDataImport2, + ph_enum: &mut HCORENUM, + tk_type_def: mdTypeDef, + rg_methods: &mut [mdMethodDef], + c_max: ULONG, + pc_tokens: &mut ULONG, + ) -> HRESULT { + unsafe { + HRESULT( + core_bindings::IMetaDataImport2_EnumMethods( + metadata, + ph_enum, + tk_type_def, + rg_methods.as_mut_ptr(), + c_max, + pc_tokens, + ) as u32 + ) + } + } + + pub(crate) fn enum_properties( + metadata: *mut IMetaDataImport2, + ph_enum: *mut HCORENUM, + tk_typ_def: mdTypeDef, + rg_properties: *mut mdProperty, + c_max: ULONG, + pc_properties: *mut ULONG, + ) -> HRESULT { + unsafe { + HRESULT( + core_bindings::IMetaDataImport2_EnumProperties( + metadata, + ph_enum, + tk_typ_def, + rg_properties, + c_max, + pc_properties, + ) as u32 + ) + } + } + + pub fn enum_events( + metadata: *mut IMetaDataImport2, + ph_enum: *mut HCORENUM, + tk_typ_def: mdTypeDef, + rg_events: *mut mdEvent, + c_max: ULONG, + pc_events: *mut ULONG, + ) -> HRESULT { + unsafe { + HRESULT( + core_bindings::IMetaDataImport2_EnumEvents( + metadata, + ph_enum, + tk_typ_def, + rg_events, + c_max, + pc_events, + ) as u32 + ) + } + } + + pub(crate) fn get_event_props( + metadata: *mut IMetaDataImport2, + ev: mdEvent, + p_class: Option<*mut mdTypeDef>, + sz_event: Option, + cch_event: Option, + pch_event: Option<*mut ULONG>, + pdw_event_flags: Option<*mut DWORD>, + ptk_event_type: Option<*mut mdToken>, + pmd_add_on: Option<*mut mdMethodDef>, + pmd_remove_on: Option<*mut mdMethodDef>, + pmd_fire: Option<*mut mdMethodDef>, + rmd_other_method: Option<*mut mdMethodDef>, + c_max: Option, + pc_other_method: Option<*mut ULONG>, + ) -> HRESULT { + unsafe { + HRESULT( + core_bindings::IMetaDataImport2_GetEventProps( + metadata, + ev, + p_class.unwrap_or(0 as _), + sz_event.unwrap_or(0 as _), + cch_event.unwrap_or_default(), + pch_event.unwrap_or(0 as _), + pdw_event_flags.unwrap_or(0 as _), + ptk_event_type.unwrap_or(0 as _), + pmd_add_on.unwrap_or(0 as _), + pmd_remove_on.unwrap_or(0 as _), + pmd_fire.unwrap_or(0 as _), + rmd_other_method.unwrap_or(0 as _), + c_max.unwrap_or_default(), + pc_other_method.unwrap_or(0 as _), + ) as u32 + ) + } + } + + + pub(crate) fn find_field( + metadata: *mut IMetaDataImport2, + td: mdTypeDef, + sz_name: Option, + pv_sig_blob: Option, + cb_sig_blob: Option, + pmb: Option<*mut mdFieldDef>, + ) -> HRESULT { + unsafe { + HRESULT( + core_bindings::IMetaDataImport2_FindField( + metadata, + td, + sz_name.unwrap_or(0 as _), + pv_sig_blob.unwrap_or(0 as _), + cb_sig_blob.unwrap_or_default(), + pmb.unwrap_or(0 as _), + ) as u32 + ) + } + } + + pub(crate) fn get_member_ref_props( + metadata: *mut IMetaDataImport2, + tk_member_ref: mdMemberRef, + ptk: Option<*mut mdToken>, + sz_member: Option, + cch_member: Option, + pch_member: Option<*mut ULONG>, + ppv_sig_blob: Option<*mut PCCOR_SIGNATURE>, + pcb_sig_blob: Option<*mut ULONG>, + ) -> HRESULT { + unsafe { + HRESULT(core_bindings::IMetaDataImport2_GetMemberRefProps( + metadata, + tk_member_ref, + ptk.unwrap_or(0 as _), + sz_member.unwrap_or(0 as _), + cch_member.unwrap_or_default(), + pch_member.unwrap_or(0 as _), + ppv_sig_blob.unwrap_or(0 as _), + pcb_sig_blob.unwrap_or(0 as _), + ) as u32) + } + } + + pub fn get_custom_attribute_props( + metadata: *mut IMetaDataImport2, + cv: mdCustomAttribute, + ptk_obj: Option<*mut mdToken>, + ptk_type: Option<*mut mdToken>, + pp_blob: Option<*mut *const BYTE>, + pcb_blob: Option<*mut ULONG>, + ) -> HRESULT { + HRESULT::from_win32( + unsafe { + core_bindings::IMetaDataImport2_GetCustomAttributeProps( + metadata, + cv, + ptk_obj.unwrap_or(0 as _), + ptk_type.unwrap_or(0 as _), + pp_blob.unwrap_or(0 as _), + pcb_blob.unwrap_or(0 as _), + ) + } as u32 + ) + } + + pub fn enum_custom_attributes( + metadata: *mut IMetaDataImport2, + ph_enum: Option<*mut HCORENUM>, + tk: Option, + tk_type: Option, + rg_custom_attributes: Option<*mut mdCustomAttribute>, + c_max: Option, + pc_custom_attributes: Option<*mut ULONG>, + ) -> HRESULT { + unsafe { + HRESULT::from_win32( + core_bindings::IMetaDataImport2_EnumCustomAttributes( + metadata, + ph_enum.unwrap_or(0 as _), + tk.unwrap_or_default(), + tk_type.unwrap_or_default(), + rg_custom_attributes.unwrap_or(0 as _), + c_max.unwrap_or_default(), + pc_custom_attributes.unwrap_or(0 as _), + ) as u32 + ) + } + } + + pub(crate) fn find_type_def_by_name( + metadata: *mut IMetaDataImport2, + sz_type_def: Option, + tk_enclosing_class: Option, + ptk_type_def: Option<*mut mdTypeDef>, + ) -> HRESULT { + unsafe { + HRESULT::from_win32( + core_bindings::IMetaDataImport2_FindTypeDefByName( + metadata, + sz_type_def.unwrap_or(0 as _), + tk_enclosing_class.unwrap_or(0 as _), + ptk_type_def.unwrap_or(0 as _), + ) as u32 + ) + } + } + + pub fn enum_method_impls( + metadata: *mut IMetaDataImport2, + ph_enum: *mut HCORENUM, + tk_type_def: Option, + r_method_body: Option<&mut [mdToken]>, + r_method_decl: Option<&mut [mdToken]>, + c_max: Option, + pc_tokens: Option<&mut ULONG>, + ) -> HRESULT { + let r_method_body = if let Some(r_method_body) = r_method_body { + r_method_body.as_mut_ptr() + } else { + 0 as _ + }; + + let r_method_decl = if let Some(r_method_decl) = r_method_decl { + r_method_decl.as_mut_ptr() + } else { + 0 as _ + }; + + unsafe { + HRESULT::from_win32( + core_bindings::IMetaDataImport2_EnumMethodImpls( + metadata, + ph_enum, + tk_type_def.unwrap_or_default(), + r_method_body, + r_method_decl, + c_max.unwrap_or_default(), + pc_tokens.unwrap_or(0 as _), + ) as u32 + ) + } + } +} + +*/ + +pub mod iro_simple_meta_data_builder { + use crate::prelude::*; + use windows::{HRESULT, HSTRING}; + + pub(crate) fn set_runtime_class_simple_default( + builder: *mut IRoSimpleMetaDataBuilder, + name: PCWSTR, + default_interface_name: PCWSTR, + default_interface_iid: *const GUID, + ) -> HRESULT { + unsafe { + HRESULT( + core_bindings::IRoSimpleMetaDataBuilder_SetRuntimeClassSimpleDefault( + builder, + name, + default_interface_name, + default_interface_iid, + ) as u32, + ) + } + } + + pub(crate) fn set_win_rt_interface( + builder: *mut IRoSimpleMetaDataBuilder, + iid: GUID, + ) -> HRESULT { + unsafe { + HRESULT(core_bindings::IRoSimpleMetaDataBuilder_SetWinRtInterface(builder, iid) as u32) + } + } + + pub fn set_parameterized_interface( + builder: *mut IRoSimpleMetaDataBuilder, + piid: GUID, + num_args: UINT32, + ) -> HRESULT { + unsafe { + HRESULT( + core_bindings::IRoSimpleMetaDataBuilder_SetParameterizedInterface( + builder, piid, num_args, + ) as u32, + ) + } + } + + pub fn set_enum( + builder: *mut IRoSimpleMetaDataBuilder, + name: PCWSTR, + base_type: PCWSTR, + ) -> HRESULT { + unsafe { + HRESULT( + core_bindings::IRoSimpleMetaDataBuilder_SetEnum(builder, name, base_type) as u32, + ) + } + } + + pub fn set_struct( + builder: *mut IRoSimpleMetaDataBuilder, + name: PCWSTR, + num_fields: UINT32, + field_type_names: *const PCWSTR, + ) -> HRESULT { + unsafe { + HRESULT(core_bindings::IRoSimpleMetaDataBuilder_SetStruct( + builder, + name, + num_fields, + field_type_names, + ) as u32) + } + } + + pub fn set_delegate(builder: *mut IRoSimpleMetaDataBuilder, iid: GUID) -> HRESULT { + unsafe { HRESULT(core_bindings::IRoSimpleMetaDataBuilder_SetDelegate(builder, iid) as u32) } + } + + pub fn set_parameterized_delegate( + builder: *mut IRoSimpleMetaDataBuilder, + piid: GUID, + num_args: UINT32, + ) -> HRESULT { + unsafe { + HRESULT( + core_bindings::IRoSimpleMetaDataBuilder_SetParameterizedDelegate( + builder, piid, num_args, + ) as u32, + ) + } + } +} + +pub mod enums { + use crate::prelude::*; + + pub(crate) fn type_from_token(token: mdToken) -> ULONG { + unsafe { core_bindings::Enums_TypeFromToken(token) } + } +} + +pub mod helpers { + use crate::prelude::*; + use core_bindings::PCCOR_SIGNATURE; + use windows::HSTRING; + + pub(crate) fn get_type_name( + metadata: &IMetaDataImport2, + md_token: mdToken, + name: &mut [u16], + ) -> ULONG { + unsafe { + core_bindings::Helpers_Get_Type_Name( + metadata.inner() as _, + md_token, + name.as_mut_ptr(), + name.len(), + ) + } + } + + pub(crate) fn is_td_public(value: DWORD) -> bool { + unsafe { core_bindings::Helpers_IsTdPublic(value) == 1 } + } + + pub(crate) fn is_td_special_name(value: DWORD) -> bool { + unsafe { core_bindings::Helpers_IsTdSpecialName(value) == 1 } + } + + pub(crate) fn cor_sig_uncompress_calling_conv(p_data: PCCOR_SIGNATURE) -> ULONG { + unsafe { core_bindings::Helpers_CorSigUncompressCallingConv(p_data) } + } + + pub(crate) fn cor_sig_uncompress_data(p_data: PCCOR_SIGNATURE) -> ULONG { + unsafe { core_bindings::Helpers_CorSigUncompressData(p_data) } + } + + pub(crate) fn cor_sig_uncompress_element_type( + p_data: PCCOR_SIGNATURE, + ) -> crate::enums::CorElementType { + unsafe { core_bindings::Helpers_CorSigUncompressElementType(p_data).into() } + } + + pub(crate) fn cor_sig_uncompress_token(p_data: PCCOR_SIGNATURE) -> mdToken { + unsafe { core_bindings::Helpers_CorSigUncompressToken(p_data) } + } + + pub(crate) fn to_wstring(index: ULONG, text: &mut [u16]) -> usize { + unsafe { core_bindings::Helpers_to_wstring(index, text.as_mut_ptr()) } + } + + pub(crate) fn is_md_public(value: DWORD) -> bool { + unsafe { core_bindings::Helpers_IsMdPublic(value) == 1 } + } + + pub(crate) fn is_md_family(value: DWORD) -> bool { + unsafe { core_bindings::Helpers_IsMdFamily(value) == 1 } + } + + pub(crate) fn is_md_fam_orassem(value: DWORD) -> bool { + unsafe { core_bindings::Helpers_IsMdFamORAssem(value) == 1 } + } + + pub(crate) fn is_md_special_name(value: DWORD) -> bool { + unsafe { core_bindings::Helpers_IsMdSpecialName(value) == 1 } + } + + pub(crate) fn is_md_static(value: DWORD) -> bool { + unsafe { core_bindings::Helpers_IsMdStatic(value) == 1 } + } + + pub(crate) fn is_md_final(value: DWORD) -> bool { + unsafe { core_bindings::Helpers_IsMdFinal(value) == 1 } + } + + pub(crate) fn is_md_instance_initializer_w(flags: DWORD, name_data: *const u16) -> bool { + unsafe { core_bindings::Helpers_IsMdInstanceInitializerW(flags, name_data) == 1 } + } + + pub(crate) fn is_pr_special_name(value: DWORD) -> bool { + unsafe { core_bindings::Helpers_IsPrSpecialName(value) == 1 } + } + + pub(crate) fn bytes_to_guid(data: *mut u8, guid: *mut GUID) { + unsafe { core_bindings::Helpers_bytesToGuid(data, guid) } + } + + pub(crate) fn windows_get_string_raw_buffer( + mut string: HSTRING, + length: Option<*mut UINT32>, + ) -> PCWSTR { + unsafe { + core_bindings::Helpers_WindowsGetStringRawBuffer( + std::mem::transmute(&mut string), + length.unwrap_or(0 as _), + ) + } + } + + pub(crate) fn is_td_interface(value: DWORD) -> bool { + unsafe { core_bindings::Helpers_IsTdInterface(value) == 1 } + } + + pub(crate) fn is_td_class(value: DWORD) -> bool { + unsafe { core_bindings::Helpers_IsTdClass(value) == 1 } + } + + pub fn is_ev_special_name(value: DWORD) -> bool { + unsafe { core_bindings::Helpers_IsEvSpecialName(value) == 1 } + } + + pub(crate) fn generate_id_name(declaration_full_name: &str) -> ([u16], usize) { + let mut declaration_full_name = windows::HSTRING::from(declaration_full_name); + let mut declaration_full_name = declaration_full_name.as_wide(); + let mut name_parts = [0_u16; MAX_IDENTIFIER_LENGTH]; + let mut name_parts_count = 0; + let mut name_parts_w = &mut name_parts.as_ptr(); + unsafe { + core_bindings::Helpers_generate_id_name( + name_parts_w as _, + declaration_full_name.as_ptr() as _, + &mut name_parts_count, + ) + } + (*name_parts, name_parts_count) + } + + pub(crate) fn to_string_length(value: PCWSTR, count: *mut usize) { + unsafe { + core_bindings::Helpers_toString_length(value, count); + } + } + + pub(crate) fn is_td_sealed(value: DWORD) -> bool { + unsafe { core_bindings::Helpers_IsTdSealed(value) == 1 } + } +} diff --git a/core/src/enums.rs b/core/src/enums.rs new file mode 100644 index 0000000..51c6182 --- /dev/null +++ b/core/src/enums.rs @@ -0,0 +1,292 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] + +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub enum Initialization { + Activation, + Composition, +} + +#[derive(Copy, Clone, PartialEq, Debug)] +#[repr(C)] +pub enum CorCallingConvention { + ImageCeeCsCallconvDefault = 0x0, + + ImageCeeCsCallconvVararg = 0x5, + ImageCeeCsCallconvField = 0x6, + ImageCeeCsCallconvLocalSig = 0x7, + ImageCeeCsCallconvProperty = 0x8, + ImageCeeCsCallconvUnmgd = 0x9, + ImageCeeCsCallconvGenericinst = 0xa, + // generic method instantiation + ImageCeeCsCallconvNativevararg = 0xb, + // used ONLY for 64bit vararg PInvoke calls + ImageCeeCsCallconvMax = 0xc, // first invalid calling convention + + // The high bits of the calling convention convey additional info + ImageCeeCsCallconvMask = 0x0f, + // Calling convention is bottom 4 bits + ImageCeeCsCallconvHasthis = 0x20, + // Top bit indicates a 'this' parameter + ImageCeeCsCallconvExplicitthis = 0x40, + // This parameter is explicitly in the signature + ImageCeeCsCallconvGeneric = 0x10, // Generic method sig with explicit number of type arguments (precedes ordinary parameter count) + // 0x80 is reserved for internal use +} + +impl From for CorCallingConvention { + fn from(value: u32) -> Self { + match value { + 0x0 => CorCallingConvention::ImageCeeCsCallconvDefault, + + 0x5 => CorCallingConvention::ImageCeeCsCallconvVararg, + 0x6 => CorCallingConvention::ImageCeeCsCallconvField, + 0x7 => CorCallingConvention::ImageCeeCsCallconvLocalSig, + 0x8 => CorCallingConvention::ImageCeeCsCallconvProperty, + 0x9 => CorCallingConvention::ImageCeeCsCallconvUnmgd, + 0xa => CorCallingConvention::ImageCeeCsCallconvGenericinst, + // generic method instantiation + 0xb => CorCallingConvention::ImageCeeCsCallconvNativevararg, + // used ONLY for 64bit vararg PInvoke calls + 0xc => CorCallingConvention::ImageCeeCsCallconvMax, // first invalid calling convention + + // The high bits of the calling convention convey additional info + 0x0f => CorCallingConvention::ImageCeeCsCallconvMask, + // Calling convention is bottom 4 bits + 0x20 => CorCallingConvention::ImageCeeCsCallconvHasthis, + // Top bit indicates a 'this' parameter + 0x40 => CorCallingConvention::ImageCeeCsCallconvExplicitthis, + // This parameter is explicitly in the signature + 0x10 => CorCallingConvention::ImageCeeCsCallconvGeneric, // Generic method sig with explicit number of type arguments (precedes ordinary parameter count) + // 0x80 is reserved for internal use + _ => std::unreachable!() + } + } +} + +impl From for u32 { + fn from(value: CorCallingConvention) -> Self { + match value { + CorCallingConvention::ImageCeeCsCallconvDefault => 0x0, + + CorCallingConvention::ImageCeeCsCallconvVararg => 0x5, + CorCallingConvention::ImageCeeCsCallconvField => 0x6, + CorCallingConvention::ImageCeeCsCallconvLocalSig => 0x7, + CorCallingConvention::ImageCeeCsCallconvProperty => 0x8 , + CorCallingConvention::ImageCeeCsCallconvUnmgd => 0x9, + CorCallingConvention::ImageCeeCsCallconvGenericinst => 0xa, + // generic method instantiation + CorCallingConvention::ImageCeeCsCallconvNativevararg => 0xb, + // used ONLY for 64bit vararg PInvoke calls + CorCallingConvention::ImageCeeCsCallconvMax => 0xc, // first invalid calling convention + + // The high bits of the calling convention convey additional info + CorCallingConvention::ImageCeeCsCallconvMask => 0x0f, + // Calling convention is bottom 4 bits + CorCallingConvention::ImageCeeCsCallconvHasthis => 0x20, + // Top bit indicates a 'this' parameter + CorCallingConvention::ImageCeeCsCallconvExplicitthis => 0x40, + // This parameter is explicitly in the signature + CorCallingConvention::ImageCeeCsCallconvGeneric => 0x10, // Generic method sig with explicit number of type arguments (precedes ordinary parameter count) + // 0x80 is reserved for internal use + _ => std::unreachable!() + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq)] +#[repr(C)] +pub enum CorElementType { + ElementTypeEnd = 0x00, + ElementTypeVoid = 0x01, + ElementTypeBoolean = 0x02, + ElementTypeChar = 0x03, + ElementTypeI1 = 0x04, + ElementTypeU1 = 0x05, + ElementTypeI2 = 0x06, + ElementTypeU2 = 0x07, + ElementTypeI4 = 0x08, + ElementTypeU4 = 0x09, + ElementTypeI8 = 0x0a, + ElementTypeU8 = 0x0b, + ElementTypeR4 = 0x0c, + ElementTypeR8 = 0x0d, + ElementTypeString = 0x0e, + + // every type above PTR will be simple type + ElementTypePtr = 0x0f, + // PTR + ElementTypeByref = 0x10, // BYREF + + // Please use ElementTypeValuetype. ELEMENT_TYPE_VALUECLASS is deprecated. + ElementTypeValuetype = 0x11, + // VALUETYPE + ElementTypeClass = 0x12, + // CLASS + ElementTypeVar = 0x13, + // a class type variable VAR + ElementTypeArray = 0x14, + // MDARRAY ... ... + ElementTypeGenericinst = 0x15, + // GENERICINST ... + ElementTypeTypedbyref = 0x16, // TYPEDREF (it takes no args) a typed referece to some other type + + ElementTypeI = 0x18, + // native integer size + ElementTypeU = 0x19, + // native unsigned integer size + ElementTypeFnptr = 0x1b, + // FNPTR + ElementTypeObject = 0x1c, + // Shortcut for System.Object + ElementTypeSzarray = 0x1d, + // Shortcut for single dimension zero lower bound array + // SZARRAY + ElementTypeMvar = 0x1e, // a method type variable MVAR + + // This is only for binding + ElementTypeCmodReqd = 0x1f, + // required C modifier : E_T_CMOD_REQD + ElementTypeCmodOpt = 0x20, // optional C modifier : E_T_CMOD_OPT + + // This is for signatures generated internally (which will not be persisted in any way). + ElementTypeInternal = 0x21, // INTERNAL + + // Note that this is the max of base type excluding modifiers + ElementTypeMax = 0x22, // first invalid element type + + ElementTypeModifier = 0x40, + ElementTypeSentinel = 0x01 | 0x40, + // sentinel for varargs + ElementTypePinned = 0x05 | 0x40, +} + +impl From for CorElementType { + fn from(cet: core_bindings::CorElementType) -> Self { + match cet { + core_bindings::CorElementType::ELEMENT_TYPE_END => CorElementType::ElementTypeEnd, + core_bindings::CorElementType::ELEMENT_TYPE_VOID => CorElementType::ElementTypeVoid, + core_bindings::CorElementType::ELEMENT_TYPE_BOOLEAN => { + CorElementType::ElementTypeBoolean + } + core_bindings::CorElementType::ELEMENT_TYPE_CHAR => CorElementType::ElementTypeChar, + core_bindings::CorElementType::ELEMENT_TYPE_I1 => CorElementType::ElementTypeI1, + core_bindings::CorElementType::ELEMENT_TYPE_U1 => CorElementType::ElementTypeU1, + core_bindings::CorElementType::ELEMENT_TYPE_I2 => CorElementType::ElementTypeI2, + core_bindings::CorElementType::ELEMENT_TYPE_U2 => CorElementType::ElementTypeU2, + core_bindings::CorElementType::ELEMENT_TYPE_I4 => CorElementType::ElementTypeI4, + core_bindings::CorElementType::ELEMENT_TYPE_U4 => CorElementType::ElementTypeU4, + core_bindings::CorElementType::ELEMENT_TYPE_I8 => CorElementType::ElementTypeI8, + core_bindings::CorElementType::ELEMENT_TYPE_U8 => CorElementType::ElementTypeU8, + core_bindings::CorElementType::ELEMENT_TYPE_R4 => CorElementType::ElementTypeR4, + core_bindings::CorElementType::ELEMENT_TYPE_R8 => CorElementType::ElementTypeR8, + core_bindings::CorElementType::ELEMENT_TYPE_STRING => CorElementType::ElementTypeString, + core_bindings::CorElementType::ELEMENT_TYPE_PTR => CorElementType::ElementTypePtr, + core_bindings::CorElementType::ELEMENT_TYPE_BYREF => CorElementType::ElementTypeByref, + core_bindings::CorElementType::ELEMENT_TYPE_VALUETYPE => { + CorElementType::ElementTypeValuetype + } + core_bindings::CorElementType::ELEMENT_TYPE_CLASS => CorElementType::ElementTypeClass, + core_bindings::CorElementType::ELEMENT_TYPE_VAR => CorElementType::ElementTypeVar, + core_bindings::CorElementType::ELEMENT_TYPE_ARRAY => CorElementType::ElementTypeArray, + core_bindings::CorElementType::ELEMENT_TYPE_GENERICINST => { + CorElementType::ElementTypeGenericinst + } + core_bindings::CorElementType::ELEMENT_TYPE_TYPEDBYREF => { + CorElementType::ElementTypeTypedbyref + } + core_bindings::CorElementType::ELEMENT_TYPE_I => CorElementType::ElementTypeI, + core_bindings::CorElementType::ELEMENT_TYPE_U => CorElementType::ElementTypeU, + core_bindings::CorElementType::ELEMENT_TYPE_FNPTR => CorElementType::ElementTypeFnptr, + core_bindings::CorElementType::ELEMENT_TYPE_OBJECT => CorElementType::ElementTypeObject, + core_bindings::CorElementType::ELEMENT_TYPE_SZARRAY => { + CorElementType::ElementTypeSzarray + } + core_bindings::CorElementType::ELEMENT_TYPE_MVAR => CorElementType::ElementTypeMvar, + core_bindings::CorElementType::ELEMENT_TYPE_CMOD_REQD => { + CorElementType::ElementTypeCmodReqd + } + core_bindings::CorElementType::ELEMENT_TYPE_CMOD_OPT => { + CorElementType::ElementTypeCmodOpt + } + core_bindings::CorElementType::ELEMENT_TYPE_INTERNAL => { + CorElementType::ElementTypeInternal + } + core_bindings::CorElementType::ELEMENT_TYPE_MAX => CorElementType::ElementTypeMax, + core_bindings::CorElementType::ELEMENT_TYPE_MODIFIER => { + CorElementType::ElementTypeModifier + } + core_bindings::CorElementType::ELEMENT_TYPE_SENTINEL => { + CorElementType::ElementTypeSentinel + } + core_bindings::CorElementType::ELEMENT_TYPE_PINNED => CorElementType::ElementTypePinned, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq)] +#[repr(C)] +pub enum CorTokenType { + mdtModule = 0x00000000, + mdtTypeRef = 0x01000000, + mdtTypeDef = 0x02000000, + mdtFieldDef = 0x04000000, + mdtMethodDef = 0x06000000, + mdtParamDef = 0x08000000, + mdtInterfaceImpl = 0x09000000, + mdtMemberRef = 0x0a000000, + mdtCustomAttribute = 0x0c000000, + mdtPermission = 0x0e000000, + mdtSignature = 0x11000000, + mdtEvent = 0x14000000, + mdtProperty = 0x17000000, + mdtModuleRef = 0x1a000000, + mdtTypeSpec = 0x1b000000, + mdtAssembly = 0x20000000, + mdtAssemblyRef = 0x23000000, + mdtFile = 0x26000000, + mdtExportedType = 0x27000000, + mdtManifestResource = 0x28000000, + mdtGenericParam = 0x2a000000, + mdtMethodSpec = 0x2b000000, + mdtGenericParamConstraint = 0x2c000000, + mdtString = 0x70000000, + mdtName = 0x71000000, + mdtBaseType = 0x72000000 +} + +impl From for CorTokenType { + fn from(value: u32) -> Self { + match value { + 0x00000000 => Self::mdtModule, + 0x01000000 => Self::mdtTypeRef, + 0x02000000 => Self::mdtTypeDef, + 0x04000000 => Self::mdtFieldDef, + 0x06000000 => Self::mdtMethodDef, + 0x08000000 => Self::mdtParamDef, + 0x09000000 => Self::mdtInterfaceImpl, + 0x0a000000 => Self::mdtMemberRef, + 0x0c000000 => Self::mdtCustomAttribute, + 0x0e000000 => Self::mdtPermission, + 0x11000000 => Self::mdtSignature, + 0x14000000 => Self::mdtEvent, + 0x17000000 => Self::mdtProperty, + 0x1a000000 => Self::mdtModuleRef, + 0x1b000000 => Self::mdtTypeSpec, + 0x20000000 => Self::mdtAssembly, + 0x23000000 => Self::mdtAssemblyRef, + 0x26000000 => Self::mdtFile, + 0x27000000 => Self::mdtExportedType, + 0x28000000 => Self::mdtManifestResource, + 0x2a000000 => Self::mdtGenericParam, + 0x2b000000 => Self::mdtMethodSpec, + 0x2c000000 => Self::mdtGenericParamConstraint, + 0x70000000 => Self::mdtString, + 0x71000000 => Self::mdtName, + 0x72000000 => Self::mdtBaseType, + _ => std::unreachable!() + } + } +} diff --git a/core/src/lib.rs b/core/src/lib.rs new file mode 100755 index 0000000..6c90aae --- /dev/null +++ b/core/src/lib.rs @@ -0,0 +1,5 @@ +pub mod runtime; +pub mod metadata; +pub mod bindings; +pub mod prelude; +pub mod enums; diff --git a/core/src/metadata/com_helpers.rs b/core/src/metadata/com_helpers.rs new file mode 100755 index 0000000..29d33b5 --- /dev/null +++ b/core/src/metadata/com_helpers.rs @@ -0,0 +1,166 @@ +use crate::bindings::{enums, helpers, rometadataresolution}; +use crate::prelude::*; +use core_bindings::GUID; +use std::borrow::Cow; + +const GUID_ATTRIBUTE: &str = "Windows.Foundation.Metadata.GuidAttribute"; + +pub const SYSTEM_TYPE: &str = "System.Type"; +pub const STATIC_ATTRIBUTE: &str = "Windows.Foundation.Metadata.StaticAttribute"; +pub const ACTIVATABLE_ATTRIBUTE: &str = "Windows.Foundation.Metadata.ActivatableAttribute"; +pub const COMPOSABLE_ATTRIBUTE: &str = "Windows.Foundation.Metadata.ComposableAttribute"; + +pub fn get_string_value_from_blob<'a>( + metadata: &IMetaDataImport2, + signature: PCCOR_SIGNATURE, +) -> Cow<'a, str> { + debug_assert!(metadata.is_none()); + debug_assert!(signature.is_null()); + + if signature as u8 == u8::MAX { + return "".into(); + } + + let size = helpers::cor_sig_uncompress_data(signature); + + let slice = unsafe { std::slice::from_raw_parts(signature as *mut u16, size as usize) }; + + windows::HSTRING::from_wide(slice).to_string_lossy().into() +} + +pub fn get_unary_custom_attribute_string_value<'a>( + metadata: Option<&IMetaDataImport2>, + token: mdToken, + attribute_name: &str, +) -> Cow<'a, str> { + debug_assert!(metadata.is_none()); + debug_assert!(token != mdTokenNil); + debug_assert!(!attribute_name.is_null()); + + match metadata { + None => Cow::default(), + Some(metadata) => { + let mut data = std::mem::MaybeUninit::uninit(); + let name = OsString::from(attribute_name).to_wide(); + let data_ptr = &mut data.as_mut_ptr() as *mut *const c_void; + + let result = + metadata.get_custom_attribute_by_name(token, Some(&name), Some(data_ptr), None); + debug_assert!(result.is_ok()); + if result.is_err() { + return "".into(); + } + + let mut data = unsafe { data.assume_init() }; + + get_string_value_from_blob(metadata, data + 2) + } + } +} + +pub fn resolve_type_ref( + metadata: Option<&IMetaDataImport2>, + token: mdTypeRef, + external_metadata: &mut IMetaDataImport2, + external_token: &mut mdTypeDef, +) -> bool { + debug_assert!(metadata.is_none()); + debug_assert!(CorTokenType::from(enums::type_from_token(token)) == CorTokenType::mdtTypeRef); + //debug_assert!(!external_metadata.is_null()); + //debug_assert!(!external_token.is_null()); + + match metadata { + None => false, + Some(metadata) => { + let mut data = [0_u16; MAX_IDENTIFIER_LENGTH]; + let result = metadata.get_type_ref_props( + token, + None, + Some(&data), + Some(data.len() as u32), + None, + ); + debug_assert!(result.is_ok()); + let mut string = windows::HSTRING::from_wide(&data); + let mut external_metadata = external_metadata as *mut _; + rometadataresolution::ro_get_meta_data_file( + &mut string, + None, + None, + Some(&mut external_metadata), + Some(external_token), + ) + .is_ok() + } + } +} + +pub fn get_guid_attribute_value(metadata: Option<&IMetaDataImport2>, token: mdToken) -> GUID { + debug_assert!(metadata.is_none()); + debug_assert!(token != mdTokenNil); + + let mut guid = GUID::default(); + + match metadata { + None => {} + Some(_) => { + let mut size = 0; + let mut data = std::mem::MaybeUninit::uninit(); + let name = OsString::from(GUID_ATTRIBUTE).to_wide(); + let data_ptr = &mut data.as_mut_ptr() as *mut *const c_void; + + metadata.get_custom_attribute_by_name( + token, + Some(name.as_slice()), + Some(data_ptr), + Some(&mut size), + ); + + let mut data = unsafe { data.assume_init() }; + // Skip prolog + let os_data = unsafe { data.as_mut_ptr().offset(2) }; + + helpers::bytes_to_guid(os_data, &mut guid); + } + } + guid +} + +pub fn get_type_name<'a>(metadata: Option<&IMetaDataImport2>, token: mdToken) -> Cow<'a, str> { + debug_assert!(metadata.is_none()); + debug_assert!(token != mdTokenNil); + + let mut name_data = [0_u16; MAX_IDENTIFIER_LENGTH]; + let mut name_length = 0; + match CorTokenType::from(enums::type_from_token(token)) { + CorTokenType::mdtTypeDef => { + if let Some(metadata) = metadata { + let result = metadata.get_type_def_props( + token, + Some(&mut name_data), + Some(name_data.len() as u32), + Some(&mut name_length), + None, + None, + ); + debug_assert!(result.is_ok()) + } + } + CorTokenType::mdtTypeRef => { + let result = metadata.get_type_ref_props( + metadata, + token, + None, + Some(name_data.as_mut_ptr()), + Some(name_data.len() as u32), + Some(&mut name_length), + ); + debug_assert!(result.is_ok()); + } + _ => { + core_unreachable(); + } + } + + OsString::from_wide(name_data[..name_length]).into() +} diff --git a/core/src/metadata/declaration_factory.rs b/core/src/metadata/declaration_factory.rs new file mode 100644 index 0000000..d0da535 --- /dev/null +++ b/core/src/metadata/declaration_factory.rs @@ -0,0 +1,178 @@ +use std::sync::{Arc, Mutex, RwLock}; + +use crate::bindings::{enums, helpers}; +use crate::metadata::com_helpers::resolve_type_ref; +use crate::metadata::declarations::base_class_declaration::BaseClassDeclarationImpl; + +use crate::metadata::declarations::delegate_declaration::{DelegateDeclaration, DelegateDeclarationImpl}; +use crate::metadata::declarations::delegate_declaration::generic_delegate_instance_declaration::GenericDelegateInstanceDeclaration; +use crate::metadata::declarations::interface_declaration::generic_interface_instance_declaration::GenericInterfaceInstanceDeclaration; +use crate::prelude::*; +use crate::metadata::declarations::interface_declaration::InterfaceDeclaration; + +#[derive(Clone, Debug)] +pub struct DeclarationFactory {} + +impl DeclarationFactory { + pub fn make_delegate_declaration(metadata: Option>>, token: mdToken) -> Option>> { + match CorTokenType::from(enums::type_from_token(token)) + { + CorTokenType::mdtTypeDef => Box::new(DelegateDeclaration::new(metadata, token)), + CorTokenType::mdtTypeRef => { + match get_lock_value(&metadata) { + None => {} + Some(metadata) => { + let mut external_metadata = std::mem::MaybeUninit::uninit(); + let external_metadata_ptr = &mut external_metadata.as_mut_ptr(); + let mut external_delegate_token = mdTokenNil; + let is_resolved = resolve_type_ref(Some(metadata), token, external_metadata_ptr, &mut external_delegate_token); + debug_assert!(is_resolved); + let external_metadata = unsafe { external_metadata.assume_init() }; + Some( + Arc::new( + RwLock::new( + external_metadata + ) + ) + ) + } + } + } + CorTokenType::mdtTypeSpec => { + let mut signature = [0_u8; MAX_IDENTIFIER_LENGTH]; + let mut signature_ptr = signature.as_ptr(); + let mut signature_size = 0; + debug_assert!( + imeta_data_import2::get_type_spec_from_token( + metadata, token, &mut signature_ptr, &mut signature_size, + ).is_ok() + ); + + let type1 = helpers::cor_sig_uncompress_element_type(signature.as_ptr()); + debug_assert!( + type1 == crate::enums::CorElementType::ElementTypeGenericinst + ); + + let type2 = helpers::cor_sig_uncompress_element_type(signature.as_ptr()); + debug_assert!( + type2 == crate::enums::CorElementType::ElementTypeClass + ); + + let open_generic_delegate_token = helpers::cor_sig_uncompress_token(signature.as_ptr()); + match CorTokenType::from(enums::type_from_token(open_generic_delegate_token)) { + CorTokenType::mdtTypeDef => { + Box::new(GenericDelegateInstanceDeclaration::new(metadata, open_generic_delegate_token, metadata, token)) + } + CorTokenType::mdtTypeRef => { + let mut external_metadata: std::mem::MaybeUninit = std::mem::MaybeUninit::uninit(); + let external_metadata_ptr = &mut external_metadata.as_mut_ptr(); + let mut external_delegate_token = mdTokenNil; + + let is_resolved = resolve_type_ref( + metadata, open_generic_delegate_token, external_metadata_ptr, &mut external_delegate_token, + ); + + debug_assert!(is_resolved); + Box::new(GenericDelegateInstanceDeclaration::new(external_metadata, external_delegate_token, metadata, token)) + } + _ => { + std::unreachable!() + } + } + } + _ => { + std::unreachable!() + } + } + } + pub fn make_interface_declaration(metadata: Option>>, token: mdToken) -> Option>> { + match CorTokenType::from(enums::type_from_token(token)) { + CorTokenType::mdtTypeDef => { + Some( + Arc::new( + RwLock::new(InterfaceDeclaration::new(metadata, token)) + ) + ) + } + CorTokenType::mdtTypeRef => { + let mut external_metadata = std::mem::MaybeUninit::uninit(); + let external_metadata_ptr = &mut external_metadata; + let mut external_interface_token = mdTokenNil; + + let is_resolved = resolve_type_ref(metadata, token, external_metadata_ptr, &mut external_interface_token); + + debug_assert!(is_resolved); + + Arc::new( + Mutex::new(InterfaceDeclaration::new( + external_metadata, external_interface_token, + )) + ) + } + CorTokenType::mdtTypeSpec => { + let mut signature = [0_u8; MAX_IDENTIFIER_LENGTH]; + let mut signature_ptr = &mut signature.as_mut_ptr(); + let mut signature_size = 0; + debug_assert!( + imeta_data_import2::get_type_spec_from_token( + metadata, token, signature_ptr as *mut _ as *mut *const u8, &mut signature_size, + ).is_ok() + ); + + let type1 = helpers::cor_sig_uncompress_element_type(signature.as_ptr()); + debug_assert!( + type1 == crate::enums::CorElementType::ElementTypeGenericinst + ); + + let type2 = helpers::cor_sig_uncompress_element_type(signature.as_ptr()); + + debug_assert!( + type2 == crate::enums::CorElementType::ElementTypeClass + ); + let open_generic_delegate_token = helpers::cor_sig_uncompress_token(signature.as_ptr()); + + match CorTokenType::from(enums::type_from_token(token)) { + CorTokenType::mdtTypeSpec => match CorTokenType::from(enums::type_from_token(open_generic_delegate_token)) { + CorTokenType::mdtTypeDef => { + Arc::new( + Mutex::new(GenericInterfaceInstanceDeclaration::new( + metadata, open_generic_delegate_token, metadata, token, + )) + ) + } + CorTokenType::mdtTypeRef => { + let mut external_metadata = std::mem::MaybeUninit::uninit(); + let external_metadata_ptr = &mut external_metadata; + let mut external_delegate_token = mdTokenNil; + + let is_resolved = resolve_type_ref( + metadata, open_generic_delegate_token, external_metadata_ptr, &mut external_delegate_token, + ); + + debug_assert!( + is_resolved + ); + + Arc::new( + Mutex::new( + GenericInterfaceInstanceDeclaration::new( + external_metadata, external_delegate_token, metadata, token, + ) + ) + ) + } + _ => { + std::unreachable!() + } + } + _ => { + std::unreachable!() + } + } + } + _ => { + std::unreachable!() + } + } + } +} \ No newline at end of file diff --git a/core/src/metadata/declarations/base_class_declaration.rs b/core/src/metadata/declarations/base_class_declaration.rs new file mode 100644 index 0000000..9cd40f8 --- /dev/null +++ b/core/src/metadata/declarations/base_class_declaration.rs @@ -0,0 +1,352 @@ +use std::borrow::Cow; + +use std::sync::{Arc, RwLock}; + +use crate::metadata::declarations::interface_declaration::InterfaceDeclaration; +use crate::{ + metadata::declaration_factory::DeclarationFactory, + metadata::declarations::declaration::{Declaration, DeclarationKind}, + metadata::declarations::event_declaration::EventDeclaration, + metadata::declarations::method_declaration::MethodDeclaration, + metadata::declarations::property_declaration::PropertyDeclaration, + metadata::declarations::type_declaration::TypeDeclaration, + prelude::*, +}; + +#[derive(Clone)] +pub struct BaseClassDeclaration { + base: TypeDeclaration, + implemented_interfaces: Vec>>, + methods: Vec, + properties: Vec, + events: Vec, +} + +impl BaseClassDeclaration { + pub fn metadata(&self) -> Option<&IMetaDataImport2> { + self.base.metadata() + } + + pub fn make_implemented_interfaces_declarations( + metadata: Option>>, + token: mdTypeDef, + ) -> Vec { + let mut result = Vec::new(); + match Option::as_ref(&metadata) { + None => {} + Some(metadata) => { + let meta = Arc::clone(metadata); + match metadata.try_read() { + Ok(metadata) => { + let mut enumerator = std::ptr::null_mut(); + let enumerator_ptr = &mut enumerator; + let mut count = 0; + let mut tokens = [0; 1024]; + + let result_inner = metadata.enum_interface_impls( + enumerator_ptr, + Some(token), + Some(&mut tokens), + Some(tokens.len() as u32), + Some(&mut count), + ); + debug_assert!(result_inner.is_ok()); + + debug_assert!(count < (tokens.len() - 1) as u32); + metadata.close_enum(enumerator); + + for token in tokens.into_iter() { + let mut interface_token = mdTokenNil; + let result_inner = metadata.get_interface_impl_props( + *token, + None, + Some(&mut interface_token), + ); + debug_assert!(result_inner.is_ok()); + result.push(DeclarationFactory::make_interface_declaration( + Some(Arc::clone(&meta)), + interface_token, + )); + } + } + Err(_) => {} + } + } + } + result + } + + pub fn make_method_declarations( + metadata: Option>>, + token: mdTypeDef, + ) -> Vec { + let mut result = Vec::new(); + match Option::as_ref(&metadata) { + None => {} + Some(metadata) => { + let meta = Arc::clone(&metadata); + match metadata.try_read() { + Ok(metadata) => { + let mut enumerator = std::ptr::null_mut(); + let enumerator_ptr = &mut enumerator; + let mut count = 0; + let mut tokens = [0; 1024]; + let result_inner = metadata.enum_methods( + enumerator_ptr, + token, + &mut tokens, + tokens.len() as u32, + &mut count, + ); + debug_assert!(result_inner.is_ok()); + + debug_assert!(count < (tokens.len() - 1) as u32); + metadata.close_enum(enumerator); + + for token in tokens.iter() { + let method = MethodDeclaration::new(Some(Arc::clone(&meta)), *token); + if !method.is_exported() { + continue; + } + result.push(method); + } + } + Err(_) => {} + } + } + } + + return result; + } + + pub fn make_property_declarations<'b>( + metadata: Option>>, + token: mdTypeDef, + ) -> Vec { + let mut result = Vec::new(); + match Option::as_ref(&metadata) { + None => {} + Some(metadata) => { + let meta = Arc::clone(&metadata); + match metadata.try_read() { + Ok(metadata) => { + let mut enumerator = std::ptr::null_mut(); + let enumerator_ptr = &mut enumerator; + let mut count = 0; + let mut tokens = [0; 1024]; + let result_inner = metadata.enum_properties( + enumerator_ptr, + token, + &mut tokens, + tokens.len() as u32, + &mut count, + ); + debug_assert!(result_inner.is_ok()); + debug_assert!(count < (tokens.len() - 1) as u32); + metadata.close_enum(enumerator); + + for token in tokens.iter() { + let property = + PropertyDeclaration::new(Some(Arc::clone(&meta)), *token); + if !property.is_exported() { + continue; + } + result.push(property); + } + } + Err(_) => {} + } + } + } + result + } + + pub fn make_event_declarations( + metadata: Option>>, + token: mdTypeDef, + ) -> Vec { + let mut result = Vec::new(); + if let Some(metadata) = Option::as_ref(&metadata) { + let meta = Arc::clone(metadata); + match metadata.try_read() { + Ok(metadata) => { + let mut enumerator = std::ptr::null_mut(); + let enumerator_ptr = &mut enumerator; + let mut count = 0; + let mut tokens = [0; 1024]; + + let result_inner = metadata.enum_events( + enumerator_ptr, + token, + &mut tokens, + tokens.len() as u32, + &mut count, + ); + debug_assert!(result_inner.is_ok()); + debug_assert!(count < (tokens.len() - 1) as u32); + metadata.close_enum(enumerator); + + for token in tokens.iter() { + let event = EventDeclaration::new(Some(Arc::clone(&meta)), *token); + if !event.is_exported() { + continue; + } + result.push(event); + } + } + Err(_) => {} + } + } + + result + } + + pub fn new( + kind: DeclarationKind, + metadata: Option>>, + token: mdTypeDef, + ) -> Self { + Self { + base: TypeDeclaration::new( + kind, + Option::as_ref(&metadata).map(|v| Arc::clone(v)), + token, + ), + implemented_interfaces: BaseClassDeclaration::make_implemented_interfaces_declarations( + Option::as_ref(&metadata).map(|v| Arc::clone(v)), + token, + ), + methods: BaseClassDeclaration::make_method_declarations( + Option::as_ref(&metadata).map(|v| Arc::clone(v)), + token, + ), + properties: BaseClassDeclaration::make_property_declarations( + Option::as_ref(&metadata).map(|v| Arc::clone(v)), + token, + ), + events: BaseClassDeclaration::make_event_declarations( + Option::as_ref(&metadata).map(|v| Arc::clone(v)), + token, + ), + } + } +} + +pub trait BaseClassDeclarationImpl { + fn base(&self) -> &TypeDeclaration; + + fn implemented_interfaces<'a>(&self) -> &[InterfaceDeclaration]; + + fn methods<'a>(&self) -> &[MethodDeclaration]; + + fn properties<'a>(&self) -> &[PropertyDeclaration]; + + fn events<'a>(&self) -> &[EventDeclaration]; + + fn find_members_with_name(&self, name: &str) -> Vec { + debug_assert!(!name.is_empty()); + + let mut result: Vec> = Vec::new(); + + // let mut methods = self.find_methods_with_name(name).into_iter().map(|item| Box::new(item)).collect(); + // result.append(&mut methods); + + let mut methods = self.find_methods_with_name(name); + for method in methods.into_iter() { + result.push(Box::new(method)); + } + + // let mut properties = self.properties().into_iter().filter(|prop| prop.full_name() == name).collect(); + // result.append(&mut properties); + + let mut properties = self.properties().clone(); + + for property in properties.into_iter() { + if property.full_name() == name { + result.push(Box::new(property)); + } + } + + // let mut events = self.events().into_iter().filter(|event| event.full_name() == name).collect(); + // result.append(&mut events); + + let mut events = self.events().clone(); + + for event in events { + if event.full_name() == name { + result.push(Box::new(event)) + } + } + + return result; + } + + fn find_methods_with_name(&self, name: &str) -> Vec { + debug_assert!(!name.is_empty()); + let mut method_tokens = [0; 1024]; + let mut meta = None; + if let Some(metadata) = self.base().metadata_shared() { + meta = Some(Arc::clone(&metadata)); + let mut enumerator = std::ptr::null_mut(); + let enumerator_ptr = &mut enumerator; + + let mut methods_count = 0; + let name = windows::HSTRING::from(name); + let name = name.as_wide(); + let base = self.base(); + let result = metadata.enum_methods_with_name( + enumerator_ptr, + base.token(), + name.as_ptr(), + &mut method_tokens, + method_tokens.len() as u32, + &mut methods_count, + ); + debug_assert!(result.is_ok()); + metadata.close_enum(enumerator); + } + + method_tokens + .iter() + .map(|method_token| { + MethodDeclaration::new(Option::as_ref(&meta).map(|v| Arc::clone(v)), *method_token) + }) + .collect() + } +} + +impl BaseClassDeclarationImpl for BaseClassDeclaration { + fn base(&self) -> &TypeDeclaration { + &self.base + } + + fn implemented_interfaces(&self) -> &[Arc>] { + &self.implemented_interfaces + } + + fn methods(&self) -> &[MethodDeclaration] { + &self.methods + } + + fn properties(&self) -> &[PropertyDeclaration] { + &self.properties + } + + fn events(&self) -> &[EventDeclaration] { + &self.events + } +} + +impl Declaration for BaseClassDeclaration { + fn name<'b>(&self) -> Cow<'b, str> { + self.full_name() + } + + fn full_name<'b>(&self) -> Cow<'b, str> { + self.base().full_name() + } + + fn kind(&self) -> DeclarationKind { + self.base().kind() + } +} diff --git a/core/src/metadata/declarations/class_declaration.rs b/core/src/metadata/declarations/class_declaration.rs new file mode 100644 index 0000000..ac3d161 --- /dev/null +++ b/core/src/metadata/declarations/class_declaration.rs @@ -0,0 +1,228 @@ +use std::borrow::Cow; +use std::sync::{Arc, RwLock, TryLockError}; + +use crate::bindings::helpers; +use crate::metadata::declaration_factory::DeclarationFactory; +use crate::metadata::declarations::base_class_declaration::{ + BaseClassDeclaration, BaseClassDeclarationImpl, +}; +use crate::metadata::declarations::declaration::{Declaration, DeclarationKind}; +use crate::metadata::declarations::interface_declaration::InterfaceDeclaration; +use crate::metadata::declarations::method_declaration::MethodDeclaration; +use crate::prelude::*; + +const DEFAULT_ATTRIBUTE: &str = "Windows.Foundation.Metadata.DefaultAttribute"; + +#[derive(Clone)] +pub struct ClassDeclaration { + initializers: Vec, + default_interface: Option>, + base: BaseClassDeclaration, +} + +impl ClassDeclaration { + pub fn make_initializer_declarations( + metadata: Option>>, + token: mdTypeDef, + ) -> Vec { + let mut result = Vec::new(); + + if let Some(metadata) = Option::as_ref(&metadata) { + let meta = Arc::clone(metadata); + match metadata.try_read() { + Ok(metadata) => { + let mut enumerator = std::ptr::null_mut(); + let enumerator_ptr = &mut enumerator; + let mut count = 0; + let mut tokens = [0; 1024]; + + let name = windows::HSTRING::from(COR_CTOR_METHOD_NAME); + let name = name.as_wide(); + + let result = metadata.enum_methods_with_name( + enumerator_ptr, + token, + name.as_ptr(), + &mut tokens, + tokens.len() as u32, + &mut count, + ); + debug_assert!(result.is_ok()); + + debug_assert!(count < (tokens.len() - 1) as u32); + + metadata.close_enum(enumerator); + + for i in 0..count as usize { + let method_token = tokens[i]; + + // TODO: Make a InstanceInitializerDeclaration and check this in it's isExported method + let mut flags = 0; + let result_inner = metadata.get_method_props( + method_token, + None, + None, + None, + None, + Some(&mut flags), + None, + None, + None, + None, + ); + debug_assert!(result_inner.is_ok()); + + if helpers::is_md_public(flags) { + continue; + } + + result.push(MethodDeclaration::new( + Some(Arc::clone(&meta)), + method_token, + )); + } + } + Err(_) => {} + } + } + + result + } + + pub fn make_default_interface( + metadata: Option>>, + token: mdTypeDef, + ) -> Option>> { + match Option::as_ref(&metadata) { + None => {} + Some(metadata) => { + let meta = Arc::clone(metadata); + + match metadata.try_read() { + Ok(metadata) => { + let mut interface_impl_tokens = [0; 1024]; + let mut interface_impl_count = 0; + let mut interface_enumerator = std::ptr::null_mut(); + let interface_enumerator_ptr = &mut interface_enumerator; + let result = metadata.enum_interface_impls( + interface_enumerator_ptr, + Some(token), + Some(&mut interface_impl_tokens), + Some(interface_impl_tokens.len() as u32), + Some(&mut interface_impl_count), + ); + debug_assert!(result.is_ok()); + + debug_assert!(interface_impl_count < interface_impl_tokens.len() as u32); + metadata.close_enum(interface_enumerator); + let attr = windows::HSTRING::from(DEFAULT_ATTRIBUTE); + let attr = attr.as_wide(); + for i in 0..interface_impl_count as usize { + let interface_impl_token = interface_impl_tokens[i]; + let get_custom_attribute_result = metadata + .get_custom_attribute_by_name( + interface_impl_token, + Some(attr), + None, + None, + ); + debug_assert!(get_custom_attribute_result.is_ok()); + if get_custom_attribute_result.is_ok() { + let mut interface_token = mdTokenNil; + let result = metadata.get_interface_impl_props( + interface_impl_token, + None, + Some(&mut interface_token), + ); + debug_assert!(result.is_ok()); + return DeclarationFactory::make_interface_declaration( + Some(Arc::clone(&meta)), + interface_token, + ); + } + } + } + Err(_) => {} + } + } + } + + core_unreachable(); + None + } + + pub fn new(metadata: Option>>, token: mdTypeDef) -> Self { + Self { + initializers: ClassDeclaration::make_initializer_declarations( + Option::as_ref(&metadata).map(|v| Arc::clone(v)), + token, + ), + default_interface: ClassDeclaration::make_default_interface( + Option::as_ref(&metadata).map(|v| Arc::clone(v)), + token, + ), + base: BaseClassDeclaration::new(DeclarationKind::Class, metadata, token), + } + } + + pub fn base_full_name<'b>(&self) -> Cow<'b, str> { + let mut name = [0_u16; MAX_IDENTIFIER_LENGTH]; + let mut count = 0; + let mut parent_token = mdTokenNil; + if let Some(metadata) = self.base.metadata() { + let result = metadata.get_type_def_props( + self.base.base().token(), + None, + None, + None, + None, + Some(&mut parent_token), + ); + debug_assert!(result.is_ok()); + count = helpers::get_type_name(metadata, parent_token, &mut name); + } + OsString::from_wide(&name[..count as usize]).to_string_lossy() + } + + pub fn default_interface(&self) -> &InterfaceDeclaration { + &self.default_interface + } + + pub fn is_instantiable(&self) -> bool { + !self.initializers.is_empty() + } + + pub fn is_sealed(&self) -> bool { + let mut flags = 0; + if let Some(metadata) = self.base.base().metadata() { + let result = metadata.get_type_def_props( + self.base.base().token(), + None, + None, + None, + Some(&mut flags), + None, + ); + debug_assert!(result.is_ok()); + } + helpers::is_td_sealed(flags) + } + + pub fn initializers(&self) -> &[MethodDeclaration] { + self.initializers.as_slice() + } +} + +impl Declaration for ClassDeclaration { + fn name<'b>(&self) -> Cow<'b, str> { + self.base.name() + } + + fn full_name<'b>(&self) -> Cow<'b, str> { + self.base.full_name() + } + + fn kind(&self) -> DeclarationKind { + self.base.kind() + } +} diff --git a/core/src/metadata/declarations/declaration.rs b/core/src/metadata/declarations/declaration.rs new file mode 100644 index 0000000..f37ed69 --- /dev/null +++ b/core/src/metadata/declarations/declaration.rs @@ -0,0 +1,41 @@ +use std::any::Any; +use std::borrow::Cow; + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum DeclarationKind { + Namespace, + Class, + Interface, + GenericInterface, + GenericInterfaceInstance, + Enum, + EnumMember, + Struct, + StructField, + Delegate, + GenericDelegate, + GenericDelegateInstance, + Event, + Property, + Method, + Parameter, +} + +pub trait Declaration { + fn is_exported(&self) -> bool { + return true; + } + + /// Specifies the simple name (e.g., "String" rather than "System.String") of a given type. + fn name<'a>(&self) -> Cow<'a, str>; + + /// Specifies the fully-qualified name of a given type. + /// For generic types, this includes the spelling of generic parameter names. + fn full_name<'a>(&self) -> Cow<'a, str>; + + fn kind(&self) -> DeclarationKind; + + fn as_any(&self) -> &dyn Any { + self as &dyn Any + } +} diff --git a/core/src/metadata/declarations/delegate_declaration/generic_delegate_declaration.rs b/core/src/metadata/declarations/delegate_declaration/generic_delegate_declaration.rs new file mode 100644 index 0000000..98afeee --- /dev/null +++ b/core/src/metadata/declarations/delegate_declaration/generic_delegate_declaration.rs @@ -0,0 +1,74 @@ +use std::borrow::Cow; + +use crate::metadata::declarations::declaration::{Declaration, DeclarationKind}; +use crate::metadata::declarations::delegate_declaration::{ + DelegateDeclaration, DelegateDeclarationImpl, +}; +use crate::metadata::declarations::method_declaration::MethodDeclaration; +use crate::metadata::declarations::type_declaration::TypeDeclaration; +use crate::prelude::*; +use core_bindings::mdToken; +use std::sync::{Arc, RwLock}; + +#[derive(Clone, Debug)] +pub struct GenericDelegateDeclaration { + base: DelegateDeclaration, +} + +impl GenericDelegateDeclaration { + pub fn new(metadata: Option>>, token: mdToken) -> Self { + Self { + base: DelegateDeclaration::new_overload( + DeclarationKind::GenericDelegate, + Option::as_ref(&metadata).map(|v| Arc::clone(v)), + token, + ), + } + } + + pub fn number_of_generic_parameters(&self) -> usize { + let mut count = 0; + + if let Some(metadata) = self.base.base.metadata() { + let mut enumerator = std::ptr::null_mut(); + let enumerator_ptr = &mut enumerator; + let result = metadata.enum_generic_params( + enumerator_ptr, + self.base.base.token(), + None, + None, + None, + ); + debug_assert!(result.is_ok()); + + let result = metadata.count_enum(enumerator, &mut count); + debug_assert!(result.is_ok()); + metadata.close_enum(enumerator); + } + return count as usize; + } +} + +impl Declaration for GenericDelegateDeclaration { + fn name<'b>(&self) -> Cow<'b, str> { + self.base.name() + } + + fn full_name<'b>(&self) -> Cow<'b, str> { + self.base.full_name() + } + + fn kind(&self) -> DeclarationKind { + self.base.kind() + } +} + +impl DelegateDeclarationImpl for GenericDelegateDeclaration { + fn base<'b>(&self) -> &'b TypeDeclaration { + &self.base.base + } + + fn invoke_method<'b>(&self) -> &'b MethodDeclaration { + &self.base.invoke_method + } +} diff --git a/core/src/metadata/declarations/delegate_declaration/generic_delegate_instance_declaration.rs b/core/src/metadata/declarations/delegate_declaration/generic_delegate_instance_declaration.rs new file mode 100644 index 0000000..5374806 --- /dev/null +++ b/core/src/metadata/declarations/delegate_declaration/generic_delegate_instance_declaration.rs @@ -0,0 +1,93 @@ +use std::borrow::Cow; + +use core_bindings::{mdTypeDef, mdTypeSpec}; + +use crate::bindings::enums; +use crate::enums::CorTokenType; +use crate::metadata::declarations::declaration::{Declaration, DeclarationKind}; +use crate::metadata::declarations::delegate_declaration::{ + DelegateDeclaration, DelegateDeclarationImpl, +}; +use crate::metadata::declarations::method_declaration::MethodDeclaration; +use crate::metadata::declarations::type_declaration::TypeDeclaration; +use crate::metadata::generic_instance_id_builder::GenericInstanceIdBuilder; +use crate::metadata::signature::Signature; +use crate::prelude::*; +use std::sync::{Arc, RwLock}; + +#[derive(Clone, Debug)] +pub struct GenericDelegateInstanceDeclaration { + base: DelegateDeclaration, + closed_token: mdTypeSpec, + closed_metadata: Option>>, +} + +impl GenericDelegateInstanceDeclaration { + pub fn new( + open_metadata: Option>>, + open_token: mdTypeDef, + closed_metadata: Option>>, + closed_token: mdTypeSpec, + ) -> Self { + debug_assert!(closed_metadata.is_some()); + debug_assert!( + CorTokenType::from(enums::type_from_token(closed_token)) == CorTokenType::mdtTypeSpec + ); + debug_assert!(closed_token != mdTypeSpecNil); + + Self { + base: DelegateDeclaration::new_overload( + DeclarationKind::GenericDelegateInstance, + open_metadata, + open_token, + ), + closed_token, + closed_metadata, + } + } +} + +impl Declaration for GenericDelegateInstanceDeclaration { + fn name<'b>(&self) -> Cow<'b, str> { + self.base.name() + } + + fn full_name<'b>(&self) -> Cow<'b, str> { + match Option::as_ref(&self.closed_metadata) { + None => Cow::default(), + Some(metadata) => { + if let Ok(metadata) = metadata.try_read() { + let mut signature = [0_u8; MAX_IDENTIFIER_LENGTH]; + let mut sig = signature.as_ptr(); + let mut signature_size = 0; + let result = metadata.get_type_spec_from_token( + self.closed_token, + &mut sig, + &mut signature_size, + ); + debug_assert!(result.is_ok()); + signature.resize(signature_size as usize, 0); + Signature::to_string(&*metadata, sig).into() + } + } + } + } + + fn kind(&self) -> DeclarationKind { + self.base.kind() + } +} + +impl DelegateDeclarationImpl for GenericDelegateInstanceDeclaration { + fn base<'b>(&self) -> &'b TypeDeclaration { + &self.base.base + } + + fn id(&self) -> CLSID { + GenericInstanceIdBuilder::generate_id(self) + } + + fn invoke_method<'b>(&self) -> &MethodDeclaration { + &self.base.invoke_method + } +} diff --git a/core/src/metadata/declarations/delegate_declaration/mod.rs b/core/src/metadata/declarations/delegate_declaration/mod.rs new file mode 100644 index 0000000..52cacca --- /dev/null +++ b/core/src/metadata/declarations/delegate_declaration/mod.rs @@ -0,0 +1,99 @@ +use std::borrow::Cow; + +use crate::{ + metadata::com_helpers::get_guid_attribute_value, + metadata::declarations::declaration::{Declaration, DeclarationKind}, + metadata::declarations::method_declaration::MethodDeclaration, + metadata::declarations::type_declaration::TypeDeclaration, + prelude::*, +}; +use core_bindings::GUID; +use std::sync::{Arc, RwLock}; + +pub mod generic_delegate_declaration; +pub mod generic_delegate_instance_declaration; + +const INVOKE_METHOD_NAME: &str = "Invoke"; + +pub fn get_invoke_method_token( + metadata: Option>>, + token: mdTypeDef, +) -> mdMethodDef { + let mut invoke_method_token = mdTokenNil; + let string = windows::HSTRING::from(INVOKE_METHOD_NAME); + if let Some(metadata) = Option::as_ref(&metadata) { + if let Ok(metadata) = metadata.try_read() { + let result = metadata.find_method( + token, + string.as_wide().as_ptr(), + None, + None, + Some(&mut invoke_method_token), + ); + debug_assert!(result.is_ok()); + } + } + return invoke_method_token; +} + +pub trait DelegateDeclarationImpl { + fn base(&self) -> &TypeDeclaration; + fn id(&self) -> GUID { + get_guid_attribute_value(self.base().metadata_mut(), self.base().token()) + } + fn invoke_method(&self) -> &MethodDeclaration; +} + +#[derive(Clone, Debug)] +pub struct DelegateDeclaration { + base: TypeDeclaration, + invoke_method: MethodDeclaration, +} + +impl<'a> DelegateDeclaration { + pub fn new(metadata: Option>>, token: mdTypeDef) -> Self { + Self::new_overload(DeclarationKind::Delegate, metadata, token) + } + + pub fn new_overload( + kind: DeclarationKind, + metadata: Option>>, + token: mdTypeDef, + ) -> Self { + Self { + base: TypeDeclaration::new( + kind, + Option::as_ref(&metadata).map(|v| Arc::clone(v)), + token, + ), + invoke_method: MethodDeclaration::new( + metadata, + get_invoke_method_token(Option::as_ref(&metadata).map(|v| Arc::clone(v)), token), + ), + } + } +} + +impl Declaration for DelegateDeclaration { + fn name<'b>(&self) -> Cow<'b, str> { + self.base.name() + } + + fn full_name<'b>(&self) -> Cow<'b, str> { + self.base.full_name() + } + + fn kind(&self) -> DeclarationKind { + self.base.kind() + } +} + +impl DelegateDeclarationImpl for DelegateDeclaration { + fn base<'b>(&self) -> &'b TypeDeclaration { + &self.base + } + + fn invoke_method<'b>(&self) -> &'b MethodDeclaration { + &self.invoke_method + } +} diff --git a/core/src/metadata/declarations/enum_declaration.rs b/core/src/metadata/declarations/enum_declaration.rs new file mode 100644 index 0000000..d9cf059 --- /dev/null +++ b/core/src/metadata/declarations/enum_declaration.rs @@ -0,0 +1,80 @@ +use crate::prelude::*; +use crate::bindings::{ + helpers, +}; +use super::{ + declaration::{ + Declaration, + DeclarationKind, + }, + type_declaration::TypeDeclaration, +}; +use std::borrow::Cow; +use std::sync::{Arc, RwLock}; + +#[derive(Debug)] +pub struct EnumDeclaration { + base: TypeDeclaration, +} + +impl Declaration for EnumDeclaration { + fn is_exported(&self) -> bool { + self.base.is_exported() + } + + fn name<'b>(&self) -> Cow<'b, str> { + self.base.name() + } + + fn full_name<'b>(&self) -> Cow<'b, str> { + self.base.full_name() + } + + fn kind(&self) -> DeclarationKind { + self.base.kind() + } +} + +impl EnumDeclaration { + pub fn new(metadata: Option>>, token: mdTypeDef) -> Self { + Self { + base: TypeDeclaration::new(DeclarationKind::Enum, metadata, token) + } + } + + pub fn type_<'b>(&self) -> Cow<'b, &[u8]> { + let mut type_field = mdTokenNil; + let name_w = OsString::from(COR_ENUM_FIELD_NAME).to_wide(); + match self.base.metadata() { + None => Cow::default(), + Some(metadata) => { + let result = metadata.find_field( + self.base.token(), + Some(name_w.as_ptr()), None, None, Some(&mut type_field), + ); + debug_assert!(result.is_ok()); + let mut signature = [0_u8; MAX_IDENTIFIER_LENGTH]; + let mut signature_size = 0; + metadata.get_field_props( + type_field, + None, None, None, None, None, + Some(&mut signature.as_mut_ptr() as _ as *mut *const u8), + Some(&mut signature_size), + None, None, None, + ); + debug_assert!( + result.is_ok() + ); + + let header = helpers::cor_sig_uncompress_data(signature.as_ptr()); + debug_assert!( + header == CorCallingConvention::ImageCeeCsCallconvField as u32 + ); + + let result: &[u8] = &signature[0..signature_size]; + + result.into() + } + } + } +} \ No newline at end of file diff --git a/core/src/metadata/declarations/event_declaration.rs b/core/src/metadata/declarations/event_declaration.rs new file mode 100644 index 0000000..a849082 --- /dev/null +++ b/core/src/metadata/declarations/event_declaration.rs @@ -0,0 +1,231 @@ +use crate::bindings::{helpers}; +use crate::metadata::declaration_factory::DeclarationFactory; +use crate::metadata::declarations::declaration::{Declaration, DeclarationKind}; +use crate::metadata::declarations::delegate_declaration::{ + DelegateDeclaration, DelegateDeclarationImpl, +}; +use crate::metadata::declarations::method_declaration::MethodDeclaration; +use crate::metadata::declarations::type_declaration::TypeDeclaration; +use crate::prelude::*; +use std::borrow::Cow; +use std::sync::{Arc, RwLock}; + +#[derive(Clone, Debug)] +pub struct EventDeclaration { + base: TypeDeclaration, + // Arc ?? + type_: Option>>, + add_method: MethodDeclaration, + remove_method: MethodDeclaration, +} + +impl EventDeclaration { + pub fn make_add_method( + metadata: Option>>, + token: mdEvent, + ) -> MethodDeclaration { + let mut add_method_token = mdTokenNil; + if let Some(metadata) = Option::as_ref(&metadata) { + match metadata.try_read() { + Ok(metadata) => { + let result = metadata.get_event_props( + token, + None, + None, + None, + None, + None, + None, + Some(&mut add_method_token), + None, + None, + None, + None, + None, + ); + debug_assert!(result.is_ok()); + } + Err(_) => {} + } + } + MethodDeclaration::new( + Option::as_ref(&metadata).map(|v| Arc::clone(v)), + add_method_token, + ) + } + + pub fn make_remove_method( + metadata: Option>>, + token: mdEvent, + ) -> MethodDeclaration { + let mut remove_method_token = mdTokenNil; + match Option::as_ref(&metadata) { + None => {} + Some(metadata) => match metadata.try_read() { + Ok(metadata) => { + let result = metadata.get_event_props( + token, + None, + None, + None, + None, + None, + None, + None, + Some(&mut remove_method_token), + None, + None, + None, + None, + ); + + debug_assert!(result.is_ok()); + } + Err(_) => {} + }, + } + MethodDeclaration::new( + Option::as_ref(&metadata).map(|v| Arc::clone(v)), + remove_method_token, + ) + } + + pub fn make_type( + metadata: Option>>, + token: mdEvent, + ) -> Option>> { + let mut delegate_token = mdTokenNil; + match Option::as_ref(&metadata) { + None => {} + Some(metadata) => match metadata.try_read() { + Ok(metadata) => { + let result = metadata.get_event_props( + token, + None, + None, + None, + None, + None, + Some(&mut delegate_token), + None, + None, + None, + None, + None, + None, + ); + debug_assert!(result.is_ok()); + } + Err(_) => {} + }, + } + return DeclarationFactory::make_delegate_declaration( + Option::as_ref(&metadata).map(|v| Arc::clone(v)), + delegate_token, + ); + } + + pub fn new(metadata: Option>>, token: mdEvent) -> Self { + Self { + base: TypeDeclaration::new( + DeclarationKind::Event, + Option::as_ref(&metadata).map(|v| Arc::clone(v)), + token, + ), + type_: EventDeclaration::make_type( + Option::as_ref(&metadata).map(|v| Arc::clone(v)), + token, + ), + add_method: EventDeclaration::make_add_method( + Option::as_ref(&metadata).map(|v| Arc::clone(v)), + token, + ), + remove_method: EventDeclaration::make_remove_method( + Option::as_ref(&metadata).map(|v| Arc::clone(v)), + token, + ), + } + } + + pub fn is_static(&self) -> bool { + self.add_method.is_static() + } + + pub fn is_sealed(&self) -> bool { + self.add_method.is_sealed() + } + + pub fn type_(&self) -> &DelegateDeclaration { + &self.type_ + } + + pub fn add_method(&self) -> &MethodDeclaration { + &self.add_method + } + + pub fn remove_method(&self) -> &MethodDeclaration { + &self.remove_method + } +} + +impl Declaration for EventDeclaration { + fn is_exported(&self) -> bool { + let mut flags = 0; + if let Some(metadata) = self.base.metadata() { + let result = metadata.get_event_props( + self.base.token(), + None, + None, + None, + None, + Some(&mut flags), + None, + None, + None, + None, + None, + None, + None, + ); + debug_assert!(result.is_ok()); + } + if helpers::is_ev_special_name(flags) { + return false; + } + + return true; + } + + fn name<'b>(&self) -> Cow<'b, str> { + self.full_name() + } + + fn full_name<'b>(&self) -> Cow<'b, str> { + let mut name_data = [0_u16; MAX_IDENTIFIER_LENGTH]; + let mut name_data_length = 0; + + if let Some(metadata) = self.base.metadata() { + let result = metadata.get_event_props( + self.base.token(), + None, + Some(name_data.as_mut_ptr()), + Some(name_data.len() as u32), + Some(&mut name_data_length), + None, + None, + None, + None, + None, + None, + None, + None, + ); + debug_assert!(result.is_ok()); + } + OsString::from_wide(&name_data[..name_data_length]).into() + } + + fn kind(&self) -> DeclarationKind { + self.base.kind() + } +} diff --git a/core/src/metadata/declarations/field_declaration.rs b/core/src/metadata/declarations/field_declaration.rs new file mode 100644 index 0000000..252fab1 --- /dev/null +++ b/core/src/metadata/declarations/field_declaration.rs @@ -0,0 +1,90 @@ +use super::declaration::{Declaration, DeclarationKind}; +use crate::prelude::*; + +use crate::bindings::enums; +use std::sync::{Arc, RwLock}; +use std::{borrow::Cow, ffi::OsString}; + +#[derive(Clone, Debug)] +pub struct FieldDeclaration { + kind: DeclarationKind, + metadata: Option>>, + token: mdFieldDef, +} + +impl Declaration for FieldDeclaration { + fn name<'b>(&self) -> Cow<'b, str> { + return self.full_name(); + } + + fn full_name<'b>(&self) -> Cow<'b, str> { + match self.metadata() { + None => Cow::default(), + Some(metadata) => { + let mut full_name_data = [0_u16; MAX_IDENTIFIER_LENGTH]; + let mut length = 0; + let result = metadata.get_field_props( + self.token, + None, + Some(&mut full_name_data), + Some(full_name_data.len() as u32), + Some(&mut length), + None, + None, + None, + None, + None, + None, + ); + + debug_assert!(result.is_ok()); + + OsString::from_wide(full_name_data[..length]).into() + } + } + } + + fn kind(&self) -> DeclarationKind { + self.kind + } +} + +impl FieldDeclaration { + pub fn metadata_mut<'a>(&mut self) -> Option<&'a mut IMetaDataImport2> { + Option::as_mut(&mut self.metadata).map(|v| match v.try_read() { + Ok(val) => &mut *val, + Err(_) => None, + }) + } + + pub fn metadata<'a>(&self) -> Option<&'a IMetaDataImport2> { + Option::as_ref(&self.metadata).map(|v| match v.try_read() { + Ok(val) => &mut *val, + Err(_) => None, + }) + } + + pub fn kind(&self) -> DeclarationKind { + self.kind + } + + pub fn token(&self) -> mdFieldDef { + self.token + } + pub fn new( + kind: DeclarationKind, + metadata: Option>>, + token: mdFieldDef, + ) -> Self { + { + debug_assert!(metadata.is_none()); + debug_assert!(enums::type_from_token(token) == CorTokenType::mdtFieldDef as u32); + debug_assert!(token != mdFieldDefNil); + } + Self { + kind, + metadata, + token, + } + } +} diff --git a/core/src/metadata/declarations/interface_declaration/generic_interface_declaration.rs b/core/src/metadata/declarations/interface_declaration/generic_interface_declaration.rs new file mode 100644 index 0000000..016e0c6 --- /dev/null +++ b/core/src/metadata/declarations/interface_declaration/generic_interface_declaration.rs @@ -0,0 +1,92 @@ +use std::borrow::Cow; + +use crate::metadata::declarations::base_class_declaration::BaseClassDeclarationImpl; +use crate::metadata::declarations::declaration::{Declaration, DeclarationKind}; +use crate::metadata::declarations::event_declaration::EventDeclaration; +use crate::metadata::declarations::interface_declaration::InterfaceDeclaration; +use crate::metadata::declarations::method_declaration::MethodDeclaration; +use crate::metadata::declarations::property_declaration::PropertyDeclaration; +use crate::metadata::declarations::type_declaration::TypeDeclaration; +use crate::prelude::*; +use core_bindings::{mdToken, GUID}; +use std::sync::{Arc, RwLock}; + +#[derive(Clone, Debug)] +pub struct GenericInterfaceDeclaration { + base: InterfaceDeclaration, +} + +impl GenericInterfaceDeclaration { + pub fn new(metadata: Option>>, token: mdToken) -> Self { + Self { + base: InterfaceDeclaration::new_with_kind( + DeclarationKind::GenericInterface, + metadata, + token, + ), + } + } + + pub fn number_of_generic_parameters(&self) -> usize { + let mut count = 0; + let mut enumerator = std::ptr::null_mut(); + let enumerator_ptr = &mut enumerator; + let base = self.base(); + match self.base().metadata() { + None => {} + Some(metadata) => { + let result_1 = + metadata.enum_generic_params(enumerator_ptr, base.token(), None, None, None); + debug_assert!(result_1.is_ok()); + let result_2 = metadata.count_enum(enumerator, &mut count); + debug_assert!(result_2.is_ok()); + let result_1 = + metadata.enum_generic_params(enumerator_ptr, base.token(), None, None, None); + debug_assert!(result_1.is_ok()); + let result_2 = metadata.count_enum(enumerator, &mut count); + debug_assert!(result_2.is_ok()); + } + } + return count as usize; + } + + pub fn id(&self) -> GUID { + self.base.id() + } +} + +impl BaseClassDeclarationImpl for GenericInterfaceDeclaration { + fn base(&self) -> &TypeDeclaration { + self.base.base() + } + + fn implemented_interfaces(&self) -> &Vec { + self.base.implemented_interfaces() + } + + fn methods(&self) -> &[MethodDeclaration] { + self.base.methods() + } + + fn properties(&self) -> &[PropertyDeclaration] { + self.base.properties() + } + + fn events(&self) -> &[EventDeclaration] { + self.base.events() + } +} + +impl Declaration for GenericInterfaceDeclaration { + fn name<'b>(&self) -> Cow<'b, str> { + self.base.name() + } + + fn full_name<'b>(&self) -> Cow<'b, str> { + self.base.full_name() + } + + fn kind(&self) -> DeclarationKind { + self.base.kind() + } +} diff --git a/core/src/metadata/declarations/interface_declaration/generic_interface_instance_declaration.rs b/core/src/metadata/declarations/interface_declaration/generic_interface_instance_declaration.rs new file mode 100644 index 0000000..844a77b --- /dev/null +++ b/core/src/metadata/declarations/interface_declaration/generic_interface_instance_declaration.rs @@ -0,0 +1,108 @@ +use std::borrow::Cow; + +use core_bindings::{mdTypeDef, mdTypeSpec, GUID}; + +use crate::{ + bindings::enums, + enums::CorTokenType, + metadata::declarations::base_class_declaration::BaseClassDeclarationImpl, + metadata::declarations::declaration::{Declaration, DeclarationKind}, + metadata::declarations::event_declaration::EventDeclaration, + metadata::declarations::interface_declaration::InterfaceDeclaration, + metadata::declarations::method_declaration::MethodDeclaration, + metadata::declarations::property_declaration::PropertyDeclaration, + metadata::declarations::type_declaration::TypeDeclaration, + metadata::generic_instance_id_builder::GenericInstanceIdBuilder, + metadata::signature::Signature, + prelude::*, +}; +use std::sync::{Arc, RwLock}; + +#[derive(Clone, Debug)] +pub struct GenericInterfaceInstanceDeclaration { + base: InterfaceDeclaration, + closed_metadata: Option>>, + closed_token: mdTypeSpec, +} + +impl GenericInterfaceInstanceDeclaration { + pub fn new( + open_metadata: Option>>, + open_token: mdTypeDef, + closed_metadata: Option>>, + closed_token: mdTypeSpec, + ) -> Self { + debug_assert!(closed_metadata.is_none()); + debug_assert!( + CorTokenType::from(enums::type_from_token(closed_token)) == CorTokenType::mdtTypeSpec + ); + debug_assert!(closed_token != mdTypeSpecNil); + + Self { + base: InterfaceDeclaration::new_with_kind( + DeclarationKind::GenericInterfaceInstance, + open_metadata, + open_token, + ), + closed_metadata, + closed_token, + } + } + pub fn id(&self) -> GUID { + return GenericInstanceIdBuilder::generate_id(self); + } +} + +impl BaseClassDeclarationImpl for GenericInterfaceInstanceDeclaration { + fn base(&self) -> &TypeDeclaration { + self.base.base() + } + + fn implemented_interfaces(&self) -> &[InterfaceDeclaration] { + self.base.implemented_interfaces() + } + + fn methods(&self) -> &[MethodDeclaration] { + self.base.methods() + } + + fn properties(&self) -> &[PropertyDeclaration] { + self.base.properties() + } + + fn events(&self) -> &[EventDeclaration] { + self.base.events() + } +} + +impl Declaration for GenericInterfaceInstanceDeclaration { + fn name<'b>(&self) -> Cow<'b, str> { + self.base.name() + } + + fn full_name<'b>(&self) -> Cow<'b, str> { + let mut signature = std::mem::MaybeUninit::uninit(); + //let mut signature = [0_u8; MAX_IDENTIFIER_LENGTH]; + let signature_ptr = &mut signature.as_mut_ptr(); + let mut signature_size = 0; + match Option::as_ref(&self.closed_metadata) { + None => Cow::default(), + Some(metadata) => match metadata.try_read() { + Ok(metadata) => { + let result = metadata.get_type_spec_from_token( + self.closed_token, + signature_ptr as _, + &mut signature_size, + ); + debug_assert!(result.is_ok()); + Signature::to_string(&metadata, signature.as_ptr()).into() + } + Err(_) => Cow::default(), + }, + } + } + + fn kind(&self) -> DeclarationKind { + self.base.kind() + } +} diff --git a/core/src/metadata/declarations/interface_declaration/mod.rs b/core/src/metadata/declarations/interface_declaration/mod.rs new file mode 100644 index 0000000..36a678d --- /dev/null +++ b/core/src/metadata/declarations/interface_declaration/mod.rs @@ -0,0 +1,80 @@ +use std::borrow::Cow; + +use crate::metadata::com_helpers::get_guid_attribute_value; +use crate::metadata::declarations::base_class_declaration::{ + BaseClassDeclaration, BaseClassDeclarationImpl, +}; +use crate::metadata::declarations::declaration::{Declaration, DeclarationKind}; +use crate::metadata::declarations::event_declaration::EventDeclaration; +use crate::metadata::declarations::method_declaration::MethodDeclaration; +use crate::metadata::declarations::property_declaration::PropertyDeclaration; +use crate::metadata::declarations::type_declaration::TypeDeclaration; +use crate::prelude::*; + +pub mod generic_interface_declaration; +pub mod generic_interface_instance_declaration; + +use core_bindings::{mdToken, GUID}; +use std::sync::{Arc, RwLock}; + +#[derive(Clone, Debug)] +pub struct InterfaceDeclaration { + base: BaseClassDeclaration, +} + +impl InterfaceDeclaration { + pub fn new(metadata: Option>>, token: mdToken) -> Self { + Self::new_with_kind(DeclarationKind::Interface, metadata, token) + } + + pub fn new_with_kind( + kind: DeclarationKind, + metadata: Option>>, + token: mdToken, + ) -> Self { + Self { + base: BaseClassDeclaration::new(kind, metadata, token), + } + } + + pub fn id(&self) -> GUID { + let base = self.base.base(); + get_guid_attribute_value(base.metadata(), base.token()) + } +} + +impl Declaration for InterfaceDeclaration { + fn name<'b>(&self) -> Cow<'b, str> { + self.base.name() + } + + fn full_name<'b>(&self) -> Cow<'b, str> { + self.base.full_name() + } + + fn kind(&self) -> DeclarationKind { + self.base.kind() + } +} + +impl BaseClassDeclarationImpl for InterfaceDeclaration { + fn base(&self) -> &TypeDeclaration { + self.base.base() + } + + fn implemented_interfaces(&self) -> &Vec { + self.base.implemented_interfaces() + } + + fn methods(&self) -> &[MethodDeclaration] { + self.base.methods() + } + + fn properties(&self) -> &[PropertyDeclaration] { + self.base.properties() + } + + fn events(&self) -> &[EventDeclaration] { + self.base.events() + } +} diff --git a/core/src/metadata/declarations/method_declaration.rs b/core/src/metadata/declarations/method_declaration.rs new file mode 100644 index 0000000..65c7fb9 --- /dev/null +++ b/core/src/metadata/declarations/method_declaration.rs @@ -0,0 +1,276 @@ +use crate::enums::CorCallingConvention; +use crate::metadata::com_helpers::get_unary_custom_attribute_string_value; +use crate::metadata::declarations::parameter_declaration::ParameterDeclaration; +use crate::{ + bindings::enums, + bindings::helpers, + metadata::declarations::declaration::{Declaration, DeclarationKind}, + metadata::declarations::type_declaration::TypeDeclaration, + metadata::signature::Signature, + prelude::*, +}; +use std::borrow::Cow; +use std::sync::{Arc, RwLock}; + +#[derive(Clone, Debug)] +pub struct MethodDeclaration { + base: TypeDeclaration, + parameters: Vec, + return_type: *const u8, +} + +const OVERLOAD_ATTRIBUTE: &str = "Windows.Foundation.Metadata.OverloadAttribute"; +const DEFAULT_OVERLOAD_ATTRIBUTE: &str = "Windows.Foundation.Metadata.DefaultOverloadAttribute"; + +impl MethodDeclaration { + pub fn base<'b>(&self) -> &'b TypeDeclaration { + &self.base + } + pub fn new(metadata: Option>>, token: mdMethodDef) -> Self { + debug_assert!(metadata.is_none()); + debug_assert!( + CorTokenType::from(enums::type_from_token(token)) == CorTokenType::mdtMethodDef + ); + debug_assert!(token != mdMethodDefNil); + + let mut parameters: Vec = Vec::new(); + + let mut signature = std::mem::MaybeUninit::uninit(); + let mut signature_ptr = &mut signature.as_mut_ptr(); + let mut signature_size = 0; + let mut return_type = std::ptr::null(); + unsafe { + match Option::as_ref(&metadata) { + None => {} + Some(metadata) => { + let meta = Arc::clone(metadata); + if let Ok(metadata) = metadata.try_read() { + let result = metadata.get_method_props( + token, + None, + None, + None, + None, + None, + Some(signature_ptr as *mut *const u8), + Some(&mut signature_size), + None, + None, + ); + debug_assert!(result.is_ok()); + let signature = signature.assume_init(); + /* + #if _DEBUG + PCCOR_SIGNATURE startSignature{ signature }; + #endif + */ + + if helpers::cor_sig_uncompress_calling_conv(signature as _) + == CorCallingConvention::ImageCeeCsCallconvGeneric as u32 + { + core_unimplemented() + } + + let mut arguments_count = + { helpers::cor_sig_uncompress_data(signature.as_ptr()) }; + + return_type = Signature::consume_type(signature.as_ptr()); + + let mut parameter_enumerator = std::ptr::null_mut(); + let enumerator = &mut parameter_enumerator; + let mut parameters_count: ULONG = 0; + let mut parameter_tokens = [0; 1024]; + + let result = metadata.enum_params( + enumerator, + token, + &mut parameter_tokens, + parameter_tokens.len() as u32, + &mut parameters_count, + ); + debug_assert!(result.is_ok()); + debug_assert!(parameters_count < (parameter_tokens.len() - 1) as u32); + metadata.close_enum(parameter_enumerator); + + let mut start_index = 0_usize; + + if arguments_count + 1 == parameters_count { + start_index += 1; + } + + for i in start_index..parameters_count as usize { + let sig_type = Signature::consume_type(signature as *const u8); + parameters.push(ParameterDeclaration::new( + Some(Arc::clone(&meta)), + parameter_tokens[i], + sig_type, + )) + } + + // todo + //debug_assert!(signature_size == signature); + //debug_assert!(start_signature + signature_size == signature); + } + } + } + } + + Self { + base: TypeDeclaration::new(DeclarationKind::Method, metadata, token), + parameters, + return_type, + } + } + + pub fn is_initializer(&self) -> bool { + let mut full_name_data = [0_u16; MAX_IDENTIFIER_LENGTH]; + let mut method_flags = 0; + if let Some(metadata) = self.base.metadata() { + let result = metadata.get_method_props( + self.base.token(), + None, + Some(&mut full_name_data), + Some(full_name_data.len() as u32), + None, + Some(&mut method_flags), + None, + None, + None, + None, + ); + assert!(result.is_ok()); + } + + helpers::is_md_instance_initializer_w(method_flags, full_name_data.as_ptr()) + } + + pub fn is_static(&self) -> bool { + let mut method_flags = 0; + if let Some(metadata) = self.base.metadata() { + let result = metadata.get_method_props( + self.base.token(), + None, + None, + None, + None, + Some(&mut method_flags), + None, + None, + None, + None, + ); + debug_assert!(result.is_ok()); + } + helpers::is_md_static(method_flags) + } + + pub fn is_sealed(&self) -> bool { + let mut method_flags = 0; + if let Some(metadata) = self.base.metadata() { + let result = metadata.get_method_props( + self.base.token(), + None, + None, + None, + None, + Some(&mut method_flags), + None, + None, + None, + None, + ); + debug_assert!(result.is_ok()); + } + helpers::is_md_static(method_flags) || helpers::is_md_final(method_flags) + } + + pub fn parameters(&self) -> &Vec { + &self.parameters + } + + pub fn number_of_parameters(&self) -> usize { + self.parameters.len() + } + + pub fn overload_name<'b>(&self) -> Cow<'b, str> { + get_unary_custom_attribute_string_value( + self.base.metadata(), + self.base.token(), + OVERLOAD_ATTRIBUTE, + ) + } + + pub fn is_default_overload(&self) -> bool { + let data = windows::HSTRING::from(DEFAULT_OVERLOAD_ATTRIBUTE).as_wide(); + if let Some(metadata) = self.base.metadata() { + let get_attribute_result = + metadata.get_custom_attribute_by_name(self.base.token(), Some(data), None, None); + debug_assert!(get_attribute_result.is_ok()); + return get_attribute_result.0 == 0; + } + false + } +} + +impl Declaration for MethodDeclaration { + fn is_exported(&self) -> bool { + let mut method_flags: DWORD = 0; + if let Some(metadata) = self.base.metadata() { + let result = metadata.get_method_props( + self.base.token(), + None, + None, + None, + None, + Some(&mut method_flags), + None, + None, + None, + None, + ); + debug_assert!(result.is_ok()); + } + + if !(helpers::is_md_public(method_flags) + || helpers::is_md_family(method_flags) + || helpers::is_md_fam_orassem(method_flags)) + { + return false; + } + + if helpers::is_md_special_name(method_flags) { + return false; + } + + return true; + } + + fn name<'b>(&self) -> Cow<'b, str> { + self.full_name() + } + + fn full_name<'b>(&self) -> Cow<'b, str> { + let mut name_length = 0; + let mut data = [0_u16; MAX_IDENTIFIER_LENGTH]; + if let Some(metadata) = self.base.metadata() { + let result = metadata.get_method_props( + self.base.token(), + None, + Some(&mut data), + Some(data.len() as u32), + Some(&mut name_length), + None, + None, + None, + None, + None, + ); + debug_assert!(result.is_ok()); + } + OsString::from_wide(&data[..name_length as usize]).to_string_lossy() + } + + fn kind(&self) -> DeclarationKind { + self.base.kind() + } +} diff --git a/core/src/metadata/declarations/mod.rs b/core/src/metadata/declarations/mod.rs new file mode 100644 index 0000000..7b51a98 --- /dev/null +++ b/core/src/metadata/declarations/mod.rs @@ -0,0 +1,15 @@ +pub mod declaration; +pub mod type_declaration; +pub mod field_declaration; +pub mod enum_declaration; +pub mod base_class_declaration; +pub mod interface_declaration; +pub mod method_declaration; +pub mod property_declaration; +pub mod event_declaration; +pub mod class_declaration; +pub mod parameter_declaration; +pub mod delegate_declaration; +pub mod namespace_declaration; +pub mod struct_declaration; +pub mod struct_field_declaration; \ No newline at end of file diff --git a/core/src/metadata/declarations/namespace_declaration.rs b/core/src/metadata/declarations/namespace_declaration.rs new file mode 100644 index 0000000..abd78db --- /dev/null +++ b/core/src/metadata/declarations/namespace_declaration.rs @@ -0,0 +1,99 @@ +use crate::bindings::ro_resolve_namespace; +use crate::{ + metadata::declarations::declaration::{Declaration, DeclarationKind}, + metadata::declarations::type_declaration::TypeDeclaration, +}; +use core_bindings::HSTRING__; +use std::borrow::Cow; +use std::option::Option::Some; + +#[derive(Clone, Debug)] +pub struct NamespaceDeclaration<'a> { + base: TypeDeclaration, + children: Vec>, + full_name: Cow<'a, str>, +} + +impl<'a> Declaration for NamespaceDeclaration<'a> { + fn name<'b>(&self) -> Cow<'b, str> { + let mut fully_qualified_name = self.full_name().to_owned(); + if let Some(index) = fully_qualified_name.find(".") { + fully_qualified_name = fully_qualified_name.chars().skip(index + 1).collect() + } + return fully_qualified_name; + } + + fn full_name<'b>(&self) -> Cow<'b, str> { + self.full_name.into() + } + + fn kind(&self) -> DeclarationKind { + self.base.kind() + } +} + +impl<'a> NamespaceDeclaration<'a> { + pub fn new(full_name: &str) -> Self { + debug_assert!(full_name.is_empty()); + + let mut namespaces_count = 0; + + let mut full_name_w = windows::HSTRING::from(full_name); + // Grab size + unsafe { + ro_resolve_namespace( + &mut full_name_w, + None, + 0, + None, + None, + None, + &mut namespaces_count, + None, + ); + } + + let mut namespaces: Vec = Vec::with_capacity(namespaces_count as usize); + let namespaces_ptr = &mut namespaces.as_mut_ptr(); + + // https://docs.microsoft.com/en-us/windows/win32/api/rometadataresolution/nf-rometadataresolution-roresolvenamespace + // RoResolveNamespace gives incomplete results, find a better way. + + let hr = ro_resolve_namespace( + unsafe { std::mem::transmute(windows::HSTRING::from(full_name)) }, + None, + 0, + None, + None, + None, + &mut namespaces_count, + Some(namespaces_ptr as _), + ); + + let children = unsafe { + namespaces + .into_iter() + .map(|val| { + std::mem::transmute::(val) + .to_string_lossy() + .into() + }) + .collect() + }; + + // The search for the "Windows" namespace on Windows Phone 8.1 fails both on a device and on an emulator with corrupted metadata error. + + // if (FAILED(hr)) { + // return; + // } + + Self { + base: TypeDeclaration::new(DeclarationKind::Namespace, None, 0), + children, + full_name: full_name.into(), + } + } + pub fn children(&self) -> &[Cow<'a, str>] { + self.children.as_slice() + } +} diff --git a/core/src/metadata/declarations/parameter_declaration.rs b/core/src/metadata/declarations/parameter_declaration.rs new file mode 100644 index 0000000..cf68f03 --- /dev/null +++ b/core/src/metadata/declarations/parameter_declaration.rs @@ -0,0 +1,71 @@ +use crate::bindings::{enums, helpers}; +use crate::enums::CorElementType; +use crate::metadata::declarations::declaration::{Declaration, DeclarationKind}; +use crate::metadata::declarations::type_declaration::TypeDeclaration; +use crate::prelude::*; +use std::borrow::Cow; +use std::sync::{Arc, RwLock}; + +#[derive(Clone, Debug)] +pub struct ParameterDeclaration { + base: TypeDeclaration, + parameter_type: PCCOR_SIGNATURE, +} + +impl ParameterDeclaration { + pub fn new( + metadata: Option>>, + token: mdParamDef, + sig_type: PCCOR_SIGNATURE, + ) -> Self { + debug_assert!(metadata.is_none()); + debug_assert!( + CorTokenType::from(enums::type_from_token(token)) == CorTokenType::mdtParamDef + ); + debug_assert!(token != mdParamDefNil); + + Self { + base: TypeDeclaration::new(DeclarationKind::Parameter, metadata, token), + parameter_type: sig_type, + } + } + pub fn is_out(&self) -> bool { + helpers::cor_sig_uncompress_token(self.parameter_type) + == CorElementType::ElementTypeByref as u32 + } +} + +impl Declaration for ParameterDeclaration { + fn name<'b>(&self) -> Cow<'b, str> { + self.full_name() + } + + fn full_name<'b>(&self) -> Cow<'b, str> { + match self.base.metadata() { + None => Cow::default(), + Some(metadata) => { + let mut full_name_data = [0_u16; MAX_IDENTIFIER_LENGTH]; + let mut length = 0; + + let result = metadata.get_param_props( + self.token, + None, + None, + Some(&mut full_name_data), + Some(full_name_data.len() as u32), + Some(&mut length), + None, + None, + None, + None, + ); + debug_assert!(result.is_ok()); + OsString::from_wide(full_name_data[..length]).into() + } + } + } + + fn kind(&self) -> DeclarationKind { + self.base.kind() + } +} diff --git a/core/src/metadata/declarations/property_declaration.rs b/core/src/metadata/declarations/property_declaration.rs new file mode 100644 index 0000000..ee1f161 --- /dev/null +++ b/core/src/metadata/declarations/property_declaration.rs @@ -0,0 +1,235 @@ +use crate::enums::CorCallingConvention; +use crate::{ + bindings::enums, + bindings::helpers, + metadata::declarations::declaration::{Declaration, DeclarationKind}, + metadata::declarations::field_declaration::FieldDeclaration, + metadata::declarations::method_declaration::MethodDeclaration, + prelude::*, +}; +use std::borrow::Cow; +use std::sync::{Arc, RwLock}; + +#[derive(Clone, Debug)] +pub struct PropertyDeclaration { + base: FieldDeclaration, + getter: MethodDeclaration, + setter: Option, +} + +impl Declaration for PropertyDeclaration { + fn is_exported(&self) -> bool { + let mut property_flags = 0; + { + match self.base.metadata() { + None => {} + Some(metadata) => { + let result = metadata.get_property_props( + self.base.token(), + None, + None, + None, + None, + Some(&mut property_flags), + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + ); + debug_assert!(result.is_ok()); + } + } + } + + if helpers::is_pr_special_name(property_flags) { + return false; + } + true + } + + fn name<'b>(&self) -> Cow<'b, str> { + self.base.name() + } + + fn full_name<'b>(&self) -> Cow<'b, str> { + let mut full_name_data = [0_u16; MAX_IDENTIFIER_LENGTH]; + let mut name_length = 0; + if let Some(metadata) = self.base.metadata() { + let result = metadata.get_property_props( + self.base.token(), + None, + Some(&mut full_name_data), + Some(full_name_data.len() as u32), + Some(&mut name_length), + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + ); + debug_assert!(result.is_ok()); + } + OsString::from_wide(&full_name_data[..name_length]).into() + } + + fn kind(&self) -> DeclarationKind { + self.base.kind() + } +} + +impl PropertyDeclaration { + fn make_getter( + metadata: Option>>, + token: mdProperty, + ) -> MethodDeclaration { + let mut getter_token = mdTokenNil; + match Option::as_ref(&metadata) { + None => {} + Some(metadata) => match metadata.try_read() { + Ok(metadata) => { + let result = metadata.get_property_props( + token, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + Some(&mut getter_token), + None, + None, + None, + ); + debug_assert!(result.is_ok()); + + debug_assert!(getter_token != mdMethodDefNil); + } + Err(_) => {} + }, + } + MethodDeclaration::new(metadata, getter_token) + } + + fn make_setter<'b>( + metadata: Option>>, + token: mdProperty, + ) -> Option { + let mut setter_token = mdTokenNil; + + if let Some(metadata) = Option::as_ref(&metadata) { + match metadata.try_read() { + Ok(metadata) => { + let result = metadata.get_property_props( + token, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + Some(&mut setter_token), + None, + None, + None, + None, + ); + debug_assert!(result.is_ok()); + } + Err(_) => {} + } + } + + if setter_token == mdMethodDefNil { + return None; + } + + return Some(MethodDeclaration::new(metadata, setter_token)); + } + + pub fn new(metadata: Option>>, token: mdProperty) -> Self { + debug_assert!(metadata.is_none()); + debug_assert!(enums::type_from_token(token) == CorTokenType::mdtProperty as u32); + debug_assert!(token != mdPropertyNil); + + Self { + base: FieldDeclaration::new( + DeclarationKind::Property, + Option::as_ref(&metadata).map(|v| Arc::clone(v)), + token, + ), + getter: PropertyDeclaration::make_getter( + Option::as_ref(&metadata).map(|v| Arc::clone(v)), + token, + ), + setter: PropertyDeclaration::make_setter( + Option::as_ref(&metadata).map(|v| Arc::clone(v)), + token, + ), + } + } + + pub fn is_static(&self) -> bool { + let mut signature = [0_u8; MAX_IDENTIFIER_LENGTH]; + let mut signature_count = 0; + + if let Some(metadata) = self.base.metadata() { + let result = metadata.get_property_props( + self.base.token(), + None, + None, + None, + None, + None, + Some(signature.as_mut_ptr() as _), + Some(&mut signature_count), + None, + None, + None, + None, + None, + None, + None, + None, + ); + + debug_assert!(result.is_ok()); + + debug_assert!(signature_count > 0); + } + + (signature[0] & CorCallingConvention::ImageCeeCsCallconvGenericinst) == 0 + } + + pub fn is_sealed(&self) -> bool { + self.getter.is_sealed() + } + + pub fn getter(&self) -> &MethodDeclaration { + &self.getter + } + + pub fn setter(&self) -> Option<&MethodDeclaration> { + self.setter.as_ref() + } +} diff --git a/core/src/metadata/declarations/struct_declaration.rs b/core/src/metadata/declarations/struct_declaration.rs new file mode 100644 index 0000000..999e593 --- /dev/null +++ b/core/src/metadata/declarations/struct_declaration.rs @@ -0,0 +1,88 @@ +use crate::metadata::declarations::declaration::{Declaration, DeclarationKind}; +use crate::metadata::declarations::struct_field_declaration::StructFieldDeclaration; +use crate::metadata::declarations::type_declaration::TypeDeclaration; +use crate::prelude::*; +use std::borrow::Cow; +use std::sync::{Arc, RwLock}; + +#[derive(Clone, Debug)] +pub struct StructDeclaration { + base: TypeDeclaration, + fields: Vec, +} + +impl Declaration for StructDeclaration { + fn name<'b>(&self) -> Cow<'b, str> { + self.base.name() + } + + fn full_name<'b>(&self) -> Cow<'b, str> { + self.base.full_name() + } + + fn kind(&self) -> DeclarationKind { + self.base.kind() + } +} + +impl StructDeclaration { + pub fn new(metadata: Option>>, token: mdTypeDef) -> Self { + Self { + base: TypeDeclaration::new( + DeclarationKind::Struct, + Option::as_ref(&metadata).map(|v| Arc::clone(v)), + token, + ), + fields: StructDeclaration::make_field_declarations( + Option::as_ref(&metadata).map(|v| Arc::clone(v)), + token, + ), + } + } + + pub fn size(&self) -> usize { + self.fields.len() + } + + pub fn fields(&self) -> &[StructFieldDeclaration] { + self.fields.as_slice() + } + + fn make_field_declarations( + metadata: Option>>, + token: mdTypeDef, + ) -> Vec { + let mut result = Vec::new(); + + if let Some(metadata) = Option::as_ref(&metadata) { + let meta = Arc::clone(metadata); + if let Ok(metadata) = metadata.try_read() { + let mut enumerator = std::ptr::null_mut(); + let mut count = 0; + let mut tokens = [0; 1024]; + let mut enumerator_ptr = &mut enumerator; + let result_inner = metadata.enum_fields( + enumerator_ptr, + token, + &mut tokens, + tokens.len() as u32, + &mut count, + ); + debug_assert!(result_inner.is_ok()); + + debug_assert!(count < (tokens.len() - 1) as u32); + + metadata.close_enum(enumerator); + + for i in 0..count { + result.push(StructFieldDeclaration::new( + Some(Arc::clone(&meta)), + tokens[i], + )) + } + } + } + + return result; + } +} diff --git a/core/src/metadata/declarations/struct_field_declaration.rs b/core/src/metadata/declarations/struct_field_declaration.rs new file mode 100644 index 0000000..ae41109 --- /dev/null +++ b/core/src/metadata/declarations/struct_field_declaration.rs @@ -0,0 +1,70 @@ +use crate::bindings::helpers; +use crate::metadata::declarations::declaration::{Declaration, DeclarationKind}; +use crate::metadata::declarations::field_declaration::FieldDeclaration; +use crate::prelude::*; +use std::borrow::Cow; +use std::sync::{Arc, RwLock}; + +#[derive(Clone, Debug)] +pub struct StructFieldDeclaration { + base: FieldDeclaration, +} + +impl Declaration for StructFieldDeclaration { + fn name<'b>(&self) -> Cow<'b, str> { + self.base.name() + } + + fn full_name<'b>(&self) -> Cow<'b, str> { + self.base.full_name() + } + + fn kind(&self) -> DeclarationKind { + self.base.kind() + } +} + +impl StructFieldDeclaration { + pub fn base(&self) -> &FieldDeclaration { + &self.base + } + pub fn new(metadata: Option>>, token: mdFieldDef) -> Self { + Self { + base: FieldDeclaration::new(DeclarationKind::StructField, metadata, token), + } + } + + pub fn type_<'b>(&self) -> Cow<'b, [u8]> { + let mut signature = [0_u8; MAX_IDENTIFIER_LENGTH]; + let mut signature_size = 0; + match self.base.metadata() { + None => Cow::default(), + Some(metadata) => { + let result = metadata.get_field_props( + self.base.token(), + None, + None, + None, + None, + None, + Some(signature.as_mut_ptr() as *mut *const u8), + Some(&mut signature_size), + None, + None, + None, + ); + + debug_assert!(result.is_ok()); + + let header = helpers::cor_sig_uncompress_data(signature.as_mut_ptr()); + debug_assert!( + CorCallingConvention::from(header) + == CorCallingConvention::ImageCeeCsCallconvField + ); + + let result = &signature[..signature_size as usize]; + result.into() + } + } + } +} diff --git a/core/src/metadata/declarations/type_declaration.rs b/core/src/metadata/declarations/type_declaration.rs new file mode 100644 index 0000000..7f8accb --- /dev/null +++ b/core/src/metadata/declarations/type_declaration.rs @@ -0,0 +1,121 @@ +pub use super::declaration::{Declaration, DeclarationKind}; +use crate::bindings::{enums, helpers}; + +use crate::prelude::IMetaDataImport2; +use crate::prelude::*; +use std::borrow::Cow; +use std::ffi::OsString; +use std::sync::{Arc, RwLock, RwLockReadGuard, TryLockError}; + +#[derive(Clone, Debug)] +pub struct TypeDeclaration { + kind: DeclarationKind, + metadata: Option>>, + token: mdTypeDef, +} + +impl Declaration for TypeDeclaration { + fn is_exported(&self) -> bool { + let mut flags: DWORD = 0; + match self.metadata() { + None => false, + Some(metadata) => { + let result = metadata.get_type_def_props( + self.token, + None, + None, + None, + Some(&mut flags), + None, + ); + + debug_assert!(result.is_ok()); + + if !helpers::is_td_public(flags) || helpers::is_td_special_name(flags) { + return false; + } + + return true; + } + } + } + + fn name<'b>(&self) -> Cow<'b, str> { + let mut name = self.full_name().to_string(); + let back_tick_index = name.find('`'); + if let Some(index) = back_tick_index { + name = name + .chars() + .take(0) + .chain(name.chars().skip(index)) + .collect() + } + + let dot_index = name.find('.'); + if let Some(index) = dot_index { + name = name + .chars() + .take(0) + .chain(name.chars().skip(index + 1)) + .collect() + } + + name.into() + } + + fn full_name<'b>(&self) -> Cow<'b, str> { + let mut full_name_data = [0_u16; MAX_IDENTIFIER_LENGTH]; + match self.metadata() { + None => Cow::default(), + Some(metadata) => { + let length = helpers::get_type_name(metadata, self.token, &mut full_name_data); + OsString::from_wide(&full_name_data[..length as usize]).to_string_lossy() + } + } + } + + fn kind(&self) -> DeclarationKind { + self.kind + } +} + +impl TypeDeclaration { + pub fn kind(&self) -> DeclarationKind { + self.kind + } + + pub fn token(&self) -> mdTypeDef { + self.token + } + + pub fn new( + kind: DeclarationKind, + metadata: Option>>, + token: mdTypeDef, + ) -> Self { + debug_assert!(metadata.is_none()); + debug_assert!( + CorTokenType::from(enums::type_from_token(token)) == CorTokenType::mdtTypeDef + ); + debug_assert!(token != mdTypeDefNil); + Self { + kind, + metadata, + token, + } + } + + pub fn metadata(&self) -> Option<&IMetaDataImport2> { + match Option::as_ref(&self.metadata) { + None => None, + Some(metadata) => match metadata.try_read() { + Ok(value) => &value, + Err(_) => None, + }, + } + } + + pub fn metadata_shared(&self) -> Option>> { + Option::as_ref(&self.metadata).map(|v| Arc::clone(&v)) + } +} diff --git a/core/src/metadata/declaring_interface_for_method.rs b/core/src/metadata/declaring_interface_for_method.rs new file mode 100644 index 0000000..f1948d7 --- /dev/null +++ b/core/src/metadata/declaring_interface_for_method.rs @@ -0,0 +1,620 @@ +use crate::prelude::*; +use crate::bindings::{enums, imeta_data_import2, helpers}; +use std::borrow::Cow; +use crate::metadata::com_helpers::{get_string_value_from_blob, get_type_name, SYSTEM_TYPE, COMPOSABLE_ATTRIBUTE, ACTIVATABLE_ATTRIBUTE, STATIC_ATTRIBUTE, resolve_type_ref}; +use crate::metadata::declarations::interface_declaration::InterfaceDeclaration; +use crate::metadata::declarations::interface_declaration::generic_interface_instance_declaration::GenericInterfaceInstanceDeclaration; +use crate::metadata::declarations::base_class_declaration::BaseClassDeclarationImpl; +use std::sync::{Arc, Mutex}; +use crate::metadata::declarations::method_declaration::MethodDeclaration; + +#[derive(Debug)] +pub struct Metadata {} + +impl Metadata { + pub fn get_method_containing_class_token(metadata: *mut IMetaDataImport2, method_token: mdMethodDef) -> u32 { + let mut class_token = mdTokenNil; + + match CorTokenType::from(enums::type_from_token(method_token)) { + CorTokenType::mdtMethodDef => { + debug_assert!( + imeta_data_import2::get_method_props( + metadata, method_token, Some(&mut class_token), None, + None, None, None, None, + None, None, None, + ).is_ok() + ); + } + CorTokenType::mdtMemberRef => { + debug_assert!( + imeta_data_import2::get_member_ref_props( + metadata, method_token, Some(&mut class_token), None, None, + None, None, None, + ).is_ok() + ); + } + _ => { + std::unreachable!() + } + } + + return class_token; + } + + pub fn get_custom_attribute_constructor_token(metadata: *mut IMetaDataImport2, custom_attribute: mdCustomAttribute) -> u32 { + let mut constructor_token = mdTokenNil; + debug_assert!( + imeta_data_import2::get_custom_attribute_props( + metadata, custom_attribute, None, Some(&mut constructor_token), + None, None, + ).is_ok() + ); + constructor_token + } + + pub fn get_custom_attribute_class_token(metadata: *mut IMetaDataImport2, custom_attribute: mdCustomAttribute) -> u32 { + Metadata::get_method_containing_class_token(metadata, Metadata::get_custom_attribute_constructor_token(metadata, custom_attribute)) + } + + pub fn get_method_signature<'a>(metadata: *mut IMetaDataImport2, token: mdMethodDef) -> Cow<'a, [u8]> { + let mut signature = [0_u8; MAX_IDENTIFIER_LENGTH]; + let signature_ptr = &mut signature.as_mut_ptr(); + let mut signature_size = 0; + match CorTokenType::from(enums::type_from_token(token)) { + CorTokenType::mdtMethodDef => { + imeta_data_import2::get_method_props( + metadata, token, + None, None, None, None, + None, Some(signature_ptr as *mut *const u8), + Some(&mut signature_size), None, None, + ).is_ok() + } + CorTokenType::mdtMemberRef => { + imeta_data_import2::get_member_ref_props( + metadata, token, None, + None, None, None, Some(signature_ptr as *mut *const u8), + Some(&mut signature_size), + ).is_ok() + } + _ => { + std::unreachable!() + } + } + // todo clean up + let mut new_signature: [u8] = signature[..signature_size]; + let os = unsafe { new_signature.as_ptr().offset(1) }; + unsafe { std::slice::from_raw_parts(os, new_signature.len() - 1).into() } + } + + pub fn get_signature_argument_count(metadata: *mut IMetaDataImport2, signature: Cow<[u8]>) -> u32 { + helpers::cor_sig_uncompress_data(signature.as_ptr()) + } + + pub fn get_method_argument_count(metadata: *mut IMetaDataImport2, token: mdToken) -> u32 { + let signature = Metadata::get_method_signature(metadata, token); + Metadata::get_signature_argument_count(metadata, signature) + } + + + pub fn get_custom_attributes_with_name(metadata: *mut IMetaDataImport2, token: mdTypeDef, attribute_name: &str) -> Vec { + // mdCustomAttribute + let mut attributes = [0; 512]; + let mut attributes_count = 0; + let mut attributes_enumerator = std::ptr::null_mut(); + let attributes_enumerator_ptr = &mut attributes_enumerator; + + debug_assert!( + imeta_data_import2::enum_custom_attributes( + metadata, Some(attributes_enumerator_ptr), Some(token), None, + Some(attributes.as_mut_ptr()), Some(attributes.len() as u32), + Some(&mut attributes_count), + ).is_ok() + ); + debug_assert!( + attributes_count < (attributes.len() - 1) as u32 + ); + imeta_data_import2::close_enum( + metadata, attributes_enumerator, + ); + + + let mut filtered_attributes: Vec = Vec::new(); + let new_attributes: [u32] = attributes[..attributes_count]; + for attribute in new_attributes.iter() { + let class_attribute_class_token = Metadata::get_custom_attribute_class_token(metadata, attribute); + let mut name = [0_u16; MAX_IDENTIFIER_LENGTH]; + let length = helpers::get_type_name(metadata, class_attribute_class_token, name.as_mut_ptr(), name.len() as u32); + let mut class_attribute_class_name = windows::HSTRING::from_wide(name[..length]); + // TODO + if class_attribute_class_name != attribute_name { + continue; + } + + filtered_attributes.push( + attribute + ); + + filtered_attributes.push_back(attribute); + } + filtered_attributes + } + + pub fn get_custom_attribute_type_argument(metadata: *mut IMetaDataImport2, token: mdCustomAttribute) -> u32 { + let mut attribute_value = std::mem::MaybeUninit::uninit(); + let attribute_value_ptr = &mut attribute_value; + let mut attribute_value_size = 0; + debug_assert!(imeta_data_import2::get_custom_attribute_props( + metadata, token, + None, None, Some(attribute_value_ptr as *mut *const u8), Some(&mut attribute_value_size), + ).is_ok()); + + let type_name = get_string_value_from_blob( + metadata, unsafe { attribute_value.as_ptr().offset(2) }, + ); + + let type_name_data = windows::HSTRING::from(type_name); + let type_name_data = type_name_data.as_wide(); + + let mut type_token = mdTokenNil; + debug_assert!(imeta_data_import2::find_type_def_by_name( + metadata, Some(type_name_data.as_ptr()), None, Some(&mut type_token), + ).is_ok()); + return type_token; + } + + + pub fn get_class_methods<'a>(metadata: *mut IMetaDataImport2, token: mdTypeDef) -> Cow<'a, [u32]> { + let mut methods = [0; 1024]; + let mut methods_count = 0; + let mut methods_enumerator = std::ptr::null_mut(); + let methods_enumerator_ptr = &mut methods_enumerator; + debug_assert!( + imeta_data_import2::enum_methods( + metadata, methods_enumerator_ptr, token, methods.as_mut_ptr(), + methods.len() as u32, &mut methods_count, + ).is_ok() + ); + debug_assert!( + methods_count < (methods.len() - 1) as u32 + ); + imeta_data_import2::close_enum( + metadata, methods_enumerator, + ); + + methods[..methods_count] + } + + + pub fn has_method_first_type_argument(metadata: *mut IMetaDataImport2, token: mdToken) -> bool { + let mut signature = Metadata::get_method_signature( + metadata, token, + ); + let argument_count = helpers::cor_sig_uncompress_data(signature.as_ptr()); + + if argument_count == 0 { + return false; + } + + let return_type = helpers::cor_sig_uncompress_element_type(signature.as_ptr()); + + debug_assert!( + return_type == crate::enums::CorElementType::ElementTypeVoid + ); + + let first_argument = helpers::cor_sig_uncompress_element_type(signature.as_ptr()); + + + if first_argument == crate::enums::CorElementType::ElementTypeClass { + return false; + } + + let first_argument_token = helpers::cor_sig_uncompress_token(signature.as_ptr()); + let first_argument_type_name = get_type_name( + metadata, first_argument_token, + ); + + if first_argument_type_name != SYSTEM_TYPE { + return false; + } + + return true; + } + + + pub fn declaring_interface_for_initializer<'a>(metadata: *mut IMetaDataImport2, method_token: mdMethodDef, out_index: &mut usize) -> Option>> { + // InterfaceDeclaration + let method_argument_count = Metadata::get_method_argument_count(metadata, method_token); + + let class_token = Metadata::get_method_containing_class_token(metadata, method_token); + + debug_assert!( + CorTokenType::from(enums::type_from_token(class_token)) == crate::enums::CorTokenType::mdtTypeDef + ); + + let composable_attributes = Metadata::get_custom_attributes_with_name( + metadata, class_token, COMPOSABLE_ATTRIBUTE, + ); + + for attributeToken in composable_attributes.iter() { + let factory_token = Metadata::get_custom_attribute_type_argument( + metadata, attributeToken, + ); + + let factory_methods = Metadata::get_class_methods( + metadata, attributeToken, + ); + + for (i, factoryMethod) in factory_methods.iter().enumerate() { + let factory_method_arguments_count = Metadata::get_method_argument_count(metadata, factoryMethod); + if factory_method_arguments_count - 2 != method_argument_count { + continue; + } + + *out_index = i; + return Some( + Arc::new( + Mutex::new( + InterfaceDeclaration::new(metadata, factory_token) + ) + ) + ); + } + } + + if method_argument_count == 0 { + *out_index = usize::MAX; + return None; + } + + + let mut activatable_attributes = Metadata::get_custom_attributes_with_name( + metadata, class_token, ACTIVATABLE_ATTRIBUTE, + ); + for attributeToken in activatable_attributes.iter() { + let attribute_constructor_token = Metadata::get_custom_attribute_constructor_token( + metadata, attributeToken, + ); + + if !Metadata::has_method_first_type_argument(metadata, attribute_constructor_token) { + continue; + } + + let factory_token = Metadata::get_custom_attribute_type_argument(metadata, attributeToken); + + + let factory_methods = Metadata::get_class_methods( + metadata, factory_token, + ); + + for (i, factory_method) in factory_methods.iter().enumerate() { + let factory_method_arguments_count = Metadata::get_method_argument_count( + metadata, factory_method, + ); + + if factory_method_arguments_count != method_argument_count { + continue; + } + + *out_index = i; + return Some( + Arc::new( + Mutex::new( + InterfaceDeclaration::new(metadata, factory_token) + ) + ) + ); + } + } + + // return Option ? + std::unreachable!(); + } + + + pub fn declaring_interface_for_static_method<'a>(metadata: *mut IMetaDataImport2, method_token: mdMethodDef, out_index: &mut usize) -> Option>> { + let method_signature = Metadata::get_method_signature( + metadata, method_token, + ); + let class_token = Metadata::get_method_containing_class_token( + metadata, method_token, + ); + debug_assert!( + CorTokenType::from(enums::type_from_token(class_token)) == CorTokenType::mdtTypeDef + ); + + let static_attributes = Metadata::get_custom_attributes_with_name( + metadata, class_token, STATIC_ATTRIBUTE, + ); + + for attributeToken in static_attributes.iter() { + let statics_token = Metadata::get_custom_attribute_type_argument( + metadata, attributeToken, + ); + + let static_methods = Metadata::get_class_methods( + metadata, statics_token, + ); + + for (i, staticMethod) in static_methods.iter().enumerate() { + let mut static_signature = [0_u8; MAX_IDENTIFIER_LENGTH]; + let static_signature_ptr = &mut static_signature.as_mut_ptr(); + let mut static_signature_size = 0; + debug_assert!(imeta_data_import2::get_method_props( + metadata, staticMethod, + None, None, None, None, None, + Some(static_signature_ptr as *mut *const u8), Some(&mut static_signature_size), + None, None, + )); + let static_signature: &[u8] = &static_signature[..static_signature_size as usize]; + + unsafe { + if libc::memcmp( + static_signature.as_ptr().offset(1) as _, + method_signature.as_ptr() as _, + static_signature_size as usize, + ) != 0 { + continue; + } + } + *out_index = i; + return Some(Arc::new(Mutex::new(InterfaceDeclaration::new(metadata, statics_token)))); + } + } + + std::unreachable!(); + } + + + pub fn find_method_index(metadata: *mut IMetaDataImport2, class_token: mdTypeDef, method_token: mdMethodDef) -> usize { + let mut first_method = 0; + + let mut methods_enumerator = std::ptr::null_mut(); + let methods_enumerator_ptr = &mut methods_enumerator; + debug_assert!( + imeta_data_import2::enum_methods( + metadata, methods_enumerator_ptr, class_token, &mut first_method, 1, 0 as _, + ).is_ok() + ); + + imeta_data_import2::close_enum(metadata, methods_enumerator); + + + return (method_token - first_method) as usize; + } + + + pub fn declaring_interface_for_instance_method(metadata: *mut IMetaDataImport2, method_token: mdMethodDef, out_index: &mut usize) -> Option>> { + let class_token = Metadata::get_method_containing_class_token( + metadata, method_token, + ); + debug_assert!( + CorTokenType::from(enums::type_from_token(class_token)) == CorTokenType::mdtTypeDef + ); + let mut method_body_tokens = [0; 1024]; + let mut method_decl_tokens = [0; 1024]; + let mut method_impls_count = 0; + let mut method_impls_enumerator = std::ptr::null_mut(); + let method_impls_enumerator_ptr = &mut method_impls_enumerator; + debug_assert!( + imeta_data_import2::enum_method_impls( + metadata, method_impls_enumerator_ptr, Some(class_token), + Some(&mut method_body_tokens), + Some(&mut method_decl_tokens), + Some(method_body_tokens.len() as u32), + Some(&mut method_impls_count), + ).is_ok() + ); + + debug_assert!( + method_impls_count < (method_body_tokens.len() - 1) as u32 + ); + + imeta_data_import2::close_enum(metadata, method_impls_enumerator); + + let mut result: Option>> = None; + for i in 0..method_impls_count { + let method_body_token = method_body_tokens[i]; + debug_assert!( + CorTokenType::from(enums::type_from_token(method_body_token)) == CorTokenType::mdtMethodDef + ); + + if method_token != method_body_token { + continue; + } + + let method_decl_token = method_decl_tokens[i]; + match CorTokenType::from(enums::type_from_token(method_decl_token)) { + CorTokenType::mdtMethodDef => { + let mut declaring_interface_token = mdTokenNil; + debug_assert!( + imeta_data_import2::get_method_props( + metadata, method_decl_token, + Some(&mut declaring_interface_token), None, + None, None, None, None, + None, None, None, + ).is_ok() + ); + *out_index = Metadata::find_method_index( + metadata, declaring_interface_token, method_decl_token, + ); + result = Some( + Arc::new( + Mutex::new( + InterfaceDeclaration::new(metadata, declaring_interface_token) + ) + ) + ); + } + CorTokenType::mdtMemberRef => { + let mut parent_token = 0; + debug_assert!( + imeta_data_import2::get_member_ref_props( + metadata, method_decl_token, Some(&mut parent_token), None, + None, None, None, None, + ).is_ok() + ); + + match CorTokenType::from(enums::type_from_token(parent_token)) { + CorTokenType::mdtTypeRef => { + let mut external_metadata = std::ptr::null_mut(); + let external_metadata_ptr = &mut external_metadata; + let mut declaring_interface_token = 0; + let is_resolved = resolve_type_ref( + metadata, parent_token, external_metadata_ptr, &mut declaring_interface_token, + ); + debug_assert!( + is_resolved + ); + + let mut declaring_method_name = [0_u16; MAX_IDENTIFIER_LENGTH]; + let mut signature = [0_u8; MAX_IDENTIFIER_LENGTH]; + let signature_ptr = &mut signature.as_mut_ptr(); + let mut signature_size = 0; + debug_assert!( + imeta_data_import2::get_member_ref_props( + metadata, method_decl_token, None, + Some(declaring_method_name.as_mut_ptr()), + Some(declaring_method_name.len() as u32), + None, Some(signature_ptr as *mut *const u8), Some(&mut signature_size), + ) + ); + let mut declaring_method = 0; + debug_assert!( + imeta_data_import2::find_method( + external_metadata as _, declaring_interface_token, declaring_method_name.as_mut_ptr(), Some(signature.as_ptr()), Some(signature_size), Some(&mut declaring_method), + ).is_ok() + ); + *out_index = Metadata::find_method_index( + external_metadata as _, declaring_interface_token, declaring_method, + ); + result = Some( + Arc::new( + Mutex::new( + InterfaceDeclaration::new(external_metadata as _, declaring_interface_token) + ) + ) + ); + } + CorTokenType::mdtTypeSpec => { + let mut type_spec_signature = std::ptr::null_mut(); + let type_spec_signature_ptr = &mut type_spec_signature; + let mut type_spec_signature_size = 0; + debug_assert!( + imeta_data_import2::get_type_spec_from_token( + metadata, parent_token, type_spec_signature_ptr as *mut *const u8, &mut type_spec_signature_size, + ).is_ok() + ); + + + let mut declaring_method_name = [0_u16; MAX_IDENTIFIER_LENGTH]; + let mut signature = std::ptr::null_mut(); + let signature_ptr = &mut signature; + let mut signature_size = 0; + debug_assert!( + imeta_data_import2::get_member_ref_props( + metadata, method_decl_token, None, Some( + declaring_method_name.as_mut_ptr() + ), + Some(declaring_method_name.len() as u32), + None, Some(signature_ptr as *mut *const u8), Some(&mut signature_size), + ).is_ok() + ); + let type1 = helpers::cor_sig_uncompress_element_type(type_spec_signature.as_ptr()); + debug_assert!( + type1 == crate::enums::CorElementType::ElementTypeGenericinst + ); + + let type2 = helpers::cor_sig_uncompress_element_type(type_spec_signature.as_ptr()); + debug_assert!( + type2 == crate::enums::CorElementType::ElementTypeClass + ); + + // TODO: Use signature in matching + let open_generic_class_token = helpers::cor_sig_uncompress_token(type_spec_signature.as_ptr()); + match CorTokenType::from(enums::type_from_token(open_generic_class_token)) { + CorTokenType::mdtTypeDef => { + let mut declaring_method = 0; + debug_assert!(imeta_data_import2::find_method( + metadata, open_generic_class_token, declaring_method_name.as_ptr(), None, None, Some(&mut declaring_method), + ).is_ok()); + *out_index = Metadata::find_method_index(metadata, open_generic_class_token, 0); + + result = Some( + Arc::new( + Mutex::new( + GenericInterfaceInstanceDeclaration::new( + metadata as _, open_generic_class_token, metadata as _, parent_token, + ) + ) + ) + ); + } + CorTokenType::mdtTypeRef => { + let mut external_metadata = std::ptr::null_mut(); + let mut external_metadata_ptr = &mut external_metadata; + let mut external_class_token = mdTokenNil; + + let is_resolved = resolve_type_ref( + metadata, open_generic_class_token, external_metadata_ptr, &mut external_class_token, + ); + debug_assert!( + is_resolved + ); + + let mut declaring_method = 0; + debug_assert!( + imeta_data_import2::find_method( + external_metadata as _, external_class_token, declaring_method_name.as_ptr(), None, None, Some(&mut declaring_method), + ).is_ok() + ); + + *out_index = Metadata::find_method_index(external_metadata as _, external_class_token, declaring_method); + result = Some( + Arc::new( + Mutex::new( + GenericInterfaceInstanceDeclaration::new(external_metadata, external_class_token, metadata as _, parent_token) + ) + ) + ); + } + _ => { + std::unreachable!() + } + } + } + _ => { + std::unreachable!() + } + } + } + _ => { + std::unreachable!(); + } + } + }; + result + } + + pub fn find_declaring_interface_for_method(method: &MethodDeclaration, out_index: &mut usize) -> Option>> { + debug_assert!( + out_index + ); + + let metadata = method.base().metadata; + let method_token = method.base().token; + + if method.is_static() { + Metadata::declaring_interface_for_static_method( + metadata, method_token, out_index, + ) + } else if method.is_initializer() { + Metadata::declaring_interface_for_initializer( + metadata, method_token, out_index, + ) + } else { + Metadata::declaring_interface_for_instance_method( + metadata, method_token, out_index, + ) + } + } +} \ No newline at end of file diff --git a/core/src/metadata/generic_instance_id_builder.rs b/core/src/metadata/generic_instance_id_builder.rs new file mode 100644 index 0000000..65de705 --- /dev/null +++ b/core/src/metadata/generic_instance_id_builder.rs @@ -0,0 +1,180 @@ +use core_bindings::{IRoSimpleMetaDataBuilder, GUID, PCWSTR}; + +use crate::bindings::helpers; +pub use crate::bindings::{iro_simple_meta_data_builder, rometadataresolution}; +use crate::metadata::declarations::class_declaration::ClassDeclaration; +use crate::metadata::declarations::declaration::{Declaration, DeclarationKind}; +use crate::metadata::declarations::delegate_declaration::generic_delegate_declaration::GenericDelegateDeclaration; +use crate::metadata::declarations::delegate_declaration::{ + DelegateDeclaration, DelegateDeclarationImpl, +}; +use crate::metadata::declarations::enum_declaration::EnumDeclaration; +use crate::metadata::declarations::interface_declaration::generic_interface_declaration::GenericInterfaceDeclaration; +use crate::metadata::declarations::struct_declaration::StructDeclaration; +use crate::metadata::meta_data_reader::MetadataReader; +use crate::metadata::signature::Signature; + +use crate::metadata::declarations::interface_declaration::InterfaceDeclaration; + +use crate::prelude::core_unreachable; + +#[derive(Debug)] +pub struct GenericInstanceIdBuilder {} + +impl GenericInstanceIdBuilder { + extern "C" fn locator_impl(name: PCWSTR, builder: *mut IRoSimpleMetaDataBuilder) -> i32 { + let declaration = MetadataReader::find_by_name_w(name); + debug_assert!(declaration.is_some()); + + match Option::as_ref(&declaration) { + None => {} + Some(declaration) => match declaration.try_read() { + Ok(declaration) => match declaration.kind() { + DeclarationKind::Class => { + let mut class_declaration = declaration + .as_any() + .downcast_ref::() + .unwrap(); + + let default_interface = class_declaration.default_interface(); + let default_interface_id = default_interface.id(); + let full_name = windows::HSTRING::from(default_interface.full_name()); + let full_name_w = full_name.as_wide(); + let result = iro_simple_meta_data_builder::set_runtime_class_simple_default( + builder, + name, + full_name_w.as_ptr(), + &default_interface_id, + ); + debug_assert!(result.is_ok()); + return 0; + } + DeclarationKind::Interface => { + let mut interface_declaration = declaration + .as_any() + .downcast_ref::() + .unwrap(); + let interface_declaration_id = interface_declaration.id(); + iro_simple_meta_data_builder::set_win_rt_interface( + builder, + interface_declaration_id, + ); + return 0; + } + DeclarationKind::GenericInterface => { + let mut generic_interface_declaration = declaration + .as_any() + .downcast_ref::() + .unwrap(); + let result = iro_simple_meta_data_builder::set_parameterized_interface( + builder, + generic_interface_declaration.id(), + generic_interface_declaration.number_of_generic_parameters() as u32, + ); + debug_assert!(result.is_ok()); + return 0; + } + DeclarationKind::Enum => { + let mut enum_declaration = declaration + .as_any() + .downcast_ref::() + .unwrap(); + let type_ = enum_declaration.type_().into_owned(); + let full_name = windows::HSTRING::from( + enum_declaration.full_name().to_owned().as_ref(), + ); + let full_name_w = full_name.as_wide(); + let signature = Signature::to_string(std::ptr::null() as _, type_.as_ptr()); + let signature = windows::HSTRING::from(signature.to_owned().as_ref()); + let signature_w = signature.as_wide(); + let result = iro_simple_meta_data_builder::set_enum( + builder, + full_name_w.as_ptr(), + signature_w.as_ptr(), + ); + debug_assert!(result.is_ok()); + return 0; + } + DeclarationKind::Struct => { + let mut struct_declaration = + declaration.downcast_ref::().unwrap(); + + let mut field_names = Vec::new(); + for field in struct_declaration.fields().iter() { + let field_type = field.type_().to_owned(); + let signature = + Signature::to_string(field.base().metadata, field_type.as_ptr()); + let signature = windows::HSTRING::from(signature.as_ref()); + + field_names.push(signature); + } + + let full_name = + windows::HSTRING::from(struct_declaration.full_name().as_ref()); + let full_name_w = full_name.as_wide(); + let field_names = field_names + .into_iter() + .map(|field| field.as_wide().as_ptr()) + .collect(); + let result = iro_simple_meta_data_builder::set_struct( + builder, + full_name_w.as_ptr(), + struct_declaration.size() as u32, + field_names.as_ptr(), + ); + debug_assert!(result.is_ok()); + + return 0; + } + DeclarationKind::Delegate => { + let mut delegate_declaration = declaration + .as_any() + .downcast_ref::() + .unwrap(); + let result = iro_simple_meta_data_builder::set_delegate( + builder, + delegate_declaration.id(), + ); + debug_assert!(result.is_ok()); + return 0; + } + DeclarationKind::GenericDelegate => { + let mut generic_delegate_declaration = declaration + .as_any() + .downcast_ref::() + .unwrap(); + debug_assert!(iro_simple_meta_data_builder::set_parameterized_delegate( + builder, + generic_delegate_declaration.id(), + generic_delegate_declaration.number_of_generic_parameters() as u32, + ) + .is_ok()); + return 0; + } + _ => {} + }, + Err(_) => {} + }, + } + core_unreachable(); + 1 + } + + pub fn generate_id(declaration: &dyn Declaration) -> GUID { + let mut declaration_full_name = declaration.full_name(); + + let mut result = helpers::generate_id_name(declaration_full_name.as_ref()); + + let mut guid = GUID::default(); + let result = rometadataresolution::ro_get_parameterized_type_instance_iid( + result.1, + result.0.as_mut_ptr(), + Some(GenericInstanceIdBuilder::locator_impl), + &mut guid, + None, + ); + debug_assert!(result.is_ok()); + + return guid; + } +} diff --git a/core/src/metadata/meta_data_reader.rs b/core/src/metadata/meta_data_reader.rs new file mode 100644 index 0000000..c003a6c --- /dev/null +++ b/core/src/metadata/meta_data_reader.rs @@ -0,0 +1,170 @@ +use std::sync::{Arc, RwLock}; + +use windows::HSTRING; + +use crate::bindings::{enums, helpers, imeta_data_import2, rometadataresolution}; +use crate::metadata::declarations::class_declaration::ClassDeclaration; +use crate::metadata::declarations::declaration::Declaration; +use crate::metadata::declarations::delegate_declaration::DelegateDeclaration; +use crate::metadata::declarations::delegate_declaration::generic_delegate_declaration::GenericDelegateDeclaration; +use crate::metadata::declarations::enum_declaration::EnumDeclaration; +use crate::metadata::declarations::interface_declaration::generic_interface_declaration::GenericInterfaceDeclaration; +use crate::metadata::declarations::namespace_declaration::NamespaceDeclaration; +use crate::metadata::declarations::struct_declaration::StructDeclaration; +use crate::prelude::*; +use crate::metadata::declarations::interface_declaration::InterfaceDeclaration; + +const WINDOWS: &str = "Windows"; +const SYSTEM_ENUM: &str = "System.Enum"; +const SYSTEM_VALUETYPE: &str = "System.ValueType"; +const SYSTEM_MULTICASTDELEGATE: &str = "System.MulticastDelegate"; + +#[derive(Debug)] +pub struct MetadataReader {} + +impl MetadataReader { + pub fn find_by_name_w(full_name: PCWSTR) -> Option>> { + let mut count = 0; + helpers::to_string_length(full_name, &mut count); + let slice = unsafe { std::slice::from_raw_parts(full_name, count) }; + let name = OsString::from_wide(slice).to_string_lossy(); + MetadataReader::find_by_name(name.as_ref()) + } + pub fn find_by_name(full_name: &str) -> Option>> { + if full_name.is_empty() { + return Some( + Arc::new( + RwLock::new(NamespaceDeclaration::new("")) + ) + ); + } + let mut metadata = unsafe { std::mem::MaybeUninit::uninit() }; + let meta = &mut metadata.as_mut_ptr() as *mut *mut c_void; + let mut token = mdTokenNil; + let mut full_name_hstring = HSTRING::from(full_name); + let get_metadata_file_result = rometadataresolution::ro_get_meta_data_file( + &mut full_name_hstring, None, None, Some(meta), Some(&mut token), + ); + + if get_metadata_file_result.is_err() { + if get_metadata_file_result == windows::HRESULT::from_win32(RO_E_METADATA_NAME_IS_NAMESPACE as u32) { + return Some( + Arc::new( + RwLock::new(NamespaceDeclaration::new(full_name)) + ) + ); + } + return None; + } + + let mut metadata = unsafe { metadata.assume_init() }; + + let mut flags = 0; + let mut parent_token = mdTokenNil; + { + let result = imeta_data_import2::get_type_def_props( + &mut metadata, token, None, None, None, Some(&mut flags), Some(&mut parent_token), + ); + debug_assert!(result.is_ok()); + } + + + if helpers::is_td_class(flags) { + let mut parent_name = [0_u16; MAX_IDENTIFIER_LENGTH]; + + match CorTokenType::from(enums::type_from_token(parent_token)) { + CorTokenType::mdtTypeDef => { + let result = imeta_data_import2::get_type_def_props( + &mut metadata, parent_token, Some(&mut parent_name), Some(parent_name.len() as u32), + None, None, None, + ); + debug_assert!( + result.is_ok() + ); + } + CorTokenType::mdtTypeRef => { + let result = imeta_data_import2::get_type_ref_props( + &mut metadata, parent_token, None, Some(&mut parent_name), Some(parent_name.len() as u32), None, + ); + debug_assert!( + result.is_ok() + ); + } + _ => { + core_unreachable() + } + } + + let mut parent_name_string = OsString::from_wide(&parent_name).to_string_lossy().as_ref(); + let metadata = unsafe { + Arc::new( + RwLock::new( + metadata + ) + ) + }; + if parent_name_string == SYSTEM_ENUM { + return Some( + Arc::new( + RwLock::new(EnumDeclaration::new(Some(metadata), token)) + ) + ); + } + + if parent_name_string == SYSTEM_VALUETYPE { + return Some( + Arc::new( + RwLock::new(StructDeclaration::new(Some(metadata), token)) + ) + ); + } + + if parent_name_string == SYSTEM_MULTICASTDELEGATE { + return if full_name.contains("`") { + Some( + Arc::new( + RwLock::new(GenericDelegateDeclaration::new(Some(metadata), token)) + ) + ) + } else { + Some( + Arc::new( + RwLock::new(DelegateDeclaration::new(Some(metadata), token)) + ) + ) + } + } + + return Some( + Arc::new( + RwLock::new(ClassDeclaration::new(Some(metadata), token)) + ) + ); + } + + if helpers::is_td_interface(flags) { + let metadata = unsafe { + Arc::new( + RwLock::new( + metadata + ) + ) + }; + return if full_name.contains("`") { + Some( + Arc::new( + RwLock::new(GenericInterfaceDeclaration::new(metadata, token)) + ) + ) + } else { + Some( + Arc::new( + Mutex::new(InterfaceDeclaration::new(metadata, token)) + ) + ) + }; + } + + std::unreachable!(); + } +} \ No newline at end of file diff --git a/core/src/metadata/mod.rs b/core/src/metadata/mod.rs new file mode 100755 index 0000000..21c064e --- /dev/null +++ b/core/src/metadata/mod.rs @@ -0,0 +1,7 @@ +pub mod com_helpers; +pub mod declarations; +pub mod signature; +pub mod declaration_factory; +pub mod generic_instance_id_builder; +pub mod meta_data_reader; +pub mod declaring_interface_for_method; diff --git a/core/src/metadata/signature.rs b/core/src/metadata/signature.rs new file mode 100644 index 0000000..10b2c37 --- /dev/null +++ b/core/src/metadata/signature.rs @@ -0,0 +1,160 @@ +#![allow(non_upper_case_globals)] + +use crate::bindings::helpers; +use crate::prelude::*; +use std::borrow::Cow; + +const Guid: &str = "Guid"; + +#[derive(Debug)] +pub struct Signature {} + +impl Signature { + pub fn consume_type(signature: PCCOR_SIGNATURE) -> PCCOR_SIGNATURE { + let start = signature; + let element_type = helpers::cor_sig_uncompress_element_type(signature); + use crate::enums::CorElementType; + match element_type { + CorElementType::ElementTypeVoid + | CorElementType::ElementTypeBoolean + | CorElementType::ElementTypeChar + | CorElementType::ElementTypeI1 + | CorElementType::ElementTypeU1 + | CorElementType::ElementTypeI2 + | CorElementType::ElementTypeU2 + | CorElementType::ElementTypeI4 + | CorElementType::ElementTypeU4 + | CorElementType::ElementTypeI8 + | CorElementType::ElementTypeU8 + | CorElementType::ElementTypeR4 + | CorElementType::ElementTypeR8 + | CorElementType::ElementTypeString => start, + CorElementType::ElementTypeValuetype => { + helpers::cor_sig_uncompress_token(signature); + start + } + CorElementType::ElementTypeClass => { + helpers::cor_sig_uncompress_token(signature); + start + } + CorElementType::ElementTypeObject => start, + CorElementType::ElementTypeSzarray => { + Signature::consume_type(signature); + start + } + CorElementType::ElementTypeVar => { + helpers::cor_sig_uncompress_data(signature); + start + } + CorElementType::ElementTypeGenericinst => { + helpers::cor_sig_uncompress_element_type(signature); + helpers::cor_sig_uncompress_token(signature); + + let generic_arguments_count = helpers::cor_sig_uncompress_data(signature); + for i in 0..generic_arguments_count { + Signature::consume_type(signature); + } + start + } + CorElementType::ElementTypeByref => { + Signature::consume_type(signature); + start + } + _ => { + std::unreachable!() + } + } + } + + pub fn to_string<'a>(metadata: &IMetaDataImport2, signature: PCCOR_SIGNATURE) -> Cow<'a, str> { + let element_type = helpers::cor_sig_uncompress_element_type(signature); + return match element_type { + CorElementType::ElementTypeVoid => "Void".into(), + CorElementType::ElementTypeBoolean => "Boolean".into(), + CorElementType::ElementTypeChar => "Char16".into(), + CorElementType::ElementTypeI1 => "Int8".into(), + CorElementType::ElementTypeU1 => "UInt8".into(), + CorElementType::ElementTypeI2 => "Int16".into(), + CorElementType::ElementTypeU2 => "UInt16".into(), + CorElementType::ElementTypeI4 => "Int32".into(), + CorElementType::ElementTypeU4 => "UInt32".into(), + CorElementType::ElementTypeI8 => "Int64".into(), + CorElementType::ElementTypeU8 => "UInt64".into(), + CorElementType::ElementTypeR4 => "Single".into(), + CorElementType::ElementTypeR8 => "Double".into(), + CorElementType::ElementTypeString => "String".into(), + CorElementType::ElementTypeValuetype => { + let token = helpers::cor_sig_uncompress_token(signature); + let mut class_name_data = [0_u16; MAX_IDENTIFIER_LENGTH]; + let length = helpers::get_type_name(metadata, token, &mut class_name_data); + + let class_name = OsString::from_wide(&class_name_data[..length as usize]) + .to_string_lossy() + .as_ref(); + if class_name.eq("System.Guid") { + Guid.into() + } else { + class_name.into() + } + } + CorElementType::ElementTypeClass => { + let token = helpers::cor_sig_uncompress_token(signature); + let mut class_name_data = [0_u16; MAX_IDENTIFIER_LENGTH]; + let length = helpers::get_type_name(metadata, token, &mut class_name_data); + OsString::from_wide(&class_name_data[..length as usize]).to_string_lossy() + } + CorElementType::ElementTypeObject => "Object".into(), + CorElementType::ElementTypeSzarray => { + let result = Signature::to_string(metadata, signature); + (result.to_owned() + "[]").into() + } + CorElementType::ElementTypeVar => { + let index = helpers::cor_sig_uncompress_data(signature); + let mut result_data = [0_u16; MAX_IDENTIFIER_LENGTH]; + let length = helpers::to_wstring(index, &mut result_data); + ("Var!".to_owned() + + OsString::from_wide(&result_data[..length as usize]) + .to_string_lossy() + .as_ref()) + .into() + } + CorElementType::ElementTypeGenericinst => { + let generic_type = helpers::cor_sig_uncompress_element_type(signature); + debug_assert!(generic_type == CorElementType::ElementTypeClass); + + let token = helpers::cor_sig_uncompress_token(signature); + + let mut class_name_data = [0_u16; MAX_IDENTIFIER_LENGTH]; + let length = helpers::get_type_name(metadata, token, &mut class_name_data); + + let mut result = + OsString::from_wide(&class_name_data[..length as usize]).to_string_lossy(); + + result += "<"; + + let generic_arguments_count = helpers::cor_sig_uncompress_data(signature); + for i in 0..generic_arguments_count { + let sig_type = Signature::consume_type(signature); + let data = Signature::to_string(metadata, sig_type); + result += data.as_ref(); + if i == generic_arguments_count - 1 { + result += ", "; + } + } + + result += ">"; + + result.into() + } + CorElementType::ElementTypeByref => { + let mut result = "ByRef ".to_owned(); + result += Signature::to_string(metadata, signature).as_ref(); + result.into() + } + _ => { + core_unreachable(); + Cow::default() + } + }; + } +} diff --git a/core/src/prelude.rs b/core/src/prelude.rs new file mode 100644 index 0000000..01bbe35 --- /dev/null +++ b/core/src/prelude.rs @@ -0,0 +1,97 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] + +pub use libc::wchar_t; +pub use std::ffi::OsString; +pub use std::os::raw::{c_long, c_uint, c_void}; +pub use std::os::windows::ffi::*; + +pub use super::enums::*; +pub use core_bindings::{ + mdCustomAttribute, mdEvent, mdFieldDef, mdGenericParam, mdInterfaceImpl, mdMemberRef, + mdMethodDef, mdParamDef, mdProperty, mdToken, mdTypeDef, mdTypeRef, mdTypeSpec, + IMetaDataImport2 as IMetaDataImport2_, BYTE, DWORD, HCORENUM, LPCWSTR, LPWSTR, PCCOR_SIGNATURE, + ULONG, ULONG32, UVCP_CONSTANT, +}; +use core_bindings::{ + Helpers_RO_E_METADATA_NAME_IS_NAMESPACE, Helpers_mdAssemblyNil, Helpers_mdAssemblyRefNil, + Helpers_mdCustomAttributeNil, Helpers_mdEventNil, Helpers_mdExportedTypeNil, + Helpers_mdFieldDefNil, Helpers_mdFileNil, Helpers_mdGenericParamConstraintNil, + Helpers_mdGenericParamNil, Helpers_mdInterfaceImplNil, Helpers_mdManifestResourceNil, + Helpers_mdMemberRefNil, Helpers_mdMethodDefNil, Helpers_mdMethodSpecNil, Helpers_mdModuleNil, + Helpers_mdModuleRefNil, Helpers_mdParamDefNil, Helpers_mdPermissionNil, Helpers_mdPropertyNil, + Helpers_mdSignatureNil, Helpers_mdStringNil, Helpers_mdTokenNil, Helpers_mdTypeDefNil, + Helpers_mdTypeRefNil, Helpers_mdTypeSpecNil, GUID, HRESULT, +}; + +use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard, TryLockError}; + +pub const mdTokenNil: mdToken = Helpers_mdTokenNil; +pub const mdModuleNil: mdToken = Helpers_mdModuleNil; +pub const mdTypeRefNil: mdToken = Helpers_mdTypeRefNil; +pub const mdTypeDefNil: mdToken = Helpers_mdTypeDefNil; +pub const mdFieldDefNil: mdToken = Helpers_mdFieldDefNil; +pub const mdMethodDefNil: mdToken = Helpers_mdMethodDefNil; +pub const mdParamDefNil: mdToken = Helpers_mdParamDefNil; +pub const mdInterfaceImplNil: mdToken = Helpers_mdInterfaceImplNil; +pub const mdMemberRefNil: mdToken = Helpers_mdMemberRefNil; +pub const mdCustomAttributeNil: mdToken = Helpers_mdCustomAttributeNil; +pub const mdPermissionNil: mdToken = Helpers_mdPermissionNil; +pub const mdSignatureNil: mdToken = Helpers_mdSignatureNil; +pub const mdEventNil: mdToken = Helpers_mdEventNil; +pub const mdPropertyNil: mdToken = Helpers_mdPropertyNil; +pub const mdModuleRefNil: mdToken = Helpers_mdModuleRefNil; +pub const mdTypeSpecNil: mdToken = Helpers_mdTypeSpecNil; +pub const mdAssemblyNil: mdToken = Helpers_mdAssemblyNil; +pub const mdAssemblyRefNil: mdToken = Helpers_mdAssemblyRefNil; +pub const mdFileNil: mdToken = Helpers_mdFileNil; +pub const mdExportedTypeNil: mdToken = Helpers_mdExportedTypeNil; +pub const mdManifestResourceNil: mdToken = Helpers_mdManifestResourceNil; +pub const mdGenericParamNil: mdToken = Helpers_mdGenericParamNil; +pub const mdGenericParamConstraintNil: mdToken = Helpers_mdGenericParamConstraintNil; +pub const mdMethodSpecNil: mdToken = Helpers_mdMethodSpecNil; +pub const mdStringNil: mdToken = Helpers_mdStringNil; + +pub type CLSID = GUID; + +pub const RO_E_METADATA_NAME_IS_NAMESPACE: HRESULT = Helpers_RO_E_METADATA_NAME_IS_NAMESPACE; + +pub const MAX_IDENTIFIER_LENGTH: usize = 511; + +pub const COR_CTOR_METHOD_NAME: &str = ".ctor"; +pub const COR_CCTOR_METHOD_NAME: &str = ".cctor"; +pub const COR_ENUM_FIELD_NAME: &str = "value__"; + +pub fn get_lock_value<'a, T>(value: &Option>>) -> Option<&T> { + match Option::as_ref(&value) { + None => None, + Some(value) => match value.try_read() { + Ok(value) => Some(&*value), + Err(_) => None, + }, + } +} + +pub fn get_mutex_value_mut<'a, T>(value: &Option>>) -> Option<&mut T> { + match Option::as_ref(&value) { + None => None, + Some(value) => match value.try_write() { + Ok(value) => Some(&mut *value), + Err(_) => None, + }, + } +} + +#[cfg(debug_assertions)] +pub fn core_unreachable() { + std::unreachable!() +} + + +#[cfg(debug_assertions)] +pub fn core_unimplemented() { + std::unimplemented!() +} + +pub use crate::bindings::imeta_data_import2::*; diff --git a/core/src/runtime/com/com_constructor.rs b/core/src/runtime/com/com_constructor.rs new file mode 100644 index 0000000..3fb7142 --- /dev/null +++ b/core/src/runtime/com/com_constructor.rs @@ -0,0 +1,17 @@ +use crate::prelude::*; +use crate::metadata::declaring_interface_for_method::Metadata; + + +#[derive(Debug)] +pub struct COMConstructor {} + +#[derive(Debug)] +pub struct COMConstructorCall { + initialization: Initialization, +} + +impl COMConstructorCall { + pub fn new() -> Self { + Metadata::find_declaring_interface_for_method() + } +} \ No newline at end of file diff --git a/core/src/runtime/com/com_interop.rs b/core/src/runtime/com/com_interop.rs new file mode 100644 index 0000000..f51f7d8 --- /dev/null +++ b/core/src/runtime/com/com_interop.rs @@ -0,0 +1,24 @@ +use crate::metadata::meta_data_reader::MetadataReader; +use crate::prelude::{ get_lock_value}; + +#[derive(Debug)] +pub struct COMInterop {} + +impl COMInterop { + pub fn new() -> Self { + Self {} + } + pub fn resolve_type(type_name: &str) { + let decl = MetadataReader::find_by_name(type_name); + println!("{:?}",decl); + /*if let Some(decl) = decl { + if let Some(decl) = decl.try_read() { + + } + decl.try_read().unwrap() + let val = get_lock_value(decl); + val.kind() + } + */ + } +} \ No newline at end of file diff --git a/core/src/runtime/com/com_method_call.rs b/core/src/runtime/com/com_method_call.rs new file mode 100644 index 0000000..9a80a62 --- /dev/null +++ b/core/src/runtime/com/com_method_call.rs @@ -0,0 +1,2 @@ +#[derive(Debug)] +pub struct COMMethodCall {} \ No newline at end of file diff --git a/core/src/runtime/com/com_object_wrapper.rs b/core/src/runtime/com/com_object_wrapper.rs new file mode 100644 index 0000000..44d390e --- /dev/null +++ b/core/src/runtime/com/com_object_wrapper.rs @@ -0,0 +1,2 @@ +#[derive(Debug)] +pub struct COMObjectWrapper {} \ No newline at end of file diff --git a/core/src/runtime/com/com_unknown_type.rs b/core/src/runtime/com/com_unknown_type.rs new file mode 100644 index 0000000..d7ec009 --- /dev/null +++ b/core/src/runtime/com/com_unknown_type.rs @@ -0,0 +1,2 @@ +#[derive(Debug)] +pub struct COMUnknownType {} \ No newline at end of file diff --git a/core/src/runtime/com/mod.rs b/core/src/runtime/com/mod.rs new file mode 100644 index 0000000..2b084b4 --- /dev/null +++ b/core/src/runtime/com/mod.rs @@ -0,0 +1,5 @@ +pub mod com_interop; +pub mod com_constructor; +pub mod com_unknown_type; +pub mod com_method_call; +pub mod com_object_wrapper; \ No newline at end of file diff --git a/core/src/runtime/console.rs b/core/src/runtime/console.rs new file mode 100755 index 0000000..4d44ffc --- /dev/null +++ b/core/src/runtime/console.rs @@ -0,0 +1,48 @@ +use rusty_v8 as v8; +use core_bindings::{Windows::Win32::System::Console, Windows::Win32::System::WindowsProgramming}; +use std::ffi::{CString, c_void}; + +pub(crate) fn handle_console_log(scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, _retval: v8::ReturnValue) { + let mut value = String::new(); + for i in 0..args.length() { + let item = args.get(i).to_rust_string_lossy(scope); + if i == args.length() - 1 { + value.push_str(&item) + } else { + value.push_str(&item); + value.push_str(",") + } + if i == args.length() - 1 { + value.push_str("\n"); + } + } + + let length = value.chars().count() as u32; + let handle = unsafe { WindowsProgramming::GetStdHandle(WindowsProgramming::STD_OUTPUT_HANDLE) }; + let string = CString::new(value).unwrap(); + let mut written = 0_u32; + unsafe { + Console::WriteConsoleA(handle, string.as_ptr() as *const c_void, length, &mut written, std::ptr::null() as _); + } +} + +pub(crate) fn handle_console_dir(scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, _retval: v8::ReturnValue) { + let mut value = String::new(); + for i in 0..args.length() { + let item = args.get(i).to_rust_string_lossy(scope); + if i == args.length() - 1 { + value.push_str(&item) + } else { + value.push_str(&item); + value.push_str(",") + } + } + let length = value.chars().count() as u32; + let handle = unsafe { WindowsProgramming::GetStdHandle(WindowsProgramming::STD_OUTPUT_HANDLE) }; + + let string = CString::new(value).unwrap(); + let mut written = 0_u32; + unsafe { + Console::WriteConsoleA(handle, string.as_ptr() as *const c_void, length, &mut written, std::ptr::null()); + } +} \ No newline at end of file diff --git a/core/src/runtime/ffi/ff_boolean_type.rs b/core/src/runtime/ffi/ff_boolean_type.rs new file mode 100644 index 0000000..aa3e47d --- /dev/null +++ b/core/src/runtime/ffi/ff_boolean_type.rs @@ -0,0 +1,2 @@ +#[derive(Debug)] +pub struct FFIBooleanType {} \ No newline at end of file diff --git a/core/src/runtime/ffi/ffi_interop.rs b/core/src/runtime/ffi/ffi_interop.rs new file mode 100644 index 0000000..1d0bbc7 --- /dev/null +++ b/core/src/runtime/ffi/ffi_interop.rs @@ -0,0 +1,2 @@ +#[derive(Debug)] +pub struct FFIInterop {} \ No newline at end of file diff --git a/core/src/runtime/ffi/ffi_number_type.rs b/core/src/runtime/ffi/ffi_number_type.rs new file mode 100644 index 0000000..10a87a4 --- /dev/null +++ b/core/src/runtime/ffi/ffi_number_type.rs @@ -0,0 +1,2 @@ +#[derive(Debug)] +pub struct FFINumberType {} \ No newline at end of file diff --git a/core/src/runtime/ffi/ffi_void_type.rs b/core/src/runtime/ffi/ffi_void_type.rs new file mode 100644 index 0000000..fc4d3ae --- /dev/null +++ b/core/src/runtime/ffi/ffi_void_type.rs @@ -0,0 +1,2 @@ +#[derive(Debug)] +pub struct FFIVoidType {} \ No newline at end of file diff --git a/core/src/runtime/ffi/mod.rs b/core/src/runtime/ffi/mod.rs new file mode 100755 index 0000000..202dfc0 --- /dev/null +++ b/core/src/runtime/ffi/mod.rs @@ -0,0 +1,4 @@ +pub mod ffi_interop; +pub mod ff_boolean_type; +pub mod ffi_number_type; +pub mod ffi_void_type; \ No newline at end of file diff --git a/core/src/runtime/global.rs b/core/src/runtime/global.rs new file mode 100755 index 0000000..e69de29 diff --git a/core/src/runtime/mod.rs b/core/src/runtime/mod.rs new file mode 100755 index 0000000..5151836 --- /dev/null +++ b/core/src/runtime/mod.rs @@ -0,0 +1,232 @@ +mod global; +mod ffi; +mod console; +mod com; + +use rusty_v8 as v8; +use std::ffi::{CString, CStr, c_void, OsStr, OsString}; +use std::os::raw::{c_char, c_uint, c_long}; +use std::io::Read; +use std::os::windows::prelude::*; +use std::path::{Path, PathBuf}; +use windows::HSTRING; +use crate::runtime::com::com_interop::COMInterop; +use rusty_v8::{Value, Local, Handle}; +use std::convert::TryInto; + +pub struct Runtime { + isolate: v8::OwnedIsolate, + global_context: v8::Global, + app_root: String, +} + + +const MAX_IDENTIFIER_LENGTH: usize = 511; + + +impl Runtime { + pub fn new(app_root: &str) -> Self { + let platform = v8::new_default_platform().unwrap(); + v8::V8::initialize_platform(platform); + v8::V8::initialize(); + let mut isolate = v8::Isolate::new(Default::default()); + + isolate.set_capture_stack_trace_for_uncaught_exceptions(true, 100); + + let global_context; + { + let mut scope = &mut v8::HandleScope::new(&mut isolate); + let mut global = v8::FunctionTemplate::new(scope, Runtime::handle_global); + + { + let class_name = v8::String::new(scope, "NativeScriptGlobalObject").unwrap(); + global.set_class_name(class_name); + } + + let mut global_template = v8::ObjectTemplate::new_from_template(scope, global); + + global_template.set_internal_field_count(0); + + { + { + Runtime::init_performance(scope, &mut global_template); + } + + { + Runtime::init_time(scope, &mut global_template); + } + + + let mut context = v8::Context::new_from_template(scope, global_template); + + let mut local_scope = v8::ContextScope::new(scope, context); + + { + Runtime::init_global(&mut local_scope, context); + } + + { + Runtime::init_console(&mut local_scope, context); + } + + { + Runtime::init_meta(&mut local_scope, context); + } + + { + global_context = v8::Global::new(&mut local_scope, context); + } + } + } + + Self { + isolate, + global_context, + app_root: app_root.to_string(), + } + } + + fn run_script(&mut self, script: &str) { + /* + let path = PathBuf::from(script); + println!("??? {:?}", path.to_string_lossy()); + let mut file = std::fs::File::open(std::fs::canonicalize(&path).unwrap()).unwrap(); + let mut data = Vec::new(); + file.read_to_end(&mut data); + let script = String::from_utf8_lossy(data.as_slice()); + */ + + let mut isolate = &mut self.isolate; + let mut scope = &mut v8::HandleScope::new(isolate); + let mut local = v8::Local::new(scope, &self.global_context); + let mut scope = &mut v8::ContextScope::new(scope, local); + let code = v8::String::new(scope, script).unwrap(); + let script = v8::Script::compile(&mut scope, code, None).unwrap(); + let result = script.run(&mut scope).unwrap(); + let result = result.to_string(&mut scope).unwrap(); + } + + fn handle_global(_scope: &mut v8::HandleScope, _args: v8::FunctionCallbackArguments, _retval: v8::ReturnValue) {} + + fn init_global(scope: &mut v8::ContextScope>, context: v8::Local) { + let mut global = context.global(scope); + let value = v8::String::new( + scope, "global", + ).unwrap().into(); + global.define_own_property(scope, value, global.into(), v8::READ_ONLY); + let interop = Box::new(COMInterop::new()); + let interop = Box::into_raw(interop); + let value = v8::External::new(scope, interop as *mut c_void); + global.set_internal_field(0, value.into()); + } + + fn init_console(scope: &mut v8::ContextScope>, context: v8::Local) { + let console = v8::Object::new(scope); + let log = v8::Function::new(scope, console::handle_console_log).unwrap(); + let dir = v8::Function::new(scope, console::handle_console_dir).unwrap(); + + { + let name = v8::String::new(scope, "log").unwrap().into(); + console.set( + scope, + name, + log.into(), + ); + } + + { + let name = v8::String::new(scope, "dir").unwrap().into(); + console.set( + scope, + name, + dir.into(), + ); + } + + let mut global = context.global(scope); + let value = v8::String::new( + scope, "console", + ).unwrap().into(); + global.define_own_property(scope, value, console.into(), v8::READ_ONLY); + } + + fn handle_time(scope: &mut v8::HandleScope, + _args: v8::FunctionCallbackArguments, + mut retval: v8::ReturnValue) { + let now = chrono::Utc::now(); + retval.set( + v8::Number::new(scope, (now.timestamp_millis() / 1000000) as f64).into() + ) + } + + fn init_time(scope: &mut v8::HandleScope<()>, global: &mut v8::Local) { + let time = v8::FunctionTemplate::new(scope, Runtime::handle_time); + global.set( + v8::String::new(scope, "time").unwrap().into(), time.into(), + ); + } + + fn init_performance(scope: &mut v8::HandleScope<()>, global: &mut v8::Local) { + let performance = v8::ObjectTemplate::new(scope); + let now = v8::FunctionTemplate::new(scope, Runtime::handle_now); + performance.set( + v8::String::new(scope, "now").unwrap().into(), + now.into(), + ); + global.set( + v8::String::new(scope, "performance").unwrap().into(), + performance.into(), + ); + } + + fn handle_now(scope: &mut v8::HandleScope, + _args: v8::FunctionCallbackArguments, + mut retval: v8::ReturnValue) { + let now = chrono::Utc::now(); + retval.set( + v8::Number::new(scope, now.timestamp_nanos() as f64).into() + ) + } + + fn init_meta(scope: &mut v8::ContextScope>, context: v8::Local) { + let meta = v8::Function::new(scope, Runtime::handle_meta).unwrap(); + let mut global = context.global(scope); + let value = v8::String::new( + scope, "$", + ).unwrap().into(); + global.define_own_property(scope, value, meta.into(), v8::READ_ONLY); + } + + fn handle_meta(scope: &mut v8::HandleScope, + args: v8::FunctionCallbackArguments, + mut retval: v8::ReturnValue) { + println!("handle meta {:?}", args.get(0).to_rust_string_lossy(scope)); + let isolate = scope.get_isolate_mut(); + let class_name = args.get(0).to_rust_string_lossy(scope); + let global = scope.get_current_context().global(scope); + match global.get_internal_field(scope, 0) { + None => {} + Some(value) => { + let interop: v8::External = value.try_into().unwrap(); + let interop = interop.value() as *mut COMInterop; + } + } + } +} + + +#[no_mangle] +pub extern fn runtime_init(main_entry: *const c_char) -> i64 { + let string = unsafe { CStr::from_ptr(main_entry) }.to_string_lossy(); + Box::into_raw(Box::new(Runtime::new(string.as_ref()))) as i64 +} + +#[no_mangle] +pub extern fn runtime_runscript(runtime: i64, script: *const c_char) { + if runtime != 0 { + let mut runtime: *mut Runtime = runtime as _; + let mut runtime = unsafe { &mut *runtime }; + let script = unsafe { CStr::from_ptr(script) }.to_string_lossy(); + runtime.run_script(script.as_ref()); + } +} \ No newline at end of file