├── .gitattributes ├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── SECURITY.md ├── cppwin32 ├── base.h ├── cmd_reader.h ├── code_writers.h ├── cppwin32.sln ├── cppwin32.vcxproj ├── cppwin32.vcxproj.filters ├── file_writers.h ├── helpers.h ├── main.cpp ├── resource.h ├── settings.h ├── task_group.h ├── text_writer.h ├── type_dependency_graph.h ├── type_writers.h ├── version.aps ├── version.rc └── winmd │ ├── LICENSE │ ├── impl │ ├── base.h │ └── winmd_reader │ │ ├── cache.h │ │ ├── column.h │ │ ├── custom_attribute.h │ │ ├── database.h │ │ ├── enum.h │ │ ├── enum_traits.h │ │ ├── filter.h │ │ ├── flags.h │ │ ├── helpers.h │ │ ├── index.h │ │ ├── key.h │ │ ├── pe.h │ │ ├── schema.h │ │ ├── signature.h │ │ ├── table.h │ │ ├── type_helpers.h │ │ └── view.h │ ├── readme.md │ ├── readme.txt │ └── winmd_reader.h └── test ├── SampleD3DApp ├── SampleD3DApp.sln └── SampleD3DApp │ ├── D3D12HelloWindow.cpp │ ├── D3D12HelloWindow.h │ ├── DXSample.cpp │ ├── DXSample.h │ ├── Main.cpp │ ├── SampleD3DApp.vcxproj │ ├── SampleD3DApp.vcxproj.filters │ ├── pch.cpp │ └── pch.h ├── Windows.Win32.Interop.dll └── Windows.Win32.winmd /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | * text eol=lf 3 | *.png -text 4 | *.exe -text 5 | *.dll -text 6 | *.winmd -text 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | # *.dll 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | 30 | # Visual Studio files 31 | .vs 32 | .vscode 33 | .nuget 34 | *.user 35 | *.nupkg 36 | 37 | build 38 | packages 39 | Debug 40 | Release 41 | Generated Files -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The C++ Windows SDK projection 2 | 3 | C++/Win32 (cppwin32) is a standard C++ language projection for Windows SDK APIs. True, the Windows SDK already releases headers that can be consumed from C++, but those headers have some severe historical and compatiblity constraints that hamper C++ developers that wish to enjoy modern language features. Goals include: 4 | - Better compliance with C++ standards, particularly C++17 and newer. 5 | - Eliminating the use of macros for constants, enumerations, and functions, and instead using C++ language constructs that participate in the type system and respect scope. 6 | - Paving the way towards a Windows SDK that can be used with C++ modules. 7 | 8 | Another goal under investigation and discussion is to converge this projection with the [C++/WinRT projection](https://github.com/microsoft/cppwinrt/). 9 | 10 | ## How it works 11 | 12 | This projection is similar to [C++/WinRT](https://github.com/microsoft/cppwinrt/) in that it generates projection header files from metadata. Instead of using Windows Runtime metadata, it uses metadata produced by the [Win32 Metadata Project](https://github.com/microsoft/win32metadata/). 13 | 14 | This project is still in the early stages and will continue to grow and evolve. Watch for a Nuget package soon. 15 | 16 | ## Contributing 17 | 18 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 19 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 20 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 21 | 22 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 23 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions 24 | provided by the bot. You will only need to do this once across all repos using our CLA. 25 | 26 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 27 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 28 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 29 | 30 | ## Trademarks 31 | 32 | This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft 33 | trademarks or logos is subject to and must follow 34 | [Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). 35 | Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. 36 | Any use of third-party trademarks or logos are subject to those third-party's policies. 37 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | -------------------------------------------------------------------------------- /cppwin32/cppwin32.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30503.244 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cppwin32", "cppwin32.vcxproj", "{F2FB982D-B69D-4D09-BE5E-E93117030819}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {F2FB982D-B69D-4D09-BE5E-E93117030819}.Debug|x64.ActiveCfg = Debug|x64 17 | {F2FB982D-B69D-4D09-BE5E-E93117030819}.Debug|x64.Build.0 = Debug|x64 18 | {F2FB982D-B69D-4D09-BE5E-E93117030819}.Debug|x86.ActiveCfg = Debug|Win32 19 | {F2FB982D-B69D-4D09-BE5E-E93117030819}.Debug|x86.Build.0 = Debug|Win32 20 | {F2FB982D-B69D-4D09-BE5E-E93117030819}.Release|x64.ActiveCfg = Release|x64 21 | {F2FB982D-B69D-4D09-BE5E-E93117030819}.Release|x64.Build.0 = Release|x64 22 | {F2FB982D-B69D-4D09-BE5E-E93117030819}.Release|x86.ActiveCfg = Release|Win32 23 | {F2FB982D-B69D-4D09-BE5E-E93117030819}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {1FE448E7-8728-4B17-8448-A8471E62BCF7} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /cppwin32/cppwin32.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {f2fb982d-b69d-4d09-be5e-e93117030819} 25 | cppwin32 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Level3 88 | true 89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);CPPWIN32_VERSION_STRING="0.0.0.1" 90 | true 91 | winmd;%(AdditionalIncludeDirectories) 92 | stdcpp17 93 | 94 | 95 | Console 96 | true 97 | 98 | 99 | 100 | 101 | Level3 102 | true 103 | true 104 | true 105 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);CPPWIN32_VERSION_STRING="0.0.0.1" 106 | true 107 | winmd;%(AdditionalIncludeDirectories) 108 | stdcpp17 109 | 110 | 111 | Console 112 | true 113 | true 114 | true 115 | 116 | 117 | 118 | 119 | Level3 120 | true 121 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions);CPPWIN32_VERSION_STRING="0.0.0.1" 122 | true 123 | winmd;%(AdditionalIncludeDirectories) 124 | stdcpp17 125 | 126 | 127 | Console 128 | true 129 | 130 | 131 | 132 | 133 | Level3 134 | true 135 | true 136 | true 137 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions);CPPWIN32_VERSION_STRING="0.0.0.1" 138 | true 139 | winmd;%(AdditionalIncludeDirectories) 140 | stdcpp17 141 | 142 | 143 | Console 144 | true 145 | true 146 | true 147 | 148 | 149 | 150 | 151 | true 152 | true 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | true 171 | true 172 | true 173 | true 174 | 175 | 176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /cppwin32/cppwin32.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files 41 | 42 | 43 | Header Files 44 | 45 | 46 | Header Files 47 | 48 | 49 | Header Files 50 | 51 | 52 | 53 | 54 | Source Files 55 | 56 | 57 | 58 | 59 | Resource Files 60 | 61 | 62 | -------------------------------------------------------------------------------- /cppwin32/file_writers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace cppwin32 4 | { 5 | static void write_namespace_0_h(std::string_view const& ns, cache::namespace_members const& members) 6 | { 7 | writer w; 8 | w.type_namespace = ns; 9 | 10 | { 11 | auto wrap = wrap_type_namespace(w, ns); 12 | 13 | w.write("#pragma region enums\n"); 14 | w.write_each(members.enums); 15 | w.write("#pragma endregion enums\n\n"); 16 | 17 | w.write("#pragma region forward_declarations\n"); 18 | w.write_each(members.structs); 19 | w.write_each(members.interfaces); 20 | w.write("#pragma endregion forward_declarations\n\n"); 21 | 22 | w.write("#pragma region delegates\n"); 23 | write_delegates(w, members.delegates); 24 | w.write("#pragma endregion delegates\n\n"); 25 | } 26 | { 27 | auto wrap = wrap_impl_namespace(w); 28 | 29 | w.write("#pragma region guids\n"); 30 | w.write_each(members.interfaces); 31 | w.write("#pragma endregion guids\n\n"); 32 | } 33 | 34 | write_close_file_guard(w); 35 | w.swap(); 36 | 37 | write_preamble(w); 38 | write_open_file_guard(w, ns, '0'); 39 | 40 | for (auto&& depends : w.depends) 41 | { 42 | auto guard = wrap_type_namespace(w, depends.first); 43 | w.write_each(depends.second); 44 | } 45 | 46 | w.save_header('0'); 47 | } 48 | 49 | static void write_namespace_1_h(std::string_view const& ns, cache::namespace_members const& members) 50 | { 51 | writer w; 52 | w.type_namespace = ns; 53 | 54 | w.write("#include \"win32/impl/complex_structs.h\"\n"); 55 | 56 | { 57 | auto wrap = wrap_type_namespace(w, ns); 58 | 59 | w.write("#pragma region interfaces\n"); 60 | //write_interfaces(w, members.interfaces); 61 | w.write("#pragma endregion interfaces\n\n"); 62 | } 63 | 64 | write_close_file_guard(w); 65 | w.swap(); 66 | write_preamble(w); 67 | write_open_file_guard(w, ns, '1'); 68 | 69 | for (auto&& depends : w.depends) 70 | { 71 | w.write_depends(depends.first, '0'); 72 | } 73 | 74 | w.write_depends(w.type_namespace, '0'); 75 | w.save_header('1'); 76 | } 77 | 78 | static void write_namespace_2_h(std::string_view const& ns, cache::namespace_members const& members) 79 | { 80 | writer w; 81 | w.type_namespace = ns; 82 | 83 | w.write("#include \"win32/impl/complex_interfaces.h\"\n"); 84 | 85 | { 86 | // No namespace 87 | w.write("#pragma region abi_methods\n"); 88 | w.write_each(members.classes); 89 | w.write("#pragma endregion abi_methods\n\n"); 90 | } 91 | 92 | write_close_file_guard(w); 93 | w.swap(); 94 | write_preamble(w); 95 | write_open_file_guard(w, ns, '2'); 96 | 97 | w.write_depends(w.type_namespace, '1'); 98 | // Workaround for https://github.com/microsoft/cppwin32/issues/2 99 | for (auto&& extern_depends : w.extern_depends) 100 | { 101 | auto guard = wrap_type_namespace(w, extern_depends.first); 102 | w.write_each(extern_depends.second); 103 | } 104 | w.save_header('2'); 105 | } 106 | 107 | static void write_namespace_h(std::string_view const& ns, cache::namespace_members const& members) 108 | { 109 | writer w; 110 | w.type_namespace = ns; 111 | { 112 | auto wrap = wrap_type_namespace(w, ns); 113 | 114 | w.write("#pragma region methods\n"); 115 | w.write_each(members.classes); 116 | w.write("#pragma endregion methods\n\n"); 117 | } 118 | 119 | write_close_file_guard(w); 120 | w.swap(); 121 | write_preamble(w); 122 | write_open_file_guard(w, ns); 123 | write_version_assert(w); 124 | 125 | w.write_depends(w.type_namespace, '2'); 126 | // Workaround for https://github.com/microsoft/cppwin32/issues/2 127 | for (auto&& extern_depends : w.extern_depends) 128 | { 129 | auto guard = wrap_type_namespace(w, extern_depends.first); 130 | w.write_each(extern_depends.second); 131 | } 132 | w.save_header(); 133 | } 134 | 135 | static void write_complex_structs_h(cache const& c) 136 | { 137 | writer w; 138 | 139 | type_dependency_graph graph; 140 | for (auto&& [ns, members] : c.namespaces()) 141 | { 142 | for (auto&& s : members.structs) 143 | { 144 | graph.add_struct(s); 145 | } 146 | } 147 | 148 | graph.walk_graph([&](TypeDef const& type) 149 | { 150 | if (!is_nested(type)) 151 | { 152 | auto guard = wrap_type_namespace(w, type.TypeNamespace()); 153 | write_struct(w, type); 154 | } 155 | }); 156 | 157 | write_close_file_guard(w); 158 | w.swap(); 159 | 160 | write_preamble(w); 161 | write_open_file_guard(w, "complex_structs"); 162 | 163 | for (auto&& depends : w.depends) 164 | { 165 | w.write_depends(depends.first, '0'); 166 | } 167 | 168 | w.flush_to_file(settings.output_folder + "win32/impl/complex_structs.h"); 169 | } 170 | 171 | static void write_complex_interfaces_h(cache const& c) 172 | { 173 | writer w; 174 | 175 | type_dependency_graph graph; 176 | for (auto&& [ns, members] : c.namespaces()) 177 | { 178 | for (auto&& s : members.interfaces) 179 | { 180 | graph.add_interface(s); 181 | } 182 | } 183 | 184 | graph.walk_graph([&](TypeDef const& type) 185 | { 186 | if (!is_nested(type)) 187 | { 188 | auto guard = wrap_type_namespace(w, type.TypeNamespace()); 189 | write_interface(w, type); 190 | } 191 | }); 192 | 193 | write_close_file_guard(w); 194 | w.swap(); 195 | 196 | write_preamble(w); 197 | write_open_file_guard(w, "complex_interfaces"); 198 | 199 | for (auto&& depends : w.depends) 200 | { 201 | w.write_depends(depends.first, '1'); 202 | } 203 | // Workaround for https://github.com/microsoft/cppwin32/issues/2 204 | for (auto&& extern_depends : w.extern_depends) 205 | { 206 | auto guard = wrap_type_namespace(w, extern_depends.first); 207 | w.write_each(extern_depends.second); 208 | } 209 | 210 | w.flush_to_file(settings.output_folder + "win32/impl/complex_interfaces.h"); 211 | } 212 | } -------------------------------------------------------------------------------- /cppwin32/helpers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace cppwin32 4 | { 5 | using namespace winmd::reader; 6 | 7 | template struct visit_overload : T... { using T::operator()...; }; 8 | 9 | template 10 | auto call(V&& variant, C&&...call) 11 | { 12 | return std::visit(visit_overload{ std::forward(call)... }, std::forward(variant)); 13 | } 14 | 15 | struct type_name 16 | { 17 | std::string_view name; 18 | std::string_view name_space; 19 | 20 | explicit type_name(TypeDef const& type) : 21 | name(type.TypeName()), 22 | name_space(type.TypeNamespace()) 23 | { 24 | } 25 | 26 | explicit type_name(TypeRef const& type) : 27 | name(type.TypeName()), 28 | name_space(type.TypeNamespace()) 29 | { 30 | } 31 | 32 | explicit type_name(coded_index const& type) 33 | { 34 | auto const& [type_namespace, type_name] = get_type_namespace_and_name(type); 35 | name_space = type_namespace; 36 | name = type_name; 37 | } 38 | }; 39 | 40 | bool operator==(type_name const& left, type_name const& right) 41 | { 42 | return left.name == right.name && left.name_space == right.name_space; 43 | } 44 | 45 | bool operator==(type_name const& left, std::string_view const& right) 46 | { 47 | if (left.name.size() + 1 + left.name_space.size() != right.size()) 48 | { 49 | return false; 50 | } 51 | 52 | if (right[left.name_space.size()] != '.') 53 | { 54 | return false; 55 | } 56 | 57 | if (0 != right.compare(left.name_space.size() + 1, left.name.size(), left.name)) 58 | { 59 | return false; 60 | } 61 | 62 | return 0 == right.compare(0, left.name_space.size(), left.name_space); 63 | } 64 | 65 | struct method_signature 66 | { 67 | explicit method_signature(MethodDef const& method) : 68 | m_method(method), 69 | m_signature(method.Signature()) 70 | { 71 | auto params = method.ParamList(); 72 | 73 | if (m_signature.ReturnType() && params.first != params.second && params.first.Sequence() == 0) 74 | { 75 | m_return = params.first; 76 | ++params.first; 77 | } 78 | 79 | for (uint32_t i{}; i != size(m_signature.Params()); ++i) 80 | { 81 | m_params.emplace_back(params.first + i, &m_signature.Params().first[i]); 82 | } 83 | } 84 | 85 | std::vector>& params() 86 | { 87 | return m_params; 88 | } 89 | 90 | std::vector> const& params() const 91 | { 92 | return m_params; 93 | } 94 | 95 | auto const& return_signature() const 96 | { 97 | return m_signature.ReturnType(); 98 | } 99 | 100 | auto return_param_name() const 101 | { 102 | std::string_view name; 103 | 104 | if (m_return && !m_return.Name().empty()) 105 | { 106 | name = m_return.Name(); 107 | } 108 | else 109 | { 110 | name = "win32_impl_result"; 111 | } 112 | 113 | return name; 114 | } 115 | 116 | auto return_param() const 117 | { 118 | return m_return; 119 | } 120 | 121 | MethodDef const& method() const 122 | { 123 | return m_method; 124 | } 125 | 126 | private: 127 | 128 | MethodDef m_method; 129 | MethodDefSig m_signature; 130 | std::vector> m_params; 131 | Param m_return; 132 | }; 133 | 134 | enum class param_category 135 | { 136 | enum_type, 137 | struct_type, 138 | array_type, 139 | fundamental_type, 140 | interface_type, 141 | delegate_type, 142 | generic_type 143 | }; 144 | 145 | inline param_category get_category(coded_index const& type, TypeDef* signature_type = nullptr) 146 | { 147 | TypeDef type_def; 148 | if (type.type() == TypeDefOrRef::TypeDef) 149 | { 150 | type_def = type.TypeDef(); 151 | } 152 | else 153 | { 154 | auto type_ref = type.TypeRef(); 155 | if (type_name(type_ref) == "System.Guid") 156 | { 157 | return param_category::struct_type; 158 | } 159 | type_def = find_required(type_ref); 160 | } 161 | 162 | if (signature_type) 163 | { 164 | *signature_type = type_def; 165 | } 166 | 167 | switch (get_category(type_def)) 168 | { 169 | case category::interface_type: 170 | return param_category::interface_type; 171 | case category::enum_type: 172 | return param_category::enum_type; 173 | case category::struct_type: 174 | return param_category::struct_type; 175 | case category::delegate_type: 176 | return param_category::delegate_type; 177 | default: 178 | return param_category::generic_type; 179 | } 180 | } 181 | 182 | inline param_category get_category(TypeSig const& signature, TypeDef* signature_type = nullptr) 183 | { 184 | if (signature.is_szarray()) 185 | { 186 | return param_category::array_type; 187 | } 188 | 189 | if (signature.element_type() == ElementType::Class) 190 | { 191 | return param_category::interface_type; 192 | } 193 | 194 | param_category result{}; 195 | 196 | call(signature.Type(), 197 | [&](ElementType type) 198 | { 199 | result = param_category::fundamental_type; 200 | }, 201 | [&](coded_index const& type) 202 | { 203 | result = get_category(type, signature_type); 204 | }, 205 | [&](auto&&) 206 | { 207 | result = param_category::generic_type; 208 | }); 209 | return result; 210 | } 211 | 212 | inline bool is_com_interface(TypeDef const& type) 213 | { 214 | if (type.TypeName() == "IUnknown") 215 | { 216 | return true; 217 | } 218 | 219 | for (auto&& base : type.InterfaceImpl()) 220 | { 221 | auto base_type = find(base.Interface()); 222 | if (base_type && is_com_interface(base_type)) 223 | { 224 | return true; 225 | } 226 | } 227 | return false; 228 | } 229 | 230 | inline bool is_union(TypeDef const& type) 231 | { 232 | return type.Flags().Layout() == TypeLayout::ExplicitLayout; 233 | } 234 | 235 | inline bool is_nested(coded_index const& type) 236 | { 237 | if (type.type() == TypeDefOrRef::TypeDef) 238 | { 239 | return is_nested(type.TypeDef()); 240 | } 241 | else 242 | { 243 | XLANG_ASSERT(type.type() == TypeDefOrRef::TypeRef); 244 | return is_nested(type.TypeRef()); 245 | } 246 | } 247 | 248 | MethodDef get_delegate_method(TypeDef const& type) 249 | { 250 | MethodDef invoke; 251 | for (auto&& method : type.MethodList()) 252 | { 253 | if (method.Name() == "Invoke") 254 | { 255 | invoke = method; 256 | break; 257 | } 258 | } 259 | return invoke; 260 | } 261 | 262 | coded_index get_base_interface(TypeDef const& type) 263 | { 264 | auto bases = type.InterfaceImpl(); 265 | if (!empty(bases)) 266 | { 267 | XLANG_ASSERT(size(bases) == 1); 268 | return bases.first.Interface(); 269 | } 270 | return {}; 271 | } 272 | } -------------------------------------------------------------------------------- /cppwin32/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "cmd_reader.h" 3 | #include "settings.h" 4 | #include "task_group.h" 5 | #include "text_writer.h" 6 | #include "type_dependency_graph.h" 7 | #include "type_writers.h" 8 | #include "code_writers.h" 9 | #include "file_writers.h" 10 | #include 11 | 12 | using namespace std::filesystem; 13 | 14 | namespace cppwin32 15 | { 16 | settings_type settings; 17 | 18 | struct usage_exception {}; 19 | 20 | static constexpr option options[] 21 | { 22 | { "input", 0, option::no_max, "", "Windows metadata to include in projection" }, 23 | { "reference", 0, option::no_max, "", "Windows metadata to reference from projection" }, 24 | { "output", 0, 1, "", "Location of generated projection and component templates" }, 25 | { "verbose", 0, 0, {}, "Show detailed progress information" }, 26 | { "pch", 0, 1, "", "Specify name of precompiled header file (defaults to pch.h)" }, 27 | { "include", 0, option::no_max, "", "One or more prefixes to include in input" }, 28 | { "exclude", 0, option::no_max, "", "One or more prefixes to exclude from input" }, 29 | { "base", 0, 0, {}, "Generate base.h unconditionally" }, 30 | { "help", 0, option::no_max, {}, "Show detailed help with examples" }, 31 | { "?", 0, option::no_max, {}, {} }, 32 | { "library", 0, 1, "", "Specify library prefix (defaults to win32)" }, 33 | { "filter" }, // One or more prefixes to include in input (same as -include) 34 | { "license", 0, 0 }, // Generate license comment 35 | { "brackets", 0, 0 }, // Use angle brackets for #includes (defaults to quotes) 36 | }; 37 | 38 | 39 | static void print_usage(writer& w) 40 | { 41 | static auto printColumns = [](writer& w, std::string_view const& col1, std::string_view const& col2) 42 | { 43 | w.write_printf(" %-20s%s\n", col1.data(), col2.data()); 44 | }; 45 | 46 | static auto printOption = [](writer& w, option const& opt) 47 | { 48 | if (opt.desc.empty()) 49 | { 50 | return; 51 | } 52 | printColumns(w, w.write_temp("-% %", opt.name, opt.arg), opt.desc); 53 | }; 54 | 55 | auto format = R"( 56 | C++/Win32 v% 57 | Copyright (c) Microsoft Corporation. All rights reserved. 58 | 59 | cppwin32.exe [options...] 60 | 61 | Options: 62 | 63 | % ^@ Response file containing command line options 64 | 65 | Where is one or more of: 66 | 67 | path Path to winmd file or recursively scanned folder 68 | )"; 69 | w.write(format, CPPWIN32_VERSION_STRING, bind_each(printOption, options)); 70 | } 71 | 72 | static void process_args(reader const& args) 73 | { 74 | settings.verbose = args.exists("verbose"); 75 | settings.fastabi = args.exists("fastabi"); 76 | 77 | settings.input = args.files("input", database::is_database); 78 | settings.reference = args.files("reference", database::is_database); 79 | 80 | settings.component = args.exists("component"); 81 | settings.base = args.exists("base"); 82 | 83 | settings.license = args.exists("license"); 84 | settings.brackets = args.exists("brackets"); 85 | 86 | std::filesystem::path output_folder = args.value("output"); 87 | std::filesystem::create_directories(output_folder / "win32/impl"); 88 | settings.output_folder = std::filesystem::canonical(output_folder).string(); 89 | settings.output_folder += '\\'; 90 | 91 | for (auto&& include : args.values("include")) 92 | { 93 | settings.include.insert(include); 94 | } 95 | 96 | for (auto&& include : args.values("filter")) 97 | { 98 | settings.include.insert(include); 99 | } 100 | 101 | for (auto&& exclude : args.values("exclude")) 102 | { 103 | settings.exclude.insert(exclude); 104 | } 105 | 106 | if (settings.component) 107 | { 108 | settings.component_overwrite = args.exists("overwrite"); 109 | settings.component_name = args.value("name"); 110 | 111 | if (settings.component_name.empty()) 112 | { 113 | // For compatibility with C++/WinRT 1.0, the component_name defaults to the *first* 114 | // input, hence the use of values() here that will return the args in input order. 115 | 116 | auto& values = args.values("input"); 117 | 118 | if (!values.empty()) 119 | { 120 | settings.component_name = path(values[0]).filename().replace_extension().string(); 121 | } 122 | } 123 | 124 | settings.component_pch = args.value("pch", "pch.h"); 125 | settings.component_prefix = args.exists("prefix"); 126 | settings.component_lib = args.value("library", "win32"); 127 | settings.component_opt = args.exists("optimize"); 128 | settings.component_ignore_velocity = args.exists("ignore_velocity"); 129 | 130 | if (settings.component_pch == ".") 131 | { 132 | settings.component_pch.clear(); 133 | } 134 | 135 | auto component = args.value("component"); 136 | 137 | if (!component.empty()) 138 | { 139 | create_directories(component); 140 | settings.component_folder = canonical(component).string(); 141 | settings.component_folder += '\\'; 142 | } 143 | } 144 | } 145 | 146 | static auto get_files_to_cache() 147 | { 148 | std::vector files; 149 | files.insert(files.end(), settings.input.begin(), settings.input.end()); 150 | files.insert(files.end(), settings.reference.begin(), settings.reference.end()); 151 | return files; 152 | } 153 | 154 | static int run(int const argc, char* argv[]) 155 | { 156 | int result{}; 157 | writer w; 158 | 159 | try 160 | { 161 | auto const start_time = std::chrono::high_resolution_clock::now(); 162 | 163 | reader args{ argc, argv, options }; 164 | 165 | if (!args || args.exists("help") || args.exists("?")) 166 | { 167 | throw usage_exception{}; 168 | } 169 | 170 | process_args(args); 171 | cache c{ get_files_to_cache() }; 172 | task_group group; 173 | 174 | w.flush_to_console(); 175 | 176 | for (auto&& [ns, members] : c.namespaces()) 177 | { 178 | group.add([&, &ns = ns, &members = members] 179 | { 180 | write_namespace_0_h(ns, members); 181 | write_namespace_1_h(ns, members); 182 | write_namespace_2_h(ns, members); 183 | write_namespace_h(ns, members); 184 | }); 185 | } 186 | group.add([&c] { write_complex_structs_h(c); }); 187 | group.add([&c] { write_complex_interfaces_h(c); }); 188 | 189 | std::filesystem::copy_file("base.h", settings.output_folder + "win32/" + "base.h", std::filesystem::copy_options::overwrite_existing); 190 | } 191 | catch (usage_exception const&) 192 | { 193 | print_usage(w); 194 | } 195 | catch (std::exception const& e) 196 | { 197 | w.write("cppwin32 : error %\n", e.what()); 198 | result = 1; 199 | } 200 | 201 | w.flush_to_console(result == 0); 202 | return result; 203 | } 204 | } 205 | 206 | int main(int const argc, char* argv[]) 207 | { 208 | cppwin32::run(argc, argv); 209 | 210 | //// Hack prototype command line args for now 211 | //o.input = argv[1]; 212 | //o.output_folder = std::filesystem::canonical(argv[2]); 213 | //std::filesystem::create_directories(o.output_folder); 214 | 215 | //winmd::reader::cache c{ o.input }; 216 | 217 | //std::set raii_helpers; 218 | 219 | //for (auto const& [ns, members] : c.namespaces()) 220 | //{ 221 | // if (ns.empty()) 222 | // { 223 | // continue; 224 | // } 225 | // writer w; 226 | // w.write("#include \"base.h\"\n"); 227 | // w.type_namespace = ns; 228 | // { 229 | // auto wrap = wrap_type_namespace(w, ns); 230 | 231 | // w.write("#pragma region enums\n"); 232 | // w.write_each(members.enums); 233 | // w.write("#pragma endregion enums\n\n"); 234 | 235 | // w.write("#pragma region forward_declarations\n"); 236 | // w.write_each(members.structs); 237 | // w.write_each(members.interfaces); 238 | // w.write("#pragma endregion forward_declarations\n\n"); 239 | 240 | // w.write("#pragma region delegates\n"); 241 | // write_delegates(w, members.delegates); 242 | // w.write("#pragma endregion delegates\n\n"); 243 | // } 244 | // { 245 | // auto wrap = wrap_impl_namespace(w); 246 | 247 | // w.write("#pragma region guids\n"); 248 | // w.write_each(members.interfaces); 249 | // w.write("#pragma endregion guids\n\n"); 250 | 251 | // //w.write("#pragma region consume\n"); 252 | // //w.write_each(members.interfaces); 253 | // //w.write("#pragma endregion consume\n\n"); 254 | // } 255 | // { 256 | // auto wrap = wrap_type_namespace(w, ns); 257 | 258 | // w.write("#pragma region structs\n"); 259 | // write_structs(w, members.structs); 260 | // w.write("#pragma endregion structs\n\n"); 261 | 262 | // w.write("#pragma region interfaces\n"); 263 | // write_interfaces(w, members.interfaces); 264 | // w.write("#pragma endregion interfaces\n\n"); 265 | // } 266 | // { 267 | // w.write("#pragma region abi_methods\n"); 268 | // w.write_each(members.classes); 269 | // w.write("#pragma endregion abi_methods\n\n"); 270 | // } 271 | // { 272 | // auto wrap = wrap_type_namespace(w, ns); 273 | 274 | // w.write("#pragma region raii_helpers\n"); 275 | // w.write_each(members.classes, raii_helpers); 276 | // w.write("#pragma endregion raii_helpers\n\n"); 277 | 278 | // w.write("#pragma region methods\n"); 279 | // w.write_each(members.classes); 280 | // w.write("#pragma endregion methods\n\n"); 281 | 282 | // w.write("#pragma region enum_operators\n"); 283 | // w.write_each(members.enums); 284 | // w.write("#pragma endregion enum_operators\n\n"); 285 | // } 286 | // { 287 | // auto wrap = wrap_impl_namespace(w); 288 | 289 | // //w.write("#pragma region consume_methods\n"); 290 | // //w.write_each(members.interfaces); 291 | // //w.write("#pragma endregion consume_methods\n\n"); 292 | // } 293 | 294 | // w.save_header(o.output_folder.string()); 295 | 296 | // std::filesystem::copy_file("base.h", o.output_folder / "base.h", std::filesystem::copy_options::overwrite_existing); 297 | //} 298 | } 299 | -------------------------------------------------------------------------------- /cppwin32/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by version.rc 4 | 5 | // Next default values for new objects 6 | // 7 | #ifdef APSTUDIO_INVOKED 8 | #ifndef APSTUDIO_READONLY_SYMBOLS 9 | #define _APS_NEXT_RESOURCE_VALUE 101 10 | #define _APS_NEXT_COMMAND_VALUE 40001 11 | #define _APS_NEXT_CONTROL_VALUE 1001 12 | #define _APS_NEXT_SYMED_VALUE 101 13 | #endif 14 | #endif 15 | -------------------------------------------------------------------------------- /cppwin32/settings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace cppwin32 4 | { 5 | struct settings_type 6 | { 7 | std::set input; 8 | std::set reference; 9 | 10 | std::string output_folder; 11 | bool base{}; 12 | bool license{}; 13 | bool brackets{}; 14 | bool verbose{}; 15 | bool component{}; 16 | std::string component_folder; 17 | std::string component_name; 18 | std::string component_pch; 19 | bool component_prefix{}; 20 | bool component_overwrite{}; 21 | std::string component_lib; 22 | bool component_opt{}; 23 | bool component_ignore_velocity{}; 24 | 25 | std::set include; 26 | std::set exclude; 27 | 28 | winmd::reader::filter projection_filter; 29 | winmd::reader::filter component_filter; 30 | 31 | bool fastabi{}; 32 | std::map fastabi_cache; 33 | }; 34 | 35 | extern settings_type settings; 36 | } 37 | -------------------------------------------------------------------------------- /cppwin32/task_group.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace cppwin32 4 | { 5 | struct task_group 6 | { 7 | task_group(task_group const&) = delete; 8 | task_group& operator=(task_group const&) = delete; 9 | 10 | task_group() noexcept = default; 11 | 12 | ~task_group() noexcept 13 | { 14 | for (auto&& task : m_tasks) 15 | { 16 | task.wait(); 17 | } 18 | } 19 | 20 | template 21 | void add(T&& callback) 22 | { 23 | #if defined(_DEBUG) 24 | callback(); 25 | #else 26 | m_tasks.push_back(std::async(std::forward(callback))); 27 | #endif 28 | } 29 | 30 | void get() 31 | { 32 | auto tasks = std::move(m_tasks); 33 | 34 | for (auto&& task : tasks) 35 | { 36 | task.wait(); 37 | } 38 | 39 | for (auto&& task : tasks) 40 | { 41 | task.get(); 42 | } 43 | } 44 | 45 | private: 46 | 47 | std::vector> m_tasks; 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /cppwin32/text_writer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace cppwin32 12 | { 13 | inline std::string file_to_string(std::string const& filename) 14 | { 15 | std::ifstream file(filename, std::ios::binary); 16 | return static_cast(std::stringstream() << file.rdbuf()).str(); 17 | } 18 | 19 | template 20 | struct writer_base 21 | { 22 | writer_base(writer_base const&) = delete; 23 | writer_base& operator=(writer_base const&) = delete; 24 | 25 | writer_base() 26 | { 27 | m_first.reserve(16 * 1024); 28 | } 29 | 30 | template 31 | void write(std::string_view const& value, Args const&... args) 32 | { 33 | #if defined(_DEBUG) 34 | auto expected = count_placeholders(value); 35 | auto actual = sizeof...(Args); 36 | assert(expected == actual); 37 | #endif 38 | write_segment(value, args...); 39 | } 40 | 41 | template 42 | std::string write_temp(std::string_view const& value, Args const&... args) 43 | { 44 | #if defined(_DEBUG) 45 | bool restore_debug_trace = debug_trace; 46 | debug_trace = false; 47 | #endif 48 | auto const size = m_first.size(); 49 | 50 | assert(count_placeholders(value) == sizeof...(Args)); 51 | write_segment(value, args...); 52 | 53 | std::string result{ m_first.data() + size, m_first.size() - size }; 54 | m_first.resize(size); 55 | 56 | #if defined(_DEBUG) 57 | debug_trace = restore_debug_trace; 58 | #endif 59 | return result; 60 | } 61 | 62 | void write_impl(std::string_view const& value) 63 | { 64 | m_first.insert(m_first.end(), value.begin(), value.end()); 65 | 66 | #if defined(_DEBUG) 67 | if (debug_trace) 68 | { 69 | ::printf("%.*s", static_cast(value.size()), value.data()); 70 | } 71 | #endif 72 | } 73 | 74 | void write_impl(char const value) 75 | { 76 | m_first.push_back(value); 77 | 78 | #if defined(_DEBUG) 79 | if (debug_trace) 80 | { 81 | ::printf("%c", value); 82 | } 83 | #endif 84 | } 85 | 86 | void write(std::string_view const& value) 87 | { 88 | static_cast(this)->write_impl(value); 89 | } 90 | 91 | void write(char const value) 92 | { 93 | static_cast(this)->write_impl(value); 94 | } 95 | 96 | void write_code(std::string_view const& value) 97 | { 98 | write(value); 99 | } 100 | 101 | template >> 102 | void write(F const& f) 103 | { 104 | f(*static_cast(this)); 105 | } 106 | 107 | void write(int32_t const value) 108 | { 109 | write(std::to_string(value)); 110 | } 111 | 112 | void write(uint32_t const value) 113 | { 114 | write(std::to_string(value)); 115 | } 116 | 117 | void write(int64_t const value) 118 | { 119 | write(std::to_string(value)); 120 | } 121 | 122 | void write(uint64_t const value) 123 | { 124 | write(std::to_string(value)); 125 | } 126 | 127 | template 128 | void write_printf(char const* format, Args const&... args) 129 | { 130 | char buffer[128]; 131 | size_t const size = sprintf_s(buffer, format, args...); 132 | write(std::string_view{ buffer, size }); 133 | } 134 | 135 | template 136 | void write_each(List const& list, Args&&... args) 137 | { 138 | for (auto&& item : list) 139 | { 140 | F(*static_cast(this), item, std::forward(args)...); 141 | } 142 | } 143 | 144 | void swap() noexcept 145 | { 146 | std::swap(m_second, m_first); 147 | } 148 | 149 | void flush_to_console(bool to_stdout = true) noexcept 150 | { 151 | fprintf(to_stdout ? stdout : stderr, "%.*s", static_cast(m_first.size()), m_first.data()); 152 | fprintf(to_stdout ? stdout : stderr, "%.*s", static_cast(m_second.size()), m_second.data()); 153 | m_first.clear(); 154 | m_second.clear(); 155 | } 156 | 157 | void flush_to_file(std::string const& filename) 158 | { 159 | if (!file_equal(filename)) 160 | { 161 | std::ofstream file{ filename, std::ios::out | std::ios::binary }; 162 | file.write(m_first.data(), m_first.size()); 163 | file.write(m_second.data(), m_second.size()); 164 | } 165 | m_first.clear(); 166 | m_second.clear(); 167 | } 168 | 169 | void flush_to_file(std::filesystem::path const& filename) 170 | { 171 | flush_to_file(filename.string()); 172 | } 173 | 174 | std::string flush_to_string() 175 | { 176 | std::string result; 177 | result.reserve(m_first.size() + m_second.size()); 178 | result.assign(m_first.begin(), m_first.end()); 179 | result.append(m_second.begin(), m_second.end()); 180 | m_first.clear(); 181 | m_second.clear(); 182 | return result; 183 | } 184 | 185 | char back() 186 | { 187 | return m_first.empty() ? char{} : m_first.back(); 188 | } 189 | 190 | bool file_equal(std::string const& filename) const 191 | { 192 | if (!std::filesystem::exists(filename)) 193 | { 194 | return false; 195 | } 196 | 197 | auto file = file_to_string(filename); 198 | 199 | if (file.size() != m_first.size() + m_second.size()) 200 | { 201 | return false; 202 | } 203 | 204 | if (!std::equal(m_first.begin(), m_first.end(), file.begin(), file.begin() + m_first.size())) 205 | { 206 | return false; 207 | } 208 | 209 | return std::equal(m_second.begin(), m_second.end(), file.begin() + m_first.size(), file.end()); 210 | } 211 | 212 | #if defined(_DEBUG) 213 | bool debug_trace{}; 214 | #endif 215 | 216 | private: 217 | 218 | static constexpr uint32_t count_placeholders(std::string_view const& format) noexcept 219 | { 220 | uint32_t count{}; 221 | bool escape{}; 222 | 223 | for (auto c : format) 224 | { 225 | if (!escape) 226 | { 227 | if (c == '^') 228 | { 229 | escape = true; 230 | continue; 231 | } 232 | 233 | if (c == '%' || c == '@') 234 | { 235 | ++count; 236 | } 237 | } 238 | escape = false; 239 | } 240 | 241 | return count; 242 | } 243 | 244 | void write_segment(std::string_view const& value) 245 | { 246 | auto offset = value.find_first_of("^"); 247 | if (offset == std::string_view::npos) 248 | { 249 | write(value); 250 | return; 251 | } 252 | 253 | write(value.substr(0, offset)); 254 | 255 | assert(offset != value.size() - 1); 256 | 257 | write(value[offset + 1]); 258 | write_segment(value.substr(offset + 2)); 259 | } 260 | 261 | template 262 | void write_segment(std::string_view const& value, First const& first, Rest const&... rest) 263 | { 264 | auto offset = value.find_first_of("^%@"); 265 | assert(offset != std::string_view::npos); 266 | write(value.substr(0, offset)); 267 | 268 | if (value[offset] == '^') 269 | { 270 | assert(offset != value.size() - 1); 271 | 272 | write(value[offset + 1]); 273 | write_segment(value.substr(offset + 2), first, rest...); 274 | } 275 | else 276 | { 277 | if (value[offset] == '%') 278 | { 279 | static_cast(this)->write(first); 280 | } 281 | else 282 | { 283 | if constexpr (std::is_convertible_v) 284 | { 285 | static_cast(this)->write_code(first); 286 | } 287 | else 288 | { 289 | assert(false); // '@' placeholders are only for text. 290 | } 291 | } 292 | 293 | write_segment(value.substr(offset + 1), rest...); 294 | } 295 | } 296 | 297 | std::vector m_second; 298 | std::vector m_first; 299 | }; 300 | 301 | 302 | template 303 | struct indented_writer_base : writer_base 304 | { 305 | struct indent_guard 306 | { 307 | indent_guard(indented_writer_base& w, int32_t offset = 1) noexcept : m_writer(w), m_offset(offset) 308 | { 309 | m_writer.m_indent += m_offset; 310 | } 311 | 312 | ~indent_guard() noexcept 313 | { 314 | m_writer.m_indent -= m_offset; 315 | } 316 | 317 | private: 318 | indented_writer_base& m_writer; 319 | int32_t m_offset{}; 320 | }; 321 | 322 | 323 | void write_indent() 324 | { 325 | for (int32_t i = 0; i < m_indent; i++) 326 | { 327 | writer_base::write_impl(" "); 328 | } 329 | } 330 | 331 | void write_impl(std::string_view const& value) 332 | { 333 | std::string_view::size_type current_pos{ 0 }; 334 | auto on_new_line = writer_base::back() == '\n'; 335 | 336 | while (true) 337 | { 338 | const auto pos = value.find('\n', current_pos); 339 | 340 | if (pos == std::string_view::npos) 341 | { 342 | if (current_pos < value.size()) 343 | { 344 | if (on_new_line) 345 | { 346 | write_indent(); 347 | } 348 | 349 | writer_base::write_impl(value.substr(current_pos)); 350 | } 351 | 352 | return; 353 | } 354 | 355 | auto current_line = value.substr(current_pos, pos - current_pos + 1); 356 | auto empty_line = current_line[0] == '\n'; 357 | 358 | if (on_new_line && !empty_line) 359 | { 360 | write_indent(); 361 | } 362 | 363 | writer_base::write_impl(current_line); 364 | 365 | on_new_line = true; 366 | current_pos = pos + 1; 367 | } 368 | } 369 | 370 | void write_impl(char const value) 371 | { 372 | if (writer_base::back() == '\n' && value != '\n') 373 | { 374 | write_indent(); 375 | } 376 | 377 | writer_base::write_impl(value); 378 | } 379 | 380 | template 381 | std::string write_temp(std::string_view const& value, Args const& ... args) 382 | { 383 | auto restore_indent = m_indent; 384 | m_indent = 0; 385 | 386 | auto result = writer_base::write_temp(value, args...); 387 | 388 | m_indent = restore_indent; 389 | 390 | return result; 391 | } 392 | 393 | int32_t m_indent{}; 394 | }; 395 | 396 | 397 | template 398 | auto bind(Args&&... args) 399 | { 400 | return [&](auto& writer) 401 | { 402 | F(writer, args...); 403 | }; 404 | } 405 | 406 | template 407 | auto bind(F fwrite, Args const&... args) 408 | { 409 | return [&, fwrite](auto& writer) 410 | { 411 | fwrite(writer, args...); 412 | }; 413 | } 414 | 415 | template 416 | auto bind_each(List const& list, Args const&... args) 417 | { 418 | return [&](auto& writer) 419 | { 420 | for (auto&& item : list) 421 | { 422 | F(writer, item, args...); 423 | } 424 | }; 425 | } 426 | 427 | template 428 | auto bind_each(List const& list, Args const&... args) 429 | { 430 | return [&](auto& writer) 431 | { 432 | for (auto&& item : list) 433 | { 434 | writer.write(item, args...); 435 | } 436 | }; 437 | } 438 | 439 | template 440 | auto bind_each(F fwrite, List const& list, Args const&... args) 441 | { 442 | return [&, fwrite](auto& writer) 443 | { 444 | for (auto&& item : list) 445 | { 446 | fwrite(writer, item, args...); 447 | } 448 | }; 449 | } 450 | 451 | template 452 | auto bind_list(std::string_view const& delimiter, T const& list, Args const&... args) 453 | { 454 | return [&](auto& writer) 455 | { 456 | bool first{ true }; 457 | 458 | for (auto&& item : list) 459 | { 460 | if (first) 461 | { 462 | first = false; 463 | } 464 | else 465 | { 466 | writer.write(delimiter); 467 | } 468 | 469 | F(writer, item, args...); 470 | } 471 | }; 472 | } 473 | 474 | template 475 | auto bind_list(std::string_view const& delimiter, T const& list) 476 | { 477 | return [&](auto& writer) 478 | { 479 | bool first{ true }; 480 | 481 | for (auto&& item : list) 482 | { 483 | if (first) 484 | { 485 | first = false; 486 | } 487 | else 488 | { 489 | writer.write(delimiter); 490 | } 491 | 492 | writer.write(item); 493 | } 494 | }; 495 | } 496 | } 497 | -------------------------------------------------------------------------------- /cppwin32/type_dependency_graph.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "helpers.h" 6 | // For tracking "hard" dependencies between types that require a definition, not a forward declaration 7 | 8 | namespace cppwin32 9 | { 10 | using namespace winmd::reader; 11 | struct type_dependency_graph 12 | { 13 | type_dependency_graph() = default; 14 | explicit type_dependency_graph(std::string_view type_namespace) 15 | : type_namespace(type_namespace) 16 | {} 17 | 18 | enum class walk_state 19 | { 20 | not_started, 21 | walking, 22 | complete 23 | }; 24 | 25 | struct node 26 | { 27 | std::vector edges; 28 | walk_state state = walk_state::not_started; 29 | 30 | void add_edge(TypeDef const& edge) 31 | { 32 | if (std::find(edges.begin(), edges.end(), edge) == edges.end()) 33 | { 34 | edges.push_back(edge); 35 | } 36 | } 37 | }; 38 | 39 | std::map graph; 40 | using value_type = std::map::value_type; 41 | std::string_view type_namespace; 42 | 43 | template 44 | void walk_graph(Callback c) 45 | { 46 | auto eligible = [](value_type const& v) { return v.second.state == walk_state::not_started; }; 47 | for (auto it = std::find_if(graph.begin(), graph.end(), eligible) 48 | ; it != graph.end() 49 | ; it = std::find_if(graph.begin(), graph.end(), eligible)) 50 | { 51 | visit(*it, c); 52 | } 53 | } 54 | 55 | void reset_walk_state() 56 | { 57 | for (auto& value : graph) 58 | { 59 | value.second.state = walk_state::not_started; 60 | } 61 | } 62 | 63 | void add_struct(TypeDef const& type) 64 | { 65 | auto [it, inserted] = graph.insert({ type, {} }); 66 | if (!inserted) return; 67 | 68 | for (auto&& field : type.FieldList()) 69 | { 70 | auto const& signature = field.Signature(); 71 | if (auto const field_type = std::get_if>(&signature.Type().Type())) 72 | { 73 | if (signature.Type().ptr_count() == 0 || is_nested(*field_type)) 74 | { 75 | auto field_type_def = find(*field_type); 76 | if (field_type_def && get_category(field_type_def) == category::struct_type) 77 | { 78 | it->second.add_edge(field_type_def); 79 | add_struct(field_type_def); 80 | } 81 | } 82 | } 83 | } 84 | } 85 | 86 | void add_delegate(TypeDef const& type) 87 | { 88 | auto [it, inserted] = graph.insert({ type, {} }); 89 | if (!inserted) return; 90 | 91 | method_signature method_signature{ get_delegate_method(type) }; 92 | auto add_param = [this, current = it](TypeSig const& type) 93 | { 94 | auto index = std::get_if>(&type.Type()); 95 | if (index) 96 | { 97 | auto param_type_def = find(*index); 98 | if (param_type_def && get_category(param_type_def) == category::delegate_type) 99 | { 100 | if (type_namespace.empty() || type_namespace == param_type_def.TypeName()) 101 | { 102 | current->second.add_edge(param_type_def); 103 | add_delegate(param_type_def); 104 | } 105 | } 106 | } 107 | }; 108 | add_param(method_signature.return_signature().Type()); 109 | for (auto const& [param, param_sig] : method_signature.params()) 110 | { 111 | add_param(param_sig->Type()); 112 | } 113 | } 114 | 115 | void add_interface(TypeDef const& type) 116 | { 117 | auto [it, inserted] = graph.insert({ type, {} }); 118 | if (!inserted) return; 119 | 120 | auto const base_index = get_base_interface(type); 121 | if (base_index) 122 | { 123 | auto const base_type = find(base_index); 124 | if (base_type 125 | && (type_namespace.empty() || type_namespace == base_type.TypeNamespace())) 126 | { 127 | it->second.add_edge(base_type); 128 | add_interface(base_type); 129 | } 130 | } 131 | } 132 | 133 | private: 134 | 135 | template 136 | void visit(value_type& v, Callback c) 137 | { 138 | #ifdef _DEBUG 139 | auto type_name = v.first.TypeName(); 140 | #endif 141 | if (v.second.state == walk_state::complete) return; 142 | if (v.second.state == walk_state::walking) throw std::invalid_argument("Cyclic dependency graph encountered at type " + std::string(v.first.TypeNamespace()) + "." + std::string(v.first.TypeName())); 143 | 144 | v.second.state = walk_state::walking; 145 | for (auto&& edge : v.second.edges) 146 | { 147 | auto it = graph.find(edge); 148 | XLANG_ASSERT(it != graph.end()); 149 | visit(*it, c); 150 | } 151 | v.second.state = walk_state::complete; 152 | c(v.first); 153 | } 154 | }; 155 | } 156 | 157 | -------------------------------------------------------------------------------- /cppwin32/type_writers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "text_writer.h" 5 | #include "helpers.h" 6 | 7 | namespace cppwin32 8 | { 9 | using namespace winmd::reader; 10 | 11 | template 12 | auto get_impl_name(First const& first, Rest const&... rest) 13 | { 14 | std::string result; 15 | result.reserve(std::string_view(first).size() + ((1 + std::string_view(rest).size()), ...)); 16 | ((result += first), (((result += '_') += rest), ...)); 17 | std::transform(result.begin(), result.end(), result.begin(), [](char c) 18 | { 19 | return c == '.' ? '_' : c; 20 | }); 21 | return result; 22 | } 23 | 24 | struct writer : writer_base 25 | { 26 | using writer_base::write; 27 | 28 | struct depends_compare 29 | { 30 | bool operator()(TypeDef const& left, TypeDef const& right) const 31 | { 32 | return left.TypeName() < right.TypeName(); 33 | } 34 | bool operator()(TypeRef const& left, TypeRef const& right) const 35 | { 36 | return left.TypeName() < right.TypeName(); 37 | } 38 | }; 39 | 40 | std::string type_namespace; 41 | bool abi_types{}; 42 | bool full_namespace{}; 43 | bool consume_types{}; 44 | std::map> depends; 45 | std::map> extern_depends; 46 | 47 | template 48 | struct member_value_guard 49 | { 50 | writer* const owner; 51 | T writer::* const member; 52 | T const previous; 53 | explicit member_value_guard(writer* arg, T writer::* ptr, T value) : 54 | owner(arg), member(ptr), previous(std::exchange(owner->*member, value)) 55 | { 56 | } 57 | 58 | ~member_value_guard() 59 | { 60 | owner->*member = previous; 61 | } 62 | 63 | member_value_guard(member_value_guard const&) = delete; 64 | member_value_guard& operator=(member_value_guard const&) = delete; 65 | }; 66 | 67 | [[nodiscard]] auto push_abi_types(bool value) 68 | { 69 | return member_value_guard(this, &writer::abi_types, value); 70 | } 71 | 72 | [[nodiscard]] auto push_full_namespace(bool value) 73 | { 74 | return member_value_guard(this, &writer::full_namespace, value); 75 | } 76 | 77 | [[nodiscard]] auto push_consume_types(bool value) 78 | { 79 | return member_value_guard(this, &writer::consume_types, value); 80 | } 81 | 82 | void write_root_include(std::string_view const& include) 83 | { 84 | auto format = R"(#include %win32/%.h% 85 | )"; 86 | 87 | write(format, 88 | settings.brackets ? '<' : '\"', 89 | include, 90 | settings.brackets ? '>' : '\"'); 91 | } 92 | 93 | void add_depends(TypeDef const& type) 94 | { 95 | auto ns = type.TypeNamespace(); 96 | 97 | if (ns != type_namespace) 98 | { 99 | depends[ns].insert(type); 100 | } 101 | } 102 | 103 | void add_extern_depends(TypeRef const& type) 104 | { 105 | auto ns = type.TypeNamespace(); 106 | XLANG_ASSERT(ns != type_namespace); 107 | extern_depends[ns].insert(type); 108 | } 109 | 110 | void write_depends(std::string_view const& ns, char impl = 0) 111 | { 112 | if (impl) 113 | { 114 | write_root_include(write_temp("impl/%.%", ns, impl)); 115 | } 116 | else 117 | { 118 | write_root_include(ns); 119 | } 120 | } 121 | 122 | template 123 | void write_value(T value) 124 | { 125 | char buffer[128]; 126 | char* first = buffer; 127 | char* last = std::end(buffer); 128 | 129 | if constexpr (std::numeric_limits::is_integer) 130 | { 131 | int base = 10; 132 | if constexpr (!std::numeric_limits::is_signed) 133 | { 134 | *first++ = '0'; 135 | *first++ = 'x'; 136 | base = 16; 137 | } 138 | auto end = std::to_chars(first, last, value, base).ptr; 139 | write(std::string_view{ buffer, static_cast(end - buffer) }); 140 | } 141 | else 142 | { 143 | static_assert(std::is_same_v || std::is_same_v); 144 | *first++ = '0'; 145 | *first++ = 'x'; 146 | auto end = std::to_chars(first, last, value, std::chars_format::hex).ptr; 147 | // Put the leading '-' in front of '0x' 148 | if (*first == '-') 149 | { 150 | std::rotate(buffer, first, first + 1); 151 | } 152 | write(std::string_view{ buffer, static_cast(end - buffer) }); 153 | } 154 | } 155 | 156 | void write_code(std::string_view const& value) 157 | { 158 | for (auto&& c : value) 159 | { 160 | if (c == '.') 161 | { 162 | write("::"); 163 | } 164 | else 165 | { 166 | write(c); 167 | } 168 | } 169 | } 170 | 171 | void write(ConstantType type) 172 | { 173 | switch (type) 174 | { 175 | case ConstantType::UInt8: 176 | write("uint8_t"); 177 | break; 178 | case ConstantType::Int8: 179 | write("int8_t"); 180 | break; 181 | case ConstantType::UInt16: 182 | write("uint16_t"); 183 | break; 184 | case ConstantType::Int16: 185 | write("int16_t"); 186 | break; 187 | case ConstantType::UInt32: 188 | write("uint32_t"); 189 | break; 190 | case ConstantType::Int32: 191 | write("int32_t"); 192 | break; 193 | case ConstantType::UInt64: 194 | write("uint64_t"); 195 | break; 196 | case ConstantType::Int64: 197 | write("int64_t"); 198 | break; 199 | case ConstantType::Float32: 200 | write("float"); 201 | break; 202 | case ConstantType::Float64: 203 | write("double"); 204 | break; 205 | case ConstantType::String: 206 | write("wchar_t const*"); 207 | break; 208 | default: 209 | throw_invalid("Invalid ConstantType"); 210 | break; 211 | } 212 | } 213 | 214 | void write(Constant const& value) 215 | { 216 | switch (value.Type()) 217 | { 218 | case ConstantType::UInt8: 219 | write_value(value.ValueUInt8()); 220 | break; 221 | case ConstantType::Int8: 222 | write_value(value.ValueInt8()); 223 | break; 224 | case ConstantType::UInt16: 225 | write_value(value.ValueUInt16()); 226 | break; 227 | case ConstantType::Int16: 228 | write_value(value.ValueInt16()); 229 | break; 230 | case ConstantType::Int32: 231 | write_value(value.ValueInt32()); 232 | break; 233 | case ConstantType::UInt32: 234 | write_value(value.ValueUInt32()); 235 | break; 236 | case ConstantType::Int64: 237 | write_value(value.ValueInt64()); 238 | break; 239 | case ConstantType::UInt64: 240 | write_value(value.ValueUInt64()); 241 | break; 242 | case ConstantType::Float32: 243 | write_value(value.ValueFloat32()); 244 | break; 245 | case ConstantType::Float64: 246 | write_value(value.ValueFloat64()); 247 | break; 248 | case ConstantType::String: 249 | write(R"(L"%")", value.ValueString()); 250 | break; 251 | default: 252 | throw std::invalid_argument("Unexpected constant type"); 253 | } 254 | } 255 | 256 | void write(std::u16string_view const& str) 257 | { 258 | auto const data = reinterpret_cast(str.data()); 259 | auto const size = ::WideCharToMultiByte(CP_UTF8, 0, data, static_cast(str.size()), nullptr, 0, nullptr, nullptr); 260 | if (size == 0) 261 | { 262 | return; 263 | } 264 | std::string result(size, '?'); 265 | ::WideCharToMultiByte(CP_UTF8, 0, data, static_cast(str.size()), result.data(), size, nullptr, nullptr); 266 | write(result); 267 | } 268 | 269 | void write(TypeDef const& type) 270 | { 271 | add_depends(type); 272 | if (is_nested(type)) 273 | { 274 | write(type.TypeName()); 275 | } 276 | else 277 | { 278 | if (full_namespace) 279 | { 280 | write("win32::"); 281 | } 282 | write("@::%", type.TypeNamespace(), type.TypeName()); 283 | } 284 | } 285 | 286 | void write(TypeRef const& type) 287 | { 288 | if (type.TypeNamespace() == "System" && type.TypeName() == "Guid") 289 | { 290 | write("::win32::guid"); 291 | } 292 | else if (is_nested(type)) 293 | { 294 | write(type.TypeName()); 295 | } 296 | else 297 | { 298 | auto type_def = find(type); 299 | if (type_def) 300 | { 301 | write(type_def); 302 | return; 303 | } 304 | add_extern_depends(type); 305 | if (full_namespace) 306 | { 307 | write("win32::"); 308 | } 309 | write("@::%", type.TypeNamespace(), type.TypeName()); 310 | } 311 | } 312 | 313 | void write(coded_index const& type) 314 | { 315 | switch (type.type()) 316 | { 317 | case TypeDefOrRef::TypeDef: 318 | write(type.TypeDef()); 319 | break; 320 | case TypeDefOrRef::TypeRef: 321 | write(type.TypeRef()); 322 | break; 323 | default: 324 | throw std::invalid_argument("Unexpected TypeDefOrRef type"); 325 | } 326 | } 327 | 328 | void write(TypeSig const& signature) 329 | { 330 | call(signature.Type(), 331 | [&](ElementType type) 332 | { 333 | switch (type) 334 | { 335 | case ElementType::Boolean: 336 | write("bool"); 337 | break; 338 | case ElementType::I1: 339 | write("int8_t"); 340 | break; 341 | case ElementType::U1: 342 | write("uint8_t"); 343 | break; 344 | case ElementType::I2: 345 | write("int16_t"); 346 | break; 347 | case ElementType::U2: 348 | write("uint16_t"); 349 | break; 350 | case ElementType::I4: 351 | write("int32_t"); 352 | break; 353 | case ElementType::U4: 354 | write("uint32_t"); 355 | break; 356 | case ElementType::I8: 357 | write("int64_t"); 358 | break; 359 | case ElementType::U8: 360 | write("uint64_t"); 361 | break; 362 | case ElementType::R4: 363 | write("float"); 364 | break; 365 | case ElementType::R8: 366 | write("double"); 367 | break; 368 | case ElementType::U: 369 | write("size_t"); 370 | break; 371 | case ElementType::I: 372 | write("intptr_t"); 373 | break; 374 | case ElementType::Void: 375 | write("void"); 376 | break; 377 | default: 378 | throw std::invalid_argument("Invalid TypeSig type"); 379 | } 380 | for (int i = 0; i < signature.ptr_count(); ++i) 381 | { 382 | write('*'); 383 | } 384 | }, 385 | [&](coded_index const& type) 386 | { 387 | write(type); 388 | for (int i = 0; i < signature.ptr_count(); ++i) 389 | { 390 | write('*'); 391 | } 392 | if (signature.element_type() == ElementType::Class) 393 | { 394 | write('*'); 395 | } 396 | }, 397 | [&](auto&& type) 398 | { 399 | throw std::invalid_argument("Invalid TypeSig type"); 400 | }); 401 | } 402 | 403 | void write(RetTypeSig const& value) 404 | { 405 | if (value) 406 | { 407 | write(value.Type()); 408 | } 409 | else 410 | { 411 | write("void"); 412 | } 413 | } 414 | 415 | void save_header(char impl = 0) 416 | { 417 | auto filename{ settings.output_folder + "win32/" }; 418 | if (impl) 419 | { 420 | filename += "impl/"; 421 | } 422 | 423 | filename += type_namespace; 424 | 425 | if (impl) 426 | { 427 | filename += '.'; 428 | filename += impl; 429 | } 430 | 431 | filename += ".h"; 432 | flush_to_file(filename); 433 | } 434 | }; 435 | } -------------------------------------------------------------------------------- /cppwin32/version.aps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/cppwin32/8a6b2507734dd9e9892059b5794f35109688fc20/cppwin32/version.aps -------------------------------------------------------------------------------- /cppwin32/version.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #include "resource.h" 4 | 5 | #define APSTUDIO_READONLY_SYMBOLS 6 | ///////////////////////////////////////////////////////////////////////////// 7 | // 8 | // Generated from the TEXTINCLUDE 2 resource. 9 | // 10 | #include "winres.h" 11 | 12 | ///////////////////////////////////////////////////////////////////////////// 13 | #undef APSTUDIO_READONLY_SYMBOLS 14 | 15 | ///////////////////////////////////////////////////////////////////////////// 16 | // English (United States) resources 17 | 18 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 19 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 20 | #pragma code_page(1252) 21 | 22 | #ifdef APSTUDIO_INVOKED 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // 25 | // TEXTINCLUDE 26 | // 27 | 28 | 1 TEXTINCLUDE 29 | BEGIN 30 | "resource.h\0" 31 | END 32 | 33 | 2 TEXTINCLUDE 34 | BEGIN 35 | "#include ""winres.h""\r\n" 36 | "\0" 37 | END 38 | 39 | 3 TEXTINCLUDE 40 | BEGIN 41 | "\r\n" 42 | "\0" 43 | END 44 | 45 | #endif // APSTUDIO_INVOKED 46 | 47 | 48 | ///////////////////////////////////////////////////////////////////////////// 49 | // 50 | // Version 51 | // 52 | 53 | VS_VERSION_INFO VERSIONINFO 54 | FILEVERSION 0,0,0,1 55 | PRODUCTVERSION 0,0,0,1 56 | FILEFLAGSMASK 0x3fL 57 | #ifdef _DEBUG 58 | FILEFLAGS 0x1L 59 | #else 60 | FILEFLAGS 0x0L 61 | #endif 62 | FILEOS 0x40004L 63 | FILETYPE 0x1L 64 | FILESUBTYPE 0x0L 65 | BEGIN 66 | BLOCK "StringFileInfo" 67 | BEGIN 68 | BLOCK "040904b0" 69 | BEGIN 70 | VALUE "CompanyName", "Microsoft Corporation" 71 | VALUE "FileDescription", "C++/Win32" 72 | VALUE "FileVersion", "0.0.0.1" 73 | VALUE "InternalName", "cppwin32.exe" 74 | VALUE "LegalCopyright", "Microsoft Corporation. All rights reserved." 75 | VALUE "OriginalFilename", "cppwin32.exe" 76 | VALUE "ProductName", "C++/Win32" 77 | VALUE "ProductVersion", "0.0.0.1" 78 | END 79 | END 80 | BLOCK "VarFileInfo" 81 | BEGIN 82 | VALUE "Translation", 0x409, 1200 83 | END 84 | END 85 | 86 | #endif // English (United States) resources 87 | ///////////////////////////////////////////////////////////////////////////// 88 | 89 | 90 | 91 | #ifndef APSTUDIO_INVOKED 92 | ///////////////////////////////////////////////////////////////////////////// 93 | // 94 | // Generated from the TEXTINCLUDE 3 resource. 95 | // 96 | 97 | 98 | ///////////////////////////////////////////////////////////////////////////// 99 | #endif // not APSTUDIO_INVOKED 100 | 101 | -------------------------------------------------------------------------------- /cppwin32/winmd/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /cppwin32/winmd/impl/base.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(_WIN32) 4 | #include 5 | #include 6 | #include 7 | #else 8 | #include 9 | #include 10 | #include 11 | #include 12 | #endif 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #if defined(_DEBUG) 32 | #define XLANG_DEBUG 33 | #define XLANG_ASSERT assert 34 | #else 35 | #define XLANG_ASSERT(expression) ((void)0) 36 | #endif 37 | 38 | namespace winmd 39 | { 40 | using namespace std::literals; 41 | 42 | namespace impl 43 | { 44 | [[noreturn]] inline void throw_invalid(std::string const& message) 45 | { 46 | throw std::invalid_argument(message); 47 | } 48 | 49 | template 50 | [[noreturn]] inline void throw_invalid(std::string message, T const&... args) 51 | { 52 | (message.append(args), ...); 53 | throw std::invalid_argument(message); 54 | } 55 | 56 | template 57 | auto c_str(std::basic_string_view const& view) noexcept 58 | { 59 | if (*(view.data() + view.size())) 60 | { 61 | std::terminate(); 62 | } 63 | 64 | return view.data(); 65 | } 66 | 67 | inline bool starts_with(std::string_view const& value, std::string_view const& match) noexcept 68 | { 69 | return 0 == value.compare(0, match.size(), match); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /cppwin32/winmd/impl/winmd_reader/cache.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | struct cache 5 | { 6 | cache() = default; 7 | cache(cache const&) = delete; 8 | cache& operator=(cache const&) = delete; 9 | 10 | template 11 | explicit cache(C const& files) 12 | { 13 | for (auto&& file : files) 14 | { 15 | auto& db = m_databases.emplace_back(file, this); 16 | 17 | for (auto&& type : db.TypeDef) 18 | { 19 | if (type.Flags().value == 0 || is_nested(type)) 20 | { 21 | continue; 22 | } 23 | 24 | auto& ns = m_namespaces[type.TypeNamespace()]; 25 | ns.types.try_emplace(type.TypeName(), type); 26 | } 27 | 28 | for (auto&& row : db.NestedClass) 29 | { 30 | m_nested_types[row.EnclosingType()].push_back(row.NestedType()); 31 | } 32 | } 33 | 34 | for (auto&&[namespace_name, members] : m_namespaces) 35 | { 36 | for (auto&&[name, type] : members.types) 37 | { 38 | switch (get_category(type)) 39 | { 40 | case category::interface_type: 41 | members.interfaces.push_back(type); 42 | continue; 43 | case category::class_type: 44 | if (extends_type(type, "System"sv, "Attribute"sv)) 45 | { 46 | members.attributes.push_back(type); 47 | continue; 48 | } 49 | members.classes.push_back(type); 50 | continue; 51 | case category::enum_type: 52 | members.enums.push_back(type); 53 | continue; 54 | case category::struct_type: 55 | if (get_attribute(type, "Windows.Foundation.Metadata"sv, "ApiContractAttribute"sv)) 56 | { 57 | members.contracts.push_back(type); 58 | continue; 59 | } 60 | members.structs.push_back(type); 61 | continue; 62 | case category::delegate_type: 63 | members.delegates.push_back(type); 64 | continue; 65 | } 66 | } 67 | } 68 | } 69 | 70 | explicit cache(std::string const& file) : cache{ std::vector{ file } } 71 | { 72 | } 73 | 74 | TypeDef find(std::string_view const& type_namespace, std::string_view const& type_name) const noexcept 75 | { 76 | auto ns = m_namespaces.find(type_namespace); 77 | 78 | if (ns == m_namespaces.end()) 79 | { 80 | return {}; 81 | } 82 | 83 | auto type = ns->second.types.find(type_name); 84 | 85 | if (type == ns->second.types.end()) 86 | { 87 | return {}; 88 | } 89 | 90 | return type->second; 91 | } 92 | 93 | TypeDef find(std::string_view const& type_string) const 94 | { 95 | auto pos = type_string.rfind('.'); 96 | 97 | if (pos == std::string_view::npos) 98 | { 99 | impl::throw_invalid("Type '", type_string, "' is missing a namespace qualifier"); 100 | } 101 | 102 | return find(type_string.substr(0, pos), type_string.substr(pos + 1, type_string.size())); 103 | } 104 | 105 | TypeDef find_required(std::string_view const& type_namespace, std::string_view const& type_name) const 106 | { 107 | auto definition = find(type_namespace, type_name); 108 | 109 | if (!definition) 110 | { 111 | impl::throw_invalid("Type '", type_namespace, ".", type_name, "' could not be found"); 112 | } 113 | 114 | return definition; 115 | } 116 | 117 | TypeDef find_required(std::string_view const& type_string) const 118 | { 119 | auto pos = type_string.rfind('.'); 120 | 121 | if (pos == std::string_view::npos) 122 | { 123 | impl::throw_invalid("Type '", type_string, "' is missing a namespace qualifier"); 124 | } 125 | 126 | return find_required(type_string.substr(0, pos), type_string.substr(pos + 1, type_string.size())); 127 | } 128 | 129 | auto const& databases() const noexcept 130 | { 131 | return m_databases; 132 | } 133 | 134 | auto const& namespaces() const noexcept 135 | { 136 | return m_namespaces; 137 | } 138 | 139 | void remove_type(std::string_view const& ns, std::string_view const& name) 140 | { 141 | auto m = m_namespaces.find(ns); 142 | if (m == m_namespaces.end()) 143 | { 144 | return; 145 | } 146 | auto& members = m->second; 147 | 148 | auto remove = [&](auto&& collection, auto&& name) 149 | { 150 | auto pos = std::find_if(collection.begin(), collection.end(), [&](auto&& type) 151 | { 152 | return type.TypeName() == name; 153 | }); 154 | 155 | if (pos != collection.end()) 156 | { 157 | collection.erase(pos); 158 | } 159 | }; 160 | 161 | remove(members.interfaces, name); 162 | remove(members.classes, name); 163 | remove(members.enums, name); 164 | remove(members.structs, name); 165 | remove(members.delegates, name); 166 | } 167 | 168 | std::vector const& nested_types(TypeDef const& enclosing_type) const 169 | { 170 | auto it = m_nested_types.find(enclosing_type); 171 | if (it != m_nested_types.end()) 172 | { 173 | return it->second; 174 | } 175 | else 176 | { 177 | static const std::vector empty; 178 | return empty; 179 | } 180 | } 181 | 182 | struct namespace_members 183 | { 184 | std::map types; 185 | std::vector interfaces; 186 | std::vector classes; 187 | std::vector enums; 188 | std::vector structs; 189 | std::vector delegates; 190 | std::vector attributes; 191 | std::vector contracts; 192 | }; 193 | 194 | using namespace_type = std::pair const&; 195 | 196 | private: 197 | 198 | std::list m_databases; 199 | std::map m_namespaces; 200 | std::map> m_nested_types; 201 | }; 202 | } -------------------------------------------------------------------------------- /cppwin32/winmd/impl/winmd_reader/custom_attribute.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | inline auto CustomAttribute::TypeNamespaceAndName() const 5 | { 6 | if (Type().type() == CustomAttributeType::MemberRef) 7 | { 8 | auto const& member_parent = Type().MemberRef().Class(); 9 | switch (member_parent.type()) 10 | { 11 | case MemberRefParent::TypeDef: 12 | { 13 | auto const& def = member_parent.TypeDef(); 14 | return std::pair{ def.TypeNamespace(), def.TypeName() }; 15 | } 16 | 17 | case MemberRefParent::TypeRef: 18 | { 19 | auto const& ref = member_parent.TypeRef(); 20 | return std::pair{ ref.TypeNamespace(), ref.TypeName() }; 21 | } 22 | default: 23 | impl::throw_invalid("A CustomAttribute MemberRef should only be a TypeDef or TypeRef"); 24 | } 25 | } 26 | else 27 | { 28 | auto const& def = Type().MethodDef().Parent(); 29 | return std::pair{ def.TypeNamespace(), def.TypeName() }; 30 | } 31 | } 32 | 33 | struct ElemSig 34 | { 35 | struct SystemType 36 | { 37 | std::string_view name; 38 | }; 39 | 40 | struct EnumValue 41 | { 42 | EnumDefinition type; 43 | using value_type = std::variant; 44 | value_type value; 45 | 46 | bool equals_enumerator(std::string_view const& name) const 47 | { 48 | auto field = type.get_enumerator(name); 49 | auto constant_value = std::visit([](auto&& v) { return Constant::constant_type{ v }; }, value); 50 | return field.Constant().Value() == constant_value; 51 | } 52 | }; 53 | 54 | using value_type = std::variant; 55 | 56 | ElemSig(database const& db, ParamSig const& param, byte_view& data) 57 | : value{ read_element(db, param, data) } 58 | { 59 | } 60 | 61 | ElemSig(SystemType type) 62 | : value(type) 63 | { 64 | } 65 | 66 | ElemSig(EnumDefinition const& enum_def, byte_view& data) 67 | : value{ EnumValue{enum_def, read_enum(enum_def.m_underlying_type, data) } } 68 | { 69 | } 70 | 71 | ElemSig(ElementType type, byte_view& data) 72 | : value{ read_primitive(type, data) } 73 | { 74 | } 75 | 76 | static value_type read_element(database const& db, ParamSig const& param, byte_view& data) 77 | { 78 | auto const& type = param.Type().Type(); 79 | if (auto element_type = std::get_if(&type)) 80 | { 81 | return read_primitive(*element_type, data); 82 | } 83 | else if (auto type_index = std::get_if>(&type)) 84 | { 85 | if ((type_index->type() == TypeDefOrRef::TypeRef && type_index->TypeRef().TypeNamespace() == "System" && type_index->TypeRef().TypeName() == "Type") || 86 | (type_index->type() == TypeDefOrRef::TypeDef && type_index->TypeDef().TypeNamespace() == "System" && type_index->TypeDef().TypeName() == "Type")) 87 | { 88 | return SystemType{ read(data) }; 89 | } 90 | else 91 | { 92 | // Should be an enum. Resolve it. 93 | auto resolve_type = [&db, &type_index]() -> TypeDef 94 | { 95 | if (type_index->type() == TypeDefOrRef::TypeDef) 96 | { 97 | return type_index->TypeDef(); 98 | } 99 | auto const& typeref = type_index->TypeRef(); 100 | return db.get_cache().find_required(typeref.TypeNamespace(), typeref.TypeName()); 101 | }; 102 | TypeDef const& enum_type = resolve_type(); 103 | if (!enum_type.is_enum()) 104 | { 105 | impl::throw_invalid("CustomAttribute params that are TypeDefOrRef must be an enum or System.Type"); 106 | } 107 | 108 | auto const& enum_def = enum_type.get_enum_definition(); 109 | return EnumValue{ enum_def, read_enum(enum_def.m_underlying_type, data) }; 110 | } 111 | } 112 | impl::throw_invalid("Custom attribute params must be primitives, enums, or System.Type"); 113 | } 114 | 115 | static value_type read_primitive(ElementType type, byte_view& data) 116 | { 117 | switch (type) 118 | { 119 | case ElementType::Boolean: 120 | return read(data); 121 | 122 | case ElementType::Char: 123 | return read(data); 124 | 125 | case ElementType::I1: 126 | return read(data); 127 | 128 | case ElementType::U1: 129 | return read(data); 130 | 131 | case ElementType::I2: 132 | return read(data); 133 | 134 | case ElementType::U2: 135 | return read(data); 136 | 137 | case ElementType::I4: 138 | return read(data); 139 | 140 | case ElementType::U4: 141 | return read(data); 142 | 143 | case ElementType::I8: 144 | return read(data); 145 | 146 | case ElementType::U8: 147 | return read(data); 148 | 149 | case ElementType::R4: 150 | return read(data); 151 | 152 | case ElementType::R8: 153 | return read(data); 154 | 155 | case ElementType::String: 156 | return read(data); 157 | 158 | default: 159 | impl::throw_invalid("Non-primitive type encountered"); 160 | } 161 | } 162 | 163 | static EnumValue::value_type read_enum(ElementType type, byte_view& data) 164 | { 165 | switch (type) 166 | { 167 | case ElementType::Boolean: 168 | return read(data); 169 | 170 | case ElementType::Char: 171 | return read(data); 172 | 173 | case ElementType::I1: 174 | return read(data); 175 | 176 | case ElementType::U1: 177 | return read(data); 178 | 179 | case ElementType::I2: 180 | return read(data); 181 | 182 | case ElementType::U2: 183 | return read(data); 184 | 185 | case ElementType::I4: 186 | return read(data); 187 | 188 | case ElementType::U4: 189 | return read(data); 190 | 191 | case ElementType::I8: 192 | return read(data); 193 | 194 | case ElementType::U8: 195 | return read(data); 196 | 197 | default: 198 | impl::throw_invalid("Invalid underling enum type encountered"); 199 | } 200 | } 201 | 202 | value_type value; 203 | }; 204 | 205 | struct FixedArgSig 206 | { 207 | using value_type = std::variant>; 208 | 209 | FixedArgSig(database const& db, ParamSig const& ctor_param, byte_view& data) 210 | : value{ read_arg(db, ctor_param, data) } 211 | {} 212 | 213 | FixedArgSig(ElemSig::SystemType type) 214 | : value{ ElemSig{type} } 215 | {} 216 | 217 | FixedArgSig(EnumDefinition const& enum_def, byte_view& data) 218 | : value{ ElemSig{ enum_def, data } } 219 | {} 220 | 221 | FixedArgSig(ElementType type, bool is_array, byte_view& data) 222 | : value{ read_arg(type, is_array, data) } 223 | {} 224 | 225 | static value_type read_arg(database const& db, ParamSig const& ctor_param, byte_view& data) 226 | { 227 | auto const& type_sig = ctor_param.Type(); 228 | if (type_sig.is_szarray()) 229 | { 230 | std::vector elems; 231 | auto const num_elements = read(data); 232 | if (num_elements != 0xffffffff) 233 | { 234 | if (num_elements > data.size()) 235 | { 236 | impl::throw_invalid("Invalid blob array size"); 237 | } 238 | elems.reserve(num_elements); 239 | for (uint32_t i = 0; i < num_elements; ++i) 240 | { 241 | elems.emplace_back(db, ctor_param, data); 242 | } 243 | } 244 | return elems; 245 | } 246 | else 247 | { 248 | return ElemSig{ db, ctor_param, data }; 249 | } 250 | } 251 | 252 | static value_type read_arg(ElementType type, bool is_array, byte_view& data) 253 | { 254 | if (is_array) 255 | { 256 | std::vector elems; 257 | auto const num_elements = read(data); 258 | if (num_elements != 0xffffffff) 259 | { 260 | if (num_elements > data.size()) 261 | { 262 | impl::throw_invalid("Invalid blob array size"); 263 | } 264 | elems.reserve(num_elements); 265 | for (uint32_t i = 0; i < num_elements; ++i) 266 | { 267 | elems.emplace_back(type, data); 268 | } 269 | } 270 | return elems; 271 | } 272 | else 273 | { 274 | return ElemSig{ type, data }; 275 | } 276 | } 277 | 278 | value_type value; 279 | }; 280 | 281 | struct NamedArgSig 282 | { 283 | NamedArgSig(database const& db, byte_view& data) 284 | : value{ parse_value(db, data) } 285 | {} 286 | 287 | std::string_view name; 288 | FixedArgSig value; 289 | 290 | private: 291 | FixedArgSig parse_value(database const& db, byte_view& data) 292 | { 293 | auto const field_or_prop = read(data); 294 | if (field_or_prop != ElementType::Field && field_or_prop != ElementType::Property) 295 | { 296 | impl::throw_invalid("NamedArg must be either FIELD or PROPERTY"); 297 | } 298 | 299 | auto type = read(data); 300 | switch (type) 301 | { 302 | case ElementType::Type: 303 | name = read(data); 304 | return FixedArgSig{ ElemSig::SystemType{read(data)} }; 305 | 306 | case ElementType::Enum: 307 | { 308 | auto type_string = read(data); 309 | name = read(data); 310 | auto type_def = db.get_cache().find(type_string); 311 | if (!type_def) 312 | { 313 | impl::throw_invalid("CustomAttribute named param referenced unresolved enum type"); 314 | } 315 | if (!type_def.is_enum()) 316 | { 317 | impl::throw_invalid("CustomAttribute named param referenced non-enum type"); 318 | } 319 | 320 | return FixedArgSig{ type_def.get_enum_definition(), data }; 321 | } 322 | 323 | default: 324 | { 325 | bool const is_array = (type == ElementType::SZArray); 326 | if (is_array) 327 | { 328 | type = read(data); 329 | } 330 | if (type < ElementType::Boolean || ElementType::String < type) 331 | { 332 | impl::throw_invalid("CustomAttribute named param must be a primitive, System.Type, or an Enum"); 333 | } 334 | name = read(data); 335 | return FixedArgSig{ type, is_array, data }; 336 | } 337 | } 338 | } 339 | }; 340 | 341 | struct CustomAttributeSig 342 | { 343 | CustomAttributeSig(table_base const* table, byte_view& data, MethodDefSig const& ctor) 344 | { 345 | database const& db = table->get_database(); 346 | auto const prolog = read(data); 347 | if (prolog != 0x0001) 348 | { 349 | impl::throw_invalid("CustomAttribute blobs must start with prolog of 0x0001"); 350 | } 351 | 352 | for (auto const& param : ctor.Params()) 353 | { 354 | m_fixed_args.push_back(FixedArgSig{ db, param, data }); 355 | } 356 | 357 | const auto num_named_args = read(data); 358 | if (num_named_args > data.size()) 359 | { 360 | impl::throw_invalid("Invalid blob array size"); 361 | } 362 | m_named_args.reserve(num_named_args); 363 | 364 | for (uint16_t i = 0; i < num_named_args; ++i) 365 | { 366 | m_named_args.emplace_back(db, data); 367 | } 368 | } 369 | 370 | std::vector const& FixedArgs() const noexcept { return m_fixed_args; } 371 | std::vector const& NamedArgs() const noexcept { return m_named_args; } 372 | 373 | private: 374 | std::vector m_fixed_args; 375 | std::vector m_named_args; 376 | }; 377 | 378 | inline auto CustomAttribute::Value() const 379 | { 380 | auto const ctor = Type(); 381 | MethodDefSig const& method_sig = ctor.type() == CustomAttributeType::MemberRef ? ctor.MemberRef().MethodSignature() : ctor.MethodDef().Signature(); 382 | auto cursor = get_blob(2); 383 | return CustomAttributeSig{ get_table(), cursor, method_sig }; 384 | } 385 | } 386 | -------------------------------------------------------------------------------- /cppwin32/winmd/impl/winmd_reader/enum.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | template 5 | struct coded_index_bits : std::integral_constant {}; 6 | 7 | template 8 | inline constexpr uint32_t coded_index_bits_v = coded_index_bits::value; 9 | 10 | enum class TypeDefOrRef : uint32_t 11 | { 12 | TypeDef, 13 | TypeRef, 14 | TypeSpec, 15 | }; 16 | template <> 17 | struct coded_index_bits : std::integral_constant {}; 18 | 19 | enum class HasConstant : uint32_t 20 | { 21 | Field, 22 | Param, 23 | Property, 24 | }; 25 | template <> 26 | struct coded_index_bits : std::integral_constant {}; 27 | 28 | enum class HasCustomAttribute : uint32_t 29 | { 30 | MethodDef, 31 | Field, 32 | TypeRef, 33 | TypeDef, 34 | Param, 35 | InterfaceImpl, 36 | MemberRef, 37 | Module, 38 | Permission, 39 | Property, 40 | Event, 41 | StandAloneSig, 42 | ModuleRef, 43 | TypeSpec, 44 | Assembly, 45 | AssemblyRef, 46 | File, 47 | ExportedType, 48 | ManifestResource, 49 | GenericParam, 50 | GenericParamConstraint, 51 | MethodSpec, 52 | }; 53 | template <> 54 | struct coded_index_bits : std::integral_constant {}; 55 | 56 | enum class HasFieldMarshal : uint32_t 57 | { 58 | Field, 59 | Param, 60 | }; 61 | template <> 62 | struct coded_index_bits : std::integral_constant {}; 63 | 64 | enum class HasDeclSecurity : uint32_t 65 | { 66 | TypeDef, 67 | MethodDef, 68 | Assembly, 69 | }; 70 | template <> 71 | struct coded_index_bits : std::integral_constant {}; 72 | 73 | enum class MemberRefParent : uint32_t 74 | { 75 | TypeDef, 76 | TypeRef, 77 | ModuleRef, 78 | MethodDef, 79 | TypeSpec, 80 | }; 81 | template <> 82 | struct coded_index_bits : std::integral_constant {}; 83 | 84 | enum class HasSemantics : uint32_t 85 | { 86 | Event, 87 | Property, 88 | }; 89 | template <> 90 | struct coded_index_bits : std::integral_constant {}; 91 | 92 | enum class MethodDefOrRef : uint32_t 93 | { 94 | MethodDef, 95 | MemberRef, 96 | }; 97 | template <> 98 | struct coded_index_bits : std::integral_constant {}; 99 | 100 | enum class MemberForwarded : uint32_t 101 | { 102 | Field, 103 | MethodDef, 104 | }; 105 | template <> 106 | struct coded_index_bits : std::integral_constant {}; 107 | 108 | enum class Implementation : uint32_t 109 | { 110 | File, 111 | AssemblyRef, 112 | ExportedType, 113 | }; 114 | template <> 115 | struct coded_index_bits : std::integral_constant {}; 116 | 117 | enum class CustomAttributeType : uint32_t 118 | { 119 | MethodDef = 2, 120 | MemberRef, 121 | }; 122 | template <> 123 | struct coded_index_bits : std::integral_constant {}; 124 | 125 | enum class ResolutionScope : uint32_t 126 | { 127 | Module, 128 | ModuleRef, 129 | AssemblyRef, 130 | TypeRef, 131 | }; 132 | template <> 133 | struct coded_index_bits : std::integral_constant {}; 134 | 135 | enum class TypeOrMethodDef : uint32_t 136 | { 137 | TypeDef, 138 | MethodDef, 139 | }; 140 | template <> 141 | struct coded_index_bits : std::integral_constant {}; 142 | 143 | enum class MemberAccess : uint16_t 144 | { 145 | CompilerControlled = 0x0000, // Member not referenceable 146 | Private = 0x0001, 147 | FamAndAssem = 0x0002, // Accessible by subtypes only in this Assembly 148 | Assembly = 0x0003, // Accessible by anyone in this Assembly 149 | Family = 0x0004, // aka Protected 150 | FamOrAssem = 0x0005, // Accessible by subtypes anywhere, plus anyone in this Assembly 151 | Public = 0x0006, 152 | }; 153 | 154 | enum class TypeVisibility : uint32_t 155 | { 156 | NotPublic = 0x00000000, 157 | Public = 0x00000001, 158 | NestedPublic = 0x00000002, 159 | NestedPrivate = 0x00000003, 160 | NestedFamily = 0x00000004, 161 | NestedAssembly = 0x00000005, 162 | NestedFamANDAssem = 0x00000006, 163 | NestedFamORAssem = 0x00000007, 164 | }; 165 | 166 | enum class TypeLayout : uint32_t 167 | { 168 | AutoLayout = 0x00000000, 169 | SequentialLayout = 0x00000008, 170 | ExplicitLayout = 0x00000010, 171 | }; 172 | 173 | enum class TypeSemantics : uint32_t 174 | { 175 | Class = 0x00000000, 176 | Interface = 0x00000020, 177 | }; 178 | 179 | enum class StringFormat : uint32_t 180 | { 181 | AnsiClass = 0x00000000, 182 | UnicodeClass = 0x00010000, 183 | AutoClass = 0x00020000, 184 | CustomFormatClass = 0x00030000, 185 | CustomFormatMask = 0x00C00000, 186 | }; 187 | 188 | enum class CodeType : uint16_t 189 | { 190 | IL = 0x0000, // Method impl is CIL 191 | Native = 0x0001, // Method impl is native 192 | OPTIL = 0x0002, // Reserved: shall be zero in conforming implementations 193 | Runtime = 0x0003, // Method impl is provided by the runtime 194 | }; 195 | 196 | enum class Managed : uint16_t 197 | { 198 | Unmanaged = 0x0004, 199 | Managed = 0x0000, 200 | }; 201 | 202 | enum class VtableLayout : uint16_t 203 | { 204 | ReuseSlot = 0x0000, // Method reuses existing slot in a vtable 205 | NewSlot = 0x0100, // Method always gets a new slot in the vtable 206 | }; 207 | 208 | enum class GenericParamVariance : uint16_t 209 | { 210 | None = 0x0000, 211 | Covariant = 0x0001, 212 | Contravariant = 0x0002 213 | }; 214 | 215 | enum class GenericParamSpecialConstraint : uint16_t 216 | { 217 | ReferenceTypeConstraint = 0x0004, 218 | NotNullableValueTypeConstraint = 0x0008, 219 | DefaultConstructorConstraint = 0x0010 220 | }; 221 | 222 | enum class ConstantType : uint16_t 223 | { 224 | Boolean = 0x02, 225 | Char = 0x03, 226 | Int8 = 0x04, 227 | UInt8 = 0x05, 228 | Int16 = 0x06, 229 | UInt16 = 0x07, 230 | Int32 = 0x08, 231 | UInt32 = 0x09, 232 | Int64 = 0x0a, 233 | UInt64 = 0x0b, 234 | Float32 = 0x0c, 235 | Float64 = 0x0d, 236 | String = 0x0e, 237 | Class = 0x12 238 | }; 239 | 240 | enum class ElementType : uint8_t 241 | { 242 | End = 0x00, // Sentinel value 243 | 244 | Void = 0x01, 245 | Boolean = 0x02, 246 | Char = 0x03, 247 | I1 = 0x04, 248 | U1 = 0x05, 249 | I2 = 0x06, 250 | U2 = 0x07, 251 | I4 = 0x08, 252 | U4 = 0x09, 253 | I8 = 0x0a, 254 | U8 = 0x0b, 255 | R4 = 0x0c, 256 | R8 = 0x0d, 257 | String = 0x0e, 258 | 259 | Ptr = 0x0f, // Followed by TypeSig 260 | ByRef = 0x10, // Followed by TypeSig 261 | ValueType = 0x11, // Followed by TypeDef or TypeRef 262 | Class = 0x12, // Followed by TypeDef or TypeRef 263 | Var = 0x13, // Generic parameter in a type definition, represented as unsigned integer 264 | Array = 0x14, 265 | GenericInst = 0x15, 266 | TypedByRef = 0x16, 267 | 268 | I = 0x18, // System.IntPtr 269 | U = 0x19, // System.UIntPtr 270 | 271 | FnPtr = 0x1b, // Followed by full method signature 272 | Object = 0x1c, // System.Object 273 | SZArray = 0x1d, 274 | MVar = 0x1e, // Generic parameter in a method definition, represented as unsigned integer 275 | CModReqd = 0x1f, // Required modifier, followed by a TypeDef or TypeRef 276 | CModOpt = 0x20, // Optional modifier, followed by a TypeDef or TypeRef 277 | Internal = 0x21, 278 | 279 | Modifier = 0x40, // Or'd with folowing element types 280 | Sentinel = 0x41, // Sentinel for vararg method signature 281 | 282 | Pinned = 0x45, 283 | 284 | Type = 0x50, // System.Type 285 | TaggedObject = 0x51, // Boxed object (in custom attributes) 286 | Field = 0x53, // Custom attribute field 287 | Property = 0x54, // Custom attribute property 288 | Enum = 0x55, // Custom attribute enum 289 | }; 290 | 291 | enum class CallingConvention : uint8_t 292 | { 293 | Default = 0x00, 294 | VarArg = 0x05, 295 | Field = 0x06, 296 | LocalSig = 0x07, 297 | Property = 0x08, 298 | GenericInst = 0x10, 299 | Mask = 0x0f, 300 | 301 | HasThis = 0x20, 302 | ExplicitThis = 0x40, 303 | Generic = 0x10, 304 | }; 305 | 306 | enum class AssemblyHashAlgorithm : uint32_t 307 | { 308 | None = 0x0000, 309 | Reserved_MD5 = 0x8003, 310 | SHA1 = 0x8004, 311 | }; 312 | 313 | enum class AssemblyFlags : uint32_t 314 | { 315 | PublicKey = 0x0001, // The assembly reference holds the full (unhashed) public key 316 | Retargetable = 0x0100, 317 | WindowsRuntime = 0x0200, 318 | DisableJITcompileOptimizer = 0x4000, 319 | EnableJITcompileTracking = 0x8000, 320 | }; 321 | 322 | template 323 | constexpr inline T enum_mask(T value, T mask) noexcept 324 | { 325 | static_assert(std::is_enum_v); 326 | using val = std::underlying_type_t; 327 | return static_cast(static_cast(value) & static_cast(mask)); 328 | } 329 | } 330 | -------------------------------------------------------------------------------- /cppwin32/winmd/impl/winmd_reader/enum_traits.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | struct Module; 5 | struct TypeRef; 6 | struct TypeDef; 7 | struct Field; 8 | struct MethodDef; 9 | struct Param; 10 | struct InterfaceImpl; 11 | struct MemberRef; 12 | struct Constant; 13 | struct CustomAttribute; 14 | struct FieldMarshal; 15 | struct DeclSecurity; 16 | struct ClassLayout; 17 | struct FieldLayout; 18 | struct StandAloneSig; 19 | struct EventMap; 20 | struct Event; 21 | struct PropertyMap; 22 | struct Property; 23 | struct MethodSemantics; 24 | struct MethodImpl; 25 | struct ModuleRef; 26 | struct TypeSpec; 27 | struct ImplMap; 28 | struct FieldRVA; 29 | struct Assembly; 30 | struct AssemblyProcessor; 31 | struct AssemblyOS; 32 | struct AssemblyRef; 33 | struct AssemblyRefProcessor; 34 | struct AssemblyRefOS; 35 | struct File; 36 | struct ExportedType; 37 | struct ManifestResource; 38 | struct NestedClass; 39 | struct GenericParam; 40 | struct MethodSpec; 41 | struct GenericParamConstraint; 42 | 43 | 44 | template 45 | struct index_tag; 46 | 47 | template 48 | inline constexpr auto index_tag_v = index_tag::value; 49 | 50 | template<> 51 | struct index_tag : std::integral_constant {}; 52 | template<> 53 | struct index_tag : std::integral_constant {}; 54 | template<> 55 | struct index_tag : std::integral_constant {}; 56 | 57 | template<> 58 | struct index_tag : std::integral_constant {}; 59 | template<> 60 | struct index_tag : std::integral_constant {}; 61 | template<> 62 | struct index_tag : std::integral_constant {}; 63 | 64 | template<> 65 | struct index_tag : std::integral_constant {}; 66 | template<> 67 | struct index_tag : std::integral_constant {}; 68 | template<> 69 | struct index_tag : std::integral_constant {}; 70 | template<> 71 | struct index_tag : std::integral_constant {}; 72 | template<> 73 | struct index_tag : std::integral_constant {}; 74 | template<> 75 | struct index_tag : std::integral_constant {}; 76 | template<> 77 | struct index_tag : std::integral_constant {}; 78 | template<> 79 | struct index_tag : std::integral_constant {}; 80 | template<> 81 | struct index_tag : std::integral_constant {}; 82 | template<> 83 | struct index_tag : std::integral_constant {}; 84 | template<> 85 | struct index_tag : std::integral_constant {}; 86 | template<> 87 | struct index_tag : std::integral_constant {}; 88 | template<> 89 | struct index_tag : std::integral_constant {}; 90 | template<> 91 | struct index_tag : std::integral_constant {}; 92 | template<> 93 | struct index_tag : std::integral_constant {}; 94 | template<> 95 | struct index_tag : std::integral_constant {}; 96 | template<> 97 | struct index_tag : std::integral_constant {}; 98 | template<> 99 | struct index_tag : std::integral_constant {}; 100 | template<> 101 | struct index_tag : std::integral_constant {}; 102 | template<> 103 | struct index_tag : std::integral_constant {}; 104 | template<> 105 | struct index_tag : std::integral_constant {}; 106 | 107 | template<> 108 | struct index_tag : std::integral_constant {}; 109 | template<> 110 | struct index_tag : std::integral_constant {}; 111 | 112 | template<> 113 | struct index_tag : std::integral_constant {}; 114 | template<> 115 | struct index_tag : std::integral_constant {}; 116 | template<> 117 | struct index_tag : std::integral_constant {}; 118 | 119 | template<> 120 | struct index_tag : std::integral_constant {}; 121 | template<> 122 | struct index_tag : std::integral_constant {}; 123 | template<> 124 | struct index_tag : std::integral_constant {}; 125 | template<> 126 | struct index_tag : std::integral_constant {}; 127 | template<> 128 | struct index_tag : std::integral_constant {}; 129 | 130 | template<> 131 | struct index_tag : std::integral_constant {}; 132 | template<> 133 | struct index_tag : std::integral_constant {}; 134 | 135 | template<> 136 | struct index_tag : std::integral_constant {}; 137 | template<> 138 | struct index_tag : std::integral_constant {}; 139 | 140 | template<> 141 | struct index_tag : std::integral_constant {}; 142 | template<> 143 | struct index_tag : std::integral_constant {}; 144 | 145 | template<> 146 | struct index_tag : std::integral_constant {}; 147 | template<> 148 | struct index_tag : std::integral_constant {}; 149 | template<> 150 | struct index_tag : std::integral_constant {}; 151 | 152 | template<> 153 | struct index_tag : std::integral_constant {}; 154 | template<> 155 | struct index_tag : std::integral_constant {}; 156 | 157 | template<> 158 | struct index_tag : std::integral_constant {}; 159 | template<> 160 | struct index_tag : std::integral_constant {}; 161 | template<> 162 | struct index_tag : std::integral_constant {}; 163 | template<> 164 | struct index_tag : std::integral_constant {}; 165 | 166 | template<> 167 | struct index_tag : std::integral_constant {}; 168 | template<> 169 | struct index_tag : std::integral_constant {}; 170 | } 171 | -------------------------------------------------------------------------------- /cppwin32/winmd/impl/winmd_reader/filter.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | struct filter 5 | { 6 | filter() noexcept = default; 7 | 8 | template 9 | filter(T const& includes, T const& excludes) 10 | { 11 | for (auto&& include : includes) 12 | { 13 | m_rules.push_back({ include, true }); 14 | } 15 | 16 | for (auto&& exclude : excludes) 17 | { 18 | m_rules.push_back({ exclude, false }); 19 | } 20 | 21 | std::sort(m_rules.begin(), m_rules.end(), [](auto const& lhs, auto const& rhs) 22 | { 23 | auto size_compare = int(lhs.first.size()) - int(rhs.first.size()); 24 | return (size_compare > 0) || ((size_compare == 0) && !lhs.second); 25 | }); 26 | } 27 | 28 | bool includes(TypeDef const& type) const 29 | { 30 | return includes(type.TypeNamespace(), type.TypeName()); 31 | } 32 | 33 | bool includes(std::string_view const& type) const 34 | { 35 | auto position = type.find_last_of('.'); 36 | return includes(type.substr(0, position), type.substr(position + 1)); 37 | } 38 | 39 | bool includes(std::vector const& types) const 40 | { 41 | if (m_rules.empty()) 42 | { 43 | return true; 44 | } 45 | 46 | for (auto&& type : types) 47 | { 48 | if (includes(type.TypeNamespace(), type.TypeName())) 49 | { 50 | return true; 51 | } 52 | } 53 | 54 | return false; 55 | } 56 | 57 | bool includes(cache::namespace_members const& members) const 58 | { 59 | if (m_rules.empty()) 60 | { 61 | return true; 62 | } 63 | 64 | for (auto&& type : members.types) 65 | { 66 | if (includes(type.second.TypeNamespace(), type.second.TypeName())) 67 | { 68 | return true; 69 | } 70 | } 71 | 72 | return false; 73 | } 74 | 75 | template 76 | auto bind_each(std::vector const& types) const 77 | { 78 | return [&](auto& writer) 79 | { 80 | for (auto&& type : types) 81 | { 82 | if (includes(type)) 83 | { 84 | F(writer, type); 85 | } 86 | } 87 | }; 88 | } 89 | 90 | bool empty() const noexcept 91 | { 92 | return m_rules.empty(); 93 | } 94 | 95 | private: 96 | 97 | bool includes(std::string_view const& type_namespace, std::string_view const& type_name) const noexcept 98 | { 99 | if (m_rules.empty()) 100 | { 101 | return true; 102 | } 103 | 104 | for (auto&& rule : m_rules) 105 | { 106 | if (match(type_namespace, type_name, rule.first)) 107 | { 108 | return rule.second; 109 | } 110 | } 111 | 112 | return false; 113 | } 114 | 115 | static bool match(std::string_view const& type_namespace, std::string_view const& type_name, std::string_view const& match) noexcept 116 | { 117 | if (match.size() <= type_namespace.size()) 118 | { 119 | return impl::starts_with(type_namespace, match); 120 | } 121 | 122 | if (!impl::starts_with(match, type_namespace)) 123 | { 124 | return false; 125 | } 126 | 127 | if (match[type_namespace.size()] != '.') 128 | { 129 | return false; 130 | } 131 | 132 | return impl::starts_with(type_name, match.substr(type_namespace.size() + 1)); 133 | } 134 | 135 | std::vector> m_rules; 136 | }; 137 | } 138 | -------------------------------------------------------------------------------- /cppwin32/winmd/impl/winmd_reader/helpers.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | template 5 | bool empty(std::pair const& range) noexcept 6 | { 7 | return range.first == range.second; 8 | } 9 | 10 | template 11 | std::size_t size(std::pair const& range) noexcept 12 | { 13 | return range.second - range.first; 14 | } 15 | 16 | inline auto find(TypeRef const& type) 17 | { 18 | if (type.ResolutionScope().type() != ResolutionScope::TypeRef) 19 | { 20 | return type.get_database().get_cache().find(type.TypeNamespace(), type.TypeName()); 21 | } 22 | else 23 | { 24 | auto enclosing_type = find(type.ResolutionScope().TypeRef()); 25 | if (!enclosing_type) 26 | { 27 | return TypeDef{}; 28 | } 29 | auto const& nested_types = enclosing_type.get_cache().nested_types(enclosing_type); 30 | auto iter = std::find_if(nested_types.begin(), nested_types.end(), 31 | [name = type.TypeName()](TypeDef const& arg) 32 | { 33 | return name == arg.TypeName(); 34 | }); 35 | if (iter == nested_types.end()) 36 | { 37 | return TypeDef{}; 38 | } 39 | return *iter; 40 | } 41 | } 42 | 43 | inline auto find_required(TypeRef const& type) 44 | { 45 | if (type.ResolutionScope().type() != ResolutionScope::TypeRef) 46 | { 47 | return type.get_database().get_cache().find_required(type.TypeNamespace(), type.TypeName()); 48 | } 49 | else 50 | { 51 | auto enclosing_type = find_required(type.ResolutionScope().TypeRef()); 52 | auto const& nested_types = enclosing_type.get_cache().nested_types(enclosing_type); 53 | auto iter = std::find_if(nested_types.begin(), nested_types.end(), 54 | [name = type.TypeName()](TypeDef const& arg) 55 | { 56 | return name == arg.TypeName(); 57 | }); 58 | if (iter == nested_types.end()) 59 | { 60 | impl::throw_invalid("Type '", enclosing_type.TypeName(), ".", type.TypeName(), "' could not be found"); 61 | } 62 | return *iter; 63 | } 64 | } 65 | 66 | inline TypeDef find(coded_index const& type) 67 | { 68 | if (type.type() == TypeDefOrRef::TypeRef) 69 | { 70 | return find(type.TypeRef()); 71 | } 72 | else if (type.type() == TypeDefOrRef::TypeDef) 73 | { 74 | return type.TypeDef(); 75 | } 76 | else 77 | { 78 | XLANG_ASSERT(false); 79 | return {}; 80 | } 81 | } 82 | 83 | inline TypeDef find_required(coded_index const& type) 84 | { 85 | if (type.type() == TypeDefOrRef::TypeRef) 86 | { 87 | return find_required(type.TypeRef()); 88 | } 89 | else if (type.type() == TypeDefOrRef::TypeDef) 90 | { 91 | return type.TypeDef(); 92 | } 93 | else 94 | { 95 | XLANG_ASSERT(false); 96 | return {}; 97 | } 98 | } 99 | 100 | inline bool is_const(ParamSig const& param) 101 | { 102 | auto is_type_const = [](auto&& type) 103 | { 104 | return type.TypeNamespace() == "System.Runtime.CompilerServices" && type.TypeName() == "IsConst"; 105 | }; 106 | 107 | for (auto const& cmod : param.CustomMod()) 108 | { 109 | auto type = cmod.Type(); 110 | 111 | if (type.type() == TypeDefOrRef::TypeDef) 112 | { 113 | if (is_type_const(type.TypeDef())) 114 | { 115 | return true; 116 | } 117 | } 118 | else if (type.type() == TypeDefOrRef::TypeRef) 119 | { 120 | if (is_type_const(type.TypeRef())) 121 | { 122 | return true; 123 | } 124 | } 125 | } 126 | 127 | return false; 128 | }; 129 | 130 | TypeDef find_non_nested_root(TypeDef const& type) 131 | { 132 | if (is_nested(type)) 133 | { 134 | return find_non_nested_root(type.EnclosingType()); 135 | } 136 | return type; 137 | } 138 | 139 | TypeDef find_non_nested_root(TypeRef const& type) 140 | { 141 | if (is_nested(type)) 142 | { 143 | return find_non_nested_root(type.ResolutionScope().TypeRef()); 144 | } 145 | return find(type); 146 | } 147 | 148 | TypeDef find_non_nested_root(coded_index const& type) 149 | { 150 | if (type.type() == TypeDefOrRef::TypeDef) 151 | { 152 | return find_non_nested_root(type.TypeDef()); 153 | } 154 | else if (type.type() == TypeDefOrRef::TypeRef) 155 | { 156 | return find_non_nested_root(type.TypeRef()); 157 | } 158 | else 159 | { 160 | XLANG_ASSERT(false); 161 | return {}; 162 | } 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /cppwin32/winmd/impl/winmd_reader/index.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | template <> struct typed_index : index_base 5 | { 6 | using index_base::index_base; 7 | 8 | auto MemberRef() const; 9 | auto MethodDef() const; 10 | }; 11 | 12 | template <> struct typed_index : index_base 13 | { 14 | using index_base::index_base; 15 | 16 | auto Field() const; 17 | auto Param() const; 18 | auto Property() const; 19 | }; 20 | 21 | template <> struct typed_index : index_base 22 | { 23 | using index_base::index_base; 24 | 25 | auto Property() const; 26 | auto Event() const; 27 | }; 28 | 29 | template <> struct typed_index : index_base 30 | { 31 | using index_base::index_base; 32 | 33 | auto MethodDef() const; 34 | auto MemberRef() const; 35 | }; 36 | 37 | template <> struct typed_index : index_base 38 | { 39 | using index_base::index_base; 40 | 41 | auto Module() const; 42 | auto ModuleRef() const; 43 | auto AssemblyRef() const; 44 | auto TypeRef() const; 45 | }; 46 | 47 | template <> struct typed_index : index_base 48 | { 49 | using index_base::index_base; 50 | 51 | TypeDef TypeDef() const; 52 | TypeRef TypeRef() const; 53 | TypeSpec TypeSpec() const; 54 | auto CustomAttribute() const; 55 | }; 56 | } 57 | -------------------------------------------------------------------------------- /cppwin32/winmd/impl/winmd_reader/key.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | template 5 | template 6 | Row index_base::get_row() const 7 | { 8 | XLANG_ASSERT(type() == (index_tag_v)); 9 | return get_database().template get_table()[index()]; 10 | } 11 | 12 | inline auto typed_index::MemberRef() const 13 | { 14 | return get_row(); 15 | } 16 | 17 | inline auto typed_index::MethodDef() const 18 | { 19 | return get_row(); 20 | } 21 | 22 | inline auto typed_index::Field() const 23 | { 24 | return get_row(); 25 | } 26 | 27 | inline auto typed_index::Param() const 28 | { 29 | return get_row(); 30 | } 31 | 32 | inline auto typed_index::Property() const 33 | { 34 | return get_row(); 35 | } 36 | 37 | inline auto typed_index::Property() const 38 | { 39 | return get_row(); 40 | } 41 | 42 | inline auto typed_index::Event() const 43 | { 44 | return get_row(); 45 | } 46 | 47 | inline auto typed_index::MethodDef() const 48 | { 49 | return get_row(); 50 | } 51 | 52 | inline auto typed_index::MemberRef() const 53 | { 54 | return get_row(); 55 | } 56 | 57 | inline auto typed_index::Module() const 58 | { 59 | return get_row(); 60 | } 61 | 62 | inline auto typed_index::ModuleRef() const 63 | { 64 | return get_row(); 65 | } 66 | 67 | inline auto typed_index::AssemblyRef() const 68 | { 69 | return get_row(); 70 | } 71 | 72 | inline auto typed_index::TypeRef() const 73 | { 74 | return get_row(); 75 | } 76 | 77 | inline TypeDef typed_index::TypeDef() const 78 | { 79 | return get_row(); 80 | } 81 | 82 | inline TypeRef typed_index::TypeRef() const 83 | { 84 | return get_row(); 85 | } 86 | 87 | inline TypeSpec typed_index::TypeSpec() const 88 | { 89 | return get_row(); 90 | } 91 | 92 | inline auto typed_index::CustomAttribute() const 93 | { 94 | if (type() == TypeDefOrRef::TypeDef) 95 | { 96 | return TypeDef().CustomAttribute(); 97 | } 98 | 99 | if (type() == TypeDefOrRef::TypeRef) 100 | { 101 | return TypeRef().CustomAttribute(); 102 | } 103 | 104 | return TypeSpec().CustomAttribute(); 105 | } 106 | 107 | inline auto typed_index::TypeRef() const 108 | { 109 | return get_row(); 110 | } 111 | 112 | inline auto typed_index::TypeDef() const 113 | { 114 | return get_row(); 115 | } 116 | 117 | inline bool TypeDef::is_enum() const 118 | { 119 | return extends_type(*this, "System"sv, "Enum"sv); 120 | } 121 | 122 | struct EnumDefinition 123 | { 124 | explicit EnumDefinition(TypeDef const& type) 125 | : m_typedef(type) 126 | { 127 | XLANG_ASSERT(type.is_enum()); 128 | for (auto field : type.FieldList()) 129 | { 130 | if (!field.Flags().Literal() && !field.Flags().Static()) 131 | { 132 | XLANG_ASSERT(m_underlying_type == ElementType::End); 133 | m_underlying_type = std::get(field.Signature().Type().Type()); 134 | XLANG_ASSERT(ElementType::Boolean <= m_underlying_type && m_underlying_type <= ElementType::U8); 135 | } 136 | } 137 | } 138 | 139 | auto get_enumerator(std::string_view const& name) const 140 | { 141 | auto fields = m_typedef.FieldList(); 142 | 143 | auto field = std::find_if(begin(fields), end(fields), [&](auto&& field) 144 | { 145 | return field.Name() == name; 146 | }); 147 | 148 | XLANG_ASSERT(field != end(fields)); 149 | return field; 150 | } 151 | 152 | TypeDef m_typedef; 153 | ElementType m_underlying_type{}; 154 | 155 | }; 156 | 157 | inline auto TypeDef::get_enum_definition() const 158 | { 159 | return EnumDefinition{ *this }; 160 | } 161 | 162 | template 163 | CustomAttribute get_attribute(T const& row, std::string_view const& type_namespace, std::string_view const& type_name) 164 | { 165 | for (auto&& attribute : row.CustomAttribute()) 166 | { 167 | auto pair = attribute.TypeNamespaceAndName(); 168 | 169 | if (pair.first == type_namespace && pair.second == type_name) 170 | { 171 | return attribute; 172 | } 173 | } 174 | 175 | return {}; 176 | } 177 | 178 | enum class category 179 | { 180 | interface_type, 181 | class_type, 182 | enum_type, 183 | struct_type, 184 | delegate_type 185 | }; 186 | 187 | inline category get_category(TypeDef const& type) 188 | { 189 | if (type.Flags().Semantics() == TypeSemantics::Interface || get_attribute(type, "System.Runtime.InteropServices"sv, "GuidAttribute"sv)) 190 | { 191 | return category::interface_type; 192 | } 193 | 194 | auto const& [extends_namespace, extends_name] = get_base_class_namespace_and_name(type); 195 | 196 | if (extends_name == "Enum"sv && extends_namespace == "System"sv) 197 | { 198 | return category::enum_type; 199 | } 200 | 201 | if (extends_name == "ValueType"sv && extends_namespace == "System"sv) 202 | { 203 | return category::struct_type; 204 | } 205 | 206 | if (extends_name == "MulticastDelegate"sv && extends_namespace == "System"sv) 207 | { 208 | return category::delegate_type; 209 | } 210 | 211 | return category::class_type; 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /cppwin32/winmd/impl/winmd_reader/pe.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::impl 3 | { 4 | struct image_dos_header 5 | { 6 | uint16_t e_signature; 7 | uint16_t e_cblp; 8 | uint16_t e_cp; 9 | uint16_t e_crlc; 10 | uint16_t e_cparhdr; 11 | uint16_t e_minalloc; 12 | uint16_t e_maxalloc; 13 | uint16_t e_ss; 14 | uint16_t e_sp; 15 | uint16_t e_csum; 16 | uint16_t e_ip; 17 | uint16_t e_cs; 18 | uint16_t e_lfarlc; 19 | uint16_t e_ovno; 20 | uint16_t e_res[4]; 21 | uint16_t e_oemid; 22 | uint16_t e_oeminfo; 23 | uint16_t e_res2[10]; 24 | int32_t e_lfanew; 25 | }; 26 | 27 | struct image_file_header 28 | { 29 | uint16_t Machine; 30 | uint16_t NumberOfSections; 31 | uint32_t TimeDateStamp; 32 | uint32_t PointerToSymbolTable; 33 | uint32_t NumberOfSymbols; 34 | uint16_t SizeOfOptionalHeader; 35 | uint16_t Characteristics; 36 | }; 37 | 38 | struct image_data_directory 39 | { 40 | uint32_t VirtualAddress; 41 | uint32_t Size; 42 | }; 43 | 44 | struct image_optional_header32 45 | { 46 | uint16_t Magic; 47 | uint8_t MajorLinkerVersion; 48 | uint8_t MinorLinkerVersion; 49 | uint32_t SizeOfCode; 50 | uint32_t SizeOfInitializedData; 51 | uint32_t SizeOfUninitializedData; 52 | uint32_t AddressOfEntryPoint; 53 | uint32_t BaseOfCode; 54 | uint32_t BaseOfData; 55 | uint32_t ImageBase; 56 | uint32_t SectionAlignment; 57 | uint32_t FileAlignment; 58 | uint16_t MajorOperatingSystemVersion; 59 | uint16_t MinorOperatingSystemVersion; 60 | uint16_t MajorImageVersion; 61 | uint16_t MinorImageVersion; 62 | uint16_t MajorSubsystemVersion; 63 | uint16_t MinorSubsystemVersion; 64 | uint32_t Win32VersionValue; 65 | uint32_t SizeOfImage; 66 | uint32_t SizeOfHeaders; 67 | uint32_t CheckSum; 68 | uint16_t Subsystem; 69 | uint16_t DllCharacteristics; 70 | uint32_t SizeOfStackReserve; 71 | uint32_t SizeOfStackCommit; 72 | uint32_t SizeOfHeapReserve; 73 | uint32_t SizeOfHeapCommit; 74 | uint32_t LoaderFlags; 75 | uint32_t NumberOfRvaAndSizes; 76 | image_data_directory DataDirectory[16]; 77 | }; 78 | 79 | struct image_nt_headers32 80 | { 81 | uint32_t Signature; 82 | image_file_header FileHeader; 83 | image_optional_header32 OptionalHeader; 84 | }; 85 | 86 | struct image_optional_header32plus 87 | { 88 | uint16_t Magic; 89 | uint8_t MajorLinkerVersion; 90 | uint8_t MinorLinkerVersion; 91 | uint32_t SizeOfCode; 92 | uint32_t SizeOfInitializedData; 93 | uint32_t SizeOfUninitializedData; 94 | uint32_t AddressOfEntryPoint; 95 | uint32_t BaseOfCode; 96 | uint64_t ImageBase; 97 | uint32_t SectionAlignment; 98 | uint32_t FileAlignment; 99 | uint16_t MajorOperatingSystemVersion; 100 | uint16_t MinorOperatingSystemVersion; 101 | uint16_t MajorImageVersion; 102 | uint16_t MinorImageVersion; 103 | uint16_t MajorSubsystemVersion; 104 | uint16_t MinorSubsystemVersion; 105 | uint32_t Win32VersionValue; 106 | uint32_t SizeOfImage; 107 | uint32_t SizeOfHeaders; 108 | uint32_t CheckSum; 109 | uint16_t Subsystem; 110 | uint16_t DllCharacteristics; 111 | uint64_t SizeOfStackReserve; 112 | uint64_t SizeOfStackCommit; 113 | uint64_t SizeOfHeapReserve; 114 | uint64_t SizeOfHeapCommit; 115 | uint32_t LoaderFlags; 116 | uint32_t NumberOfRvaAndSizes; 117 | image_data_directory DataDirectory[16]; 118 | }; 119 | 120 | struct image_nt_headers32plus 121 | { 122 | uint32_t Signature; 123 | image_file_header FileHeader; 124 | image_optional_header32plus OptionalHeader; 125 | }; 126 | 127 | struct image_section_header { 128 | uint8_t Name[8]; // IMAGE_SIZEOF_SHORT_NAME 129 | union 130 | { 131 | uint32_t PhysicalAddress; 132 | uint32_t VirtualSize; 133 | } Misc; 134 | uint32_t VirtualAddress; 135 | uint32_t SizeOfRawData; 136 | uint32_t PointerToRawData; 137 | uint32_t PointerToRelocations; 138 | uint32_t PointerToLinenumbers; 139 | uint16_t NumberOfRelocations; 140 | uint16_t NumberOfLinenumbers; 141 | uint32_t Characteristics; 142 | }; 143 | 144 | struct image_cor20_header 145 | { 146 | uint32_t cb; 147 | uint16_t MajorRuntimeVersion; 148 | uint16_t MinorRuntimeVersion; 149 | image_data_directory MetaData; 150 | uint32_t Flags; 151 | union 152 | { 153 | uint32_t EntryPointToken; 154 | uint32_t EntryPointRVA; 155 | } dummyunionname; 156 | image_data_directory Resources; 157 | image_data_directory StrongNameSignature; 158 | image_data_directory CodeManagerTable; 159 | image_data_directory VTableFixups; 160 | image_data_directory ExportAddressTableJumps; 161 | image_data_directory ManagedNativeHeader; 162 | }; 163 | } 164 | -------------------------------------------------------------------------------- /cppwin32/winmd/impl/winmd_reader/schema.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | struct TypeRef : row_base 5 | { 6 | using row_base::row_base; 7 | 8 | auto ResolutionScope() const 9 | { 10 | return get_coded_index(0); 11 | } 12 | 13 | auto TypeName() const 14 | { 15 | return get_string(1); 16 | } 17 | 18 | auto TypeNamespace() const 19 | { 20 | return get_string(2); 21 | } 22 | 23 | auto CustomAttribute() const; 24 | }; 25 | 26 | struct CustomAttribute : row_base 27 | { 28 | using row_base::row_base; 29 | 30 | auto Parent() const 31 | { 32 | return get_coded_index(0); 33 | } 34 | 35 | auto Type() const 36 | { 37 | return get_coded_index(1); 38 | } 39 | 40 | auto Value() const; 41 | 42 | auto TypeNamespaceAndName() const; 43 | }; 44 | 45 | struct TypeDef : row_base 46 | { 47 | using row_base::row_base; 48 | 49 | auto Flags() const 50 | { 51 | return TypeAttributes{{ get_value(0) }}; 52 | } 53 | 54 | auto TypeName() const 55 | { 56 | return get_string(1); 57 | } 58 | 59 | auto TypeNamespace() const 60 | { 61 | return get_string(2); 62 | } 63 | 64 | auto Extends() const 65 | { 66 | return get_coded_index(3); 67 | } 68 | 69 | auto FieldList() const; 70 | auto MethodList() const; 71 | 72 | auto CustomAttribute() const; 73 | auto InterfaceImpl() const; 74 | auto GenericParam() const; 75 | auto PropertyList() const; 76 | auto EventList() const; 77 | auto MethodImplList() const; 78 | 79 | auto EnclosingType() const; 80 | 81 | bool is_enum() const; 82 | auto get_enum_definition() const; 83 | }; 84 | 85 | struct MethodDef : row_base 86 | { 87 | using row_base::row_base; 88 | 89 | auto RVA() const 90 | { 91 | return get_value(0); 92 | } 93 | 94 | auto ImplFlags() const 95 | { 96 | return MethodImplAttributes{{ get_value(1) }}; 97 | } 98 | 99 | auto Flags() const 100 | { 101 | return MethodAttributes{{ get_value(2) }}; 102 | } 103 | 104 | auto Name() const 105 | { 106 | return get_string(3); 107 | } 108 | 109 | MethodDefSig Signature() const 110 | { 111 | auto cursor = get_blob(4); 112 | return{ get_table(), cursor }; 113 | } 114 | 115 | auto ParamList() const; 116 | auto CustomAttribute() const; 117 | auto Parent() const; 118 | auto GenericParam() const; 119 | 120 | bool SpecialName() const 121 | { 122 | return Flags().SpecialName(); 123 | } 124 | }; 125 | 126 | struct MemberRef : row_base 127 | { 128 | using row_base::row_base; 129 | 130 | auto Class() const 131 | { 132 | return get_coded_index(0); 133 | } 134 | 135 | auto Name() const 136 | { 137 | return get_string(1); 138 | } 139 | 140 | MethodDefSig MethodSignature() const 141 | { 142 | auto cursor = get_blob(2); 143 | return{ get_table(), cursor }; 144 | } 145 | 146 | auto CustomAttribute() const; 147 | }; 148 | 149 | struct Module : row_base 150 | { 151 | using row_base::row_base; 152 | 153 | auto Name() const 154 | { 155 | return get_string(1); 156 | } 157 | 158 | auto CustomAttribute() const; 159 | }; 160 | 161 | struct Field : row_base 162 | { 163 | using row_base::row_base; 164 | 165 | auto Flags() const 166 | { 167 | return FieldAttributes{{ get_value(0) }}; 168 | } 169 | 170 | auto Name() const 171 | { 172 | return get_string(1); 173 | } 174 | 175 | auto Signature() const 176 | { 177 | auto cursor = get_blob(2); 178 | return FieldSig{ get_table(), cursor }; 179 | } 180 | 181 | auto CustomAttribute() const; 182 | auto Constant() const; 183 | auto Parent() const; 184 | auto FieldMarshal() const; 185 | }; 186 | 187 | struct Param : row_base 188 | { 189 | using row_base::row_base; 190 | 191 | auto Flags() const 192 | { 193 | return ParamAttributes{{ get_value(0) }}; 194 | } 195 | 196 | auto Sequence() const 197 | { 198 | return get_value(1); 199 | } 200 | 201 | auto Name() const 202 | { 203 | return get_string(2); 204 | } 205 | 206 | auto CustomAttribute() const; 207 | auto Constant() const; 208 | auto FieldMarshal() const; 209 | }; 210 | 211 | struct InterfaceImpl : row_base 212 | { 213 | using row_base::row_base; 214 | 215 | auto Class() const; 216 | 217 | auto Interface() const 218 | { 219 | return get_coded_index(1); 220 | } 221 | 222 | auto CustomAttribute() const; 223 | }; 224 | 225 | struct Constant : row_base 226 | { 227 | using row_base::row_base; 228 | 229 | using constant_type = std::variant; 230 | 231 | auto Type() const 232 | { 233 | return get_value(0); 234 | } 235 | 236 | auto Parent() const 237 | { 238 | return get_coded_index(1); 239 | } 240 | 241 | auto ValueBoolean() const; 242 | auto ValueChar() const; 243 | auto ValueInt8() const; 244 | auto ValueUInt8() const; 245 | auto ValueInt16() const; 246 | auto ValueUInt16() const; 247 | auto ValueInt32() const; 248 | auto ValueUInt32() const; 249 | auto ValueInt64() const; 250 | auto ValueUInt64() const; 251 | auto ValueFloat32() const; 252 | auto ValueFloat64() const; 253 | auto ValueString() const; 254 | auto ValueClass() const; 255 | 256 | constant_type Value() const; 257 | }; 258 | 259 | struct FieldMarshal : row_base 260 | { 261 | using row_base::row_base; 262 | 263 | auto Parent() const 264 | { 265 | return get_coded_index(0); 266 | } 267 | }; 268 | 269 | struct TypeSpec : row_base 270 | { 271 | using row_base::row_base; 272 | 273 | TypeSpecSig Signature() const 274 | { 275 | auto cursor = get_blob(0); 276 | return{ get_table(), cursor }; 277 | } 278 | 279 | auto CustomAttribute() const; 280 | }; 281 | 282 | struct DeclSecurity : row_base 283 | { 284 | using row_base::row_base; 285 | }; 286 | 287 | struct ClassLayout : row_base 288 | { 289 | using row_base::row_base; 290 | 291 | auto PackingSize() const 292 | { 293 | return get_value(0); 294 | } 295 | 296 | auto ClassSize() const 297 | { 298 | return get_value(1); 299 | } 300 | 301 | auto Parent() const; 302 | }; 303 | 304 | struct FieldLayout : row_base 305 | { 306 | using row_base::row_base; 307 | }; 308 | 309 | struct StandAloneSig : row_base 310 | { 311 | using row_base::row_base; 312 | 313 | auto CustomAttribute() const; 314 | }; 315 | 316 | struct EventMap : row_base 317 | { 318 | using row_base::row_base; 319 | 320 | auto Parent() const; 321 | auto EventList() const; 322 | }; 323 | 324 | struct Event : row_base 325 | { 326 | using row_base::row_base; 327 | 328 | auto EventFlags() const 329 | { 330 | return EventAttributes{{ get_value(0) }}; 331 | } 332 | 333 | auto Name() const 334 | { 335 | return get_string(1); 336 | } 337 | 338 | auto EventType() const 339 | { 340 | return get_coded_index(2); 341 | } 342 | 343 | auto MethodSemantic() const; 344 | auto Parent() const; 345 | auto CustomAttribute() const; 346 | }; 347 | 348 | struct PropertyMap : row_base 349 | { 350 | using row_base::row_base; 351 | 352 | auto Parent() const; 353 | auto PropertyList() const; 354 | }; 355 | 356 | struct Property : row_base 357 | { 358 | using row_base::row_base; 359 | 360 | auto Flags() const 361 | { 362 | return PropertyAttributes{{ get_value(0) }}; 363 | } 364 | 365 | auto Name() const 366 | { 367 | return get_string(1); 368 | } 369 | 370 | PropertySig Type() const 371 | { 372 | auto cursor = get_blob(2); 373 | return{ get_table(), cursor }; 374 | } 375 | 376 | auto MethodSemantic() const; 377 | auto Parent() const; 378 | auto Constant() const; 379 | auto CustomAttribute() const; 380 | }; 381 | 382 | struct MethodSemantics : row_base 383 | { 384 | using row_base::row_base; 385 | 386 | auto Semantic() const 387 | { 388 | return MethodSemanticsAttributes{{ get_value(0) }}; 389 | } 390 | 391 | auto Method() const; 392 | 393 | auto Association() const 394 | { 395 | return get_coded_index(2); 396 | } 397 | }; 398 | 399 | struct MethodImpl : row_base 400 | { 401 | using row_base::row_base; 402 | 403 | auto Class() const; 404 | 405 | auto MethodBody() const 406 | { 407 | return get_coded_index(1); 408 | } 409 | 410 | auto MethodDeclaration() const 411 | { 412 | return get_coded_index(2); 413 | } 414 | }; 415 | 416 | struct ModuleRef : row_base 417 | { 418 | using row_base::row_base; 419 | 420 | auto CustomAttribute() const; 421 | }; 422 | 423 | struct ImplMap : row_base 424 | { 425 | using row_base::row_base; 426 | }; 427 | 428 | struct FieldRVA : row_base 429 | { 430 | using row_base::row_base; 431 | }; 432 | 433 | struct Assembly : row_base 434 | { 435 | using row_base::row_base; 436 | 437 | auto HashAlgId() const 438 | { 439 | return get_value(0); 440 | } 441 | 442 | auto Version() const; 443 | 444 | auto Flags() const 445 | { 446 | return AssemblyAttributes{{ get_value(2) }}; 447 | } 448 | 449 | auto PublicKey() const 450 | { 451 | return get_blob(3); 452 | } 453 | 454 | auto Name() const 455 | { 456 | return get_string(4); 457 | } 458 | 459 | auto Culture() const 460 | { 461 | return get_string(5); 462 | } 463 | 464 | auto CustomAttribute() const; 465 | }; 466 | 467 | struct AssemblyProcessor : row_base 468 | { 469 | using row_base::row_base; 470 | 471 | auto Processor() const 472 | { 473 | return get_value(0); 474 | } 475 | }; 476 | 477 | struct AssemblyOS : row_base 478 | { 479 | using row_base::row_base; 480 | 481 | auto OSPlatformId() const 482 | { 483 | return get_value(0); 484 | } 485 | 486 | auto OSMajorVersion() const 487 | { 488 | return get_value(1); 489 | } 490 | 491 | auto OSMinorVersion() const 492 | { 493 | return get_value(2); 494 | } 495 | }; 496 | 497 | struct AssemblyRef : row_base 498 | { 499 | using row_base::row_base; 500 | 501 | auto Version() const; 502 | 503 | auto Flags() const 504 | { 505 | return AssemblyAttributes{{ get_value(1) }}; 506 | } 507 | 508 | auto PublicKeyOrToken() const 509 | { 510 | return get_blob(2); 511 | } 512 | 513 | auto Name() const 514 | { 515 | return get_string(3); 516 | } 517 | 518 | auto Culture() const 519 | { 520 | return get_string(4); 521 | } 522 | 523 | auto HashValue() const 524 | { 525 | return get_string(5); 526 | } 527 | 528 | auto CustomAttribute() const; 529 | }; 530 | 531 | struct AssemblyRefProcessor : row_base 532 | { 533 | using row_base::row_base; 534 | 535 | auto Processor() const 536 | { 537 | return get_value(0); 538 | } 539 | 540 | auto AssemblyRef() const; 541 | }; 542 | 543 | struct AssemblyRefOS : row_base 544 | { 545 | using row_base::row_base; 546 | 547 | auto OSPlatformId() const 548 | { 549 | return get_value(0); 550 | } 551 | 552 | auto OSMajorVersion() const 553 | { 554 | return get_value(1); 555 | } 556 | 557 | auto OSMinorVersion() const 558 | { 559 | return get_value(2); 560 | } 561 | 562 | auto AssemblyRef() const; 563 | }; 564 | 565 | struct File : row_base 566 | { 567 | using row_base::row_base; 568 | 569 | auto CustomAttribute() const; 570 | }; 571 | 572 | struct ExportedType : row_base 573 | { 574 | using row_base::row_base; 575 | 576 | auto CustomAttribute() const; 577 | }; 578 | 579 | struct ManifestResource : row_base 580 | { 581 | using row_base::row_base; 582 | 583 | auto CustomAttribute() const; 584 | }; 585 | 586 | struct NestedClass : row_base 587 | { 588 | using row_base::row_base; 589 | 590 | TypeDef NestedType() const; 591 | TypeDef EnclosingType() const; 592 | }; 593 | 594 | struct GenericParam : row_base 595 | { 596 | using row_base::row_base; 597 | 598 | auto Number() const 599 | { 600 | return get_value(0); 601 | } 602 | 603 | auto Flags() const 604 | { 605 | return GenericParamAttributes{{ get_value(1) }}; 606 | } 607 | 608 | auto Owner() const 609 | { 610 | return get_coded_index(2); 611 | } 612 | 613 | auto Name() const 614 | { 615 | return get_string(3); 616 | } 617 | 618 | auto CustomAttribute() const; 619 | }; 620 | 621 | struct MethodSpec : row_base 622 | { 623 | using row_base::row_base; 624 | 625 | auto CustomAttribute() const; 626 | }; 627 | 628 | struct GenericParamConstraint : row_base 629 | { 630 | using row_base::row_base; 631 | 632 | auto CustomAttribute() const; 633 | }; 634 | 635 | inline bool operator<(coded_index const& left, CustomAttribute const& right) noexcept 636 | { 637 | return left < right.Parent(); 638 | } 639 | 640 | inline bool operator<(CustomAttribute const& left, coded_index const& right) noexcept 641 | { 642 | return left.Parent() < right; 643 | } 644 | 645 | inline bool operator<(coded_index const& left, GenericParam const& right) noexcept 646 | { 647 | return left < right.Owner(); 648 | } 649 | 650 | inline bool operator<(GenericParam const& left, coded_index const& right) noexcept 651 | { 652 | return left.Owner() < right; 653 | } 654 | 655 | inline bool operator<(coded_index const& left, Constant const& right) noexcept 656 | { 657 | return left < right.Parent(); 658 | } 659 | 660 | inline bool operator<(Constant const& left, coded_index const& right) noexcept 661 | { 662 | return left.Parent() < right; 663 | } 664 | 665 | inline bool operator<(coded_index const& left, MethodSemantics const& right) noexcept 666 | { 667 | return left < right.Association(); 668 | } 669 | 670 | inline bool operator<(MethodSemantics const& left, coded_index const& right) noexcept 671 | { 672 | return left.Association() < right; 673 | } 674 | 675 | inline bool operator<(NestedClass const& left, TypeDef const& right) noexcept 676 | { 677 | return left.NestedType() < right; 678 | } 679 | 680 | inline bool operator<(TypeDef const& left, NestedClass const& right) noexcept 681 | { 682 | return left < right.NestedType(); 683 | } 684 | 685 | inline bool operator<(coded_index const& left, FieldMarshal const& right) noexcept 686 | { 687 | return left < right.Parent(); 688 | } 689 | 690 | inline bool operator<(FieldMarshal const& left, coded_index const& right) noexcept 691 | { 692 | return left.Parent() < right; 693 | } 694 | } 695 | -------------------------------------------------------------------------------- /cppwin32/winmd/impl/winmd_reader/table.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | struct database; 5 | struct cache; 6 | 7 | struct table_base 8 | { 9 | explicit table_base(database const* database) noexcept : m_database(database) 10 | { 11 | } 12 | 13 | database const& get_database() const noexcept 14 | { 15 | return *m_database; 16 | } 17 | 18 | uint32_t size() const noexcept 19 | { 20 | return m_row_count; 21 | } 22 | 23 | uint32_t row_size() const noexcept 24 | { 25 | return m_row_size; 26 | } 27 | 28 | uint32_t column_size(uint32_t const column) const noexcept 29 | { 30 | return m_columns[column].size; 31 | } 32 | 33 | template 34 | T get_value(uint32_t const row, uint32_t const column) const 35 | { 36 | static_assert(std::is_enum_v || std::is_integral_v); 37 | uint32_t const data_size = m_columns[column].size; 38 | XLANG_ASSERT(data_size == 1 || data_size == 2 || data_size == 4 || data_size == 8); 39 | XLANG_ASSERT(data_size <= sizeof(T)); 40 | 41 | if (row > size()) 42 | { 43 | impl::throw_invalid("Invalid row index"); 44 | } 45 | 46 | uint8_t const* ptr = m_data + row * m_row_size + m_columns[column].offset; 47 | switch (data_size) 48 | { 49 | case 1: 50 | { 51 | uint8_t temp = *ptr; 52 | return static_cast(temp); 53 | } 54 | case 2: 55 | { 56 | uint16_t temp = *reinterpret_cast(ptr); 57 | return static_cast(temp); 58 | } 59 | case 4: 60 | { 61 | uint32_t temp = *reinterpret_cast(ptr); 62 | return static_cast(temp); 63 | } 64 | default: 65 | { 66 | uint64_t temp = *reinterpret_cast(ptr); 67 | return static_cast(temp); 68 | } 69 | } 70 | } 71 | 72 | private: 73 | 74 | friend database; 75 | 76 | struct column 77 | { 78 | uint8_t offset; 79 | uint8_t size; 80 | }; 81 | 82 | database const* m_database; 83 | uint8_t const* m_data{}; 84 | uint32_t m_row_count{}; 85 | uint8_t m_row_size{}; 86 | std::array m_columns{}; 87 | 88 | void set_row_count(uint32_t const row_count) noexcept 89 | { 90 | XLANG_ASSERT(!m_row_count); 91 | m_row_count = row_count; 92 | } 93 | 94 | void set_columns(uint8_t const a, uint8_t const b = 0, uint8_t const c = 0, uint8_t const d = 0, uint8_t const e = 0, uint8_t const f = 0) noexcept 95 | { 96 | XLANG_ASSERT(a); 97 | XLANG_ASSERT(a <= 8); 98 | XLANG_ASSERT(b <= 8); 99 | XLANG_ASSERT(c <= 8); 100 | XLANG_ASSERT(d <= 8); 101 | XLANG_ASSERT(e <= 8); 102 | XLANG_ASSERT(f <= 8); 103 | 104 | XLANG_ASSERT(!m_row_size); 105 | m_row_size = a + b + c + d + e + f; 106 | XLANG_ASSERT(m_row_size < UINT8_MAX); 107 | 108 | m_columns[0] = { 0, a }; 109 | if (b) { m_columns[1] = { static_cast(a), b }; } 110 | if (c) { m_columns[2] = { static_cast(a + b), c }; } 111 | if (d) { m_columns[3] = { static_cast(a + b + c), d }; } 112 | if (e) { m_columns[4] = { static_cast(a + b + c + d), e }; } 113 | if (f) { m_columns[5] = { static_cast(a + b + c + d + e), f }; } 114 | } 115 | 116 | void set_data(byte_view& view) noexcept 117 | { 118 | XLANG_ASSERT(!m_data); 119 | 120 | if (m_row_count) 121 | { 122 | XLANG_ASSERT(m_row_size); 123 | m_data = view.begin(); 124 | view = view.seek(m_row_count * m_row_size); 125 | } 126 | } 127 | 128 | uint8_t index_size() const noexcept 129 | { 130 | return m_row_count < (1 << 16) ? 2 : 4; 131 | } 132 | }; 133 | 134 | template 135 | struct index_base 136 | { 137 | index_base() noexcept = default; 138 | 139 | index_base(table_base const* const table, T const type, uint32_t const row) noexcept : 140 | m_table{ table }, 141 | m_value{ ((row + 1) << coded_index_bits_v) | static_cast(type) } 142 | { 143 | } 144 | 145 | index_base(table_base const* const table, uint32_t const value) noexcept : 146 | m_table{ table }, 147 | m_value{ value } 148 | { 149 | } 150 | 151 | explicit operator bool() const noexcept 152 | { 153 | return m_value != 0; 154 | } 155 | 156 | T type() const noexcept 157 | { 158 | return static_cast(m_value & ((1 << coded_index_bits_v) - 1)); 159 | } 160 | 161 | uint32_t index() const noexcept 162 | { 163 | return (m_value >> coded_index_bits_v) - 1; 164 | } 165 | 166 | template 167 | Row get_row() const; 168 | 169 | bool operator==(index_base const& other) const noexcept 170 | { 171 | return m_value == other.m_value; 172 | } 173 | 174 | bool operator!=(index_base const& other) const noexcept 175 | { 176 | return !(*this == other); 177 | } 178 | 179 | bool operator<(index_base const& other) const noexcept 180 | { 181 | return m_value < other.m_value; 182 | } 183 | 184 | database const& get_database() const noexcept 185 | { 186 | return m_table->get_database(); 187 | } 188 | 189 | protected: 190 | 191 | table_base const* m_table{}; 192 | uint32_t m_value{}; 193 | }; 194 | 195 | template 196 | struct typed_index : index_base 197 | { 198 | using index_base::index_base; 199 | }; 200 | 201 | template <> struct typed_index : index_base 202 | { 203 | using index_base::index_base; 204 | 205 | auto TypeRef() const; 206 | auto TypeDef() const; 207 | }; 208 | 209 | template 210 | struct coded_index : typed_index 211 | { 212 | coded_index() noexcept = default; 213 | 214 | coded_index(table_base const* const table, T const type, uint32_t const row) noexcept : 215 | typed_index{ table, type, row } 216 | { 217 | } 218 | 219 | coded_index(table_base const* const table, uint32_t const value) noexcept : 220 | typed_index{ table, value } 221 | { 222 | } 223 | }; 224 | 225 | template 226 | struct row_base 227 | { 228 | using iterator_category = std::random_access_iterator_tag; 229 | using value_type = Row; 230 | using difference_type = int32_t; 231 | using pointer = value_type*; 232 | using reference = value_type&; 233 | using const_reference = value_type const&; 234 | 235 | row_base(table_base const* const table, uint32_t const index) noexcept : m_table(table), m_index(index) 236 | { 237 | } 238 | 239 | uint32_t index() const noexcept 240 | { 241 | return m_index; 242 | } 243 | 244 | template 245 | auto coded_index() const noexcept 246 | { 247 | return reader::coded_index{ m_table, index_tag_v, index() }; 248 | } 249 | 250 | template 251 | T get_value(uint32_t const column) const 252 | { 253 | XLANG_ASSERT(*this); 254 | return m_table->get_value(m_index, column); 255 | } 256 | 257 | template 258 | auto get_list(uint32_t const column) const; 259 | 260 | template 261 | auto get_target_row(uint32_t const column) const; 262 | 263 | template 264 | auto get_parent_row() const; 265 | 266 | database const& get_database() const noexcept 267 | { 268 | return m_table->get_database(); 269 | } 270 | 271 | cache const& get_cache() const noexcept 272 | { 273 | return get_database().get_cache(); 274 | } 275 | 276 | reference operator++() noexcept 277 | { 278 | ++m_index; 279 | return static_cast(*this); 280 | } 281 | 282 | value_type operator++(int) noexcept 283 | { 284 | row_base temp{ *this }; 285 | operator++(); 286 | return temp; 287 | } 288 | 289 | reference operator--() noexcept 290 | { 291 | --m_index; 292 | return *this; 293 | } 294 | 295 | value_type operator--(int) noexcept 296 | { 297 | row_base temp{ *this }; 298 | operator--(); 299 | return temp; 300 | } 301 | 302 | reference operator+=(difference_type offset) noexcept 303 | { 304 | m_index += offset; 305 | return static_cast(*this); 306 | } 307 | 308 | value_type operator+(difference_type offset) const noexcept 309 | { 310 | return { m_table, m_index + offset }; 311 | } 312 | 313 | reference operator-=(difference_type offset) noexcept 314 | { 315 | return *this += -offset; 316 | } 317 | 318 | value_type operator-(difference_type offset) const noexcept 319 | { 320 | return *this + -offset; 321 | } 322 | 323 | difference_type operator-(row_base const& other) const noexcept 324 | { 325 | XLANG_ASSERT(m_table == other.m_table); 326 | return m_index - other.m_index; 327 | } 328 | 329 | value_type operator[](difference_type offset) const noexcept 330 | { 331 | return { m_table, m_index + offset }; 332 | } 333 | 334 | bool operator==(row_base const& other) const noexcept 335 | { 336 | return (m_table == other.m_table) && (m_index == other.m_index); 337 | } 338 | 339 | bool operator!=(row_base const& other) const noexcept 340 | { 341 | return !(*this == other); 342 | } 343 | 344 | bool operator<(row_base const& other) const noexcept 345 | { 346 | return m_table < other.m_table || (!(other.m_table < m_table) && m_index < other.m_index); 347 | } 348 | 349 | bool operator>(row_base const& other) const noexcept 350 | { 351 | return other < *this; 352 | } 353 | 354 | bool operator<=(row_base const& other) const noexcept 355 | { 356 | return !(other < *this); 357 | } 358 | 359 | bool operator>=(row_base const& other) const noexcept 360 | { 361 | return !(*this < other); 362 | } 363 | 364 | [[nodiscard]] const_reference operator*() const noexcept 365 | { 366 | return static_cast(*this); 367 | } 368 | 369 | explicit operator bool() const noexcept 370 | { 371 | return m_table != nullptr; 372 | } 373 | 374 | protected: 375 | 376 | row_base() noexcept = default; 377 | 378 | std::string_view get_string(uint32_t const column) const; 379 | byte_view get_blob(uint32_t const column) const; 380 | 381 | template 382 | auto get_coded_index(uint32_t const column) const 383 | { 384 | return reader::coded_index{ m_table, m_table->get_value(m_index, column) }; 385 | } 386 | 387 | table_base const* get_table() const noexcept 388 | { 389 | return m_table; 390 | } 391 | 392 | private: 393 | 394 | table_base const* m_table{}; 395 | uint32_t m_index{}; 396 | }; 397 | 398 | template 399 | struct table : table_base 400 | { 401 | explicit table(database const* const database) noexcept : table_base{ database } 402 | { 403 | } 404 | 405 | T begin() const noexcept 406 | { 407 | return { this, 0 }; 408 | } 409 | 410 | T end() const noexcept 411 | { 412 | return { this, size() }; 413 | } 414 | 415 | T operator[](uint32_t const row) const noexcept 416 | { 417 | return { this, row }; 418 | } 419 | }; 420 | } 421 | -------------------------------------------------------------------------------- /cppwin32/winmd/impl/winmd_reader/type_helpers.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | inline std::pair get_type_namespace_and_name(coded_index const& type) 5 | { 6 | if (type.type() == TypeDefOrRef::TypeDef) 7 | { 8 | auto const def = type.TypeDef(); 9 | return { def.TypeNamespace(), def.TypeName() }; 10 | } 11 | else if (type.type() == TypeDefOrRef::TypeRef) 12 | { 13 | auto const ref = type.TypeRef(); 14 | return { ref.TypeNamespace(), ref.TypeName() }; 15 | } 16 | else 17 | { 18 | XLANG_ASSERT(false); 19 | return {}; 20 | } 21 | } 22 | 23 | inline std::pair get_base_class_namespace_and_name(TypeDef const& type) 24 | { 25 | return get_type_namespace_and_name(type.Extends()); 26 | } 27 | 28 | inline auto extends_type(TypeDef type, std::string_view typeNamespace, std::string_view typeName) 29 | { 30 | return get_base_class_namespace_and_name(type) == std::pair(typeNamespace, typeName); 31 | } 32 | 33 | inline bool is_nested(TypeDef const& type) 34 | { 35 | const auto visibility = type.Flags().Visibility(); 36 | return !(visibility == TypeVisibility::Public || visibility == TypeVisibility::NotPublic); 37 | } 38 | 39 | inline bool is_nested(TypeRef const& type) 40 | { 41 | return type.ResolutionScope().type() == ResolutionScope::TypeRef; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /cppwin32/winmd/impl/winmd_reader/view.h: -------------------------------------------------------------------------------- 1 | 2 | namespace winmd::reader 3 | { 4 | template 5 | auto const& begin(std::pair const& values) noexcept 6 | { 7 | return values.first; 8 | } 9 | 10 | template 11 | auto const& end(std::pair const& values) noexcept 12 | { 13 | return values.second; 14 | } 15 | 16 | template 17 | auto distance(std::pair const& values) noexcept 18 | { 19 | return values.second - values.first; 20 | } 21 | 22 | template 23 | auto equal_range(Container const& container, T const& value) noexcept 24 | { 25 | return std::equal_range(container.begin(), container.end(), value); 26 | } 27 | 28 | template 29 | auto equal_range(Container const& container, T const& value, Compare compare) noexcept 30 | { 31 | return std::equal_range(container.begin(), container.end(), value, compare); 32 | } 33 | 34 | struct byte_view; 35 | inline int32_t uncompress_signed(byte_view& cursor, uint32_t length); 36 | 37 | struct byte_view 38 | { 39 | byte_view() noexcept = default; 40 | byte_view(byte_view const&) noexcept = default; 41 | byte_view& operator=(byte_view const&) noexcept = default; 42 | 43 | byte_view(byte_view&& other) noexcept : 44 | m_first(std::exchange(other.m_first, {})), 45 | m_last(std::exchange(other.m_last, {})) 46 | { 47 | } 48 | 49 | byte_view& operator=(byte_view&& other) noexcept 50 | { 51 | m_first = std::exchange(other.m_first, {}); 52 | m_last = std::exchange(other.m_last, {}); 53 | return *this; 54 | } 55 | 56 | byte_view(uint8_t const* const first, uint8_t const* const last) noexcept : 57 | m_first(first), 58 | m_last(last) 59 | { 60 | } 61 | 62 | auto begin() const noexcept 63 | { 64 | return m_first; 65 | } 66 | 67 | auto end() const noexcept 68 | { 69 | return m_last; 70 | } 71 | 72 | uint32_t size() const noexcept 73 | { 74 | return static_cast(end() - begin()); 75 | } 76 | 77 | explicit operator bool() const noexcept 78 | { 79 | return size() > 0; 80 | } 81 | 82 | byte_view seek(uint32_t const offset) const 83 | { 84 | check_available(offset); 85 | return{ m_first + offset, m_last }; 86 | } 87 | 88 | byte_view sub(uint32_t const offset, uint32_t const size) const 89 | { 90 | check_available(offset + size); 91 | return{ m_first + offset, m_first + offset + size }; 92 | } 93 | 94 | template 95 | T const& as(uint32_t const offset = 0) const 96 | { 97 | check_available(offset + sizeof(T)); 98 | return reinterpret_cast(*(m_first + offset)); 99 | } 100 | 101 | std::string_view as_string(uint32_t const offset = 0) const 102 | { 103 | static_assert(sizeof(uint8_t) == 1); 104 | check_available(offset + 1); 105 | auto const length = as(offset); 106 | if (length == 0) 107 | { 108 | return ""; 109 | } 110 | else if (length == 0xff) 111 | { 112 | return { nullptr, 0 }; 113 | } 114 | else 115 | { 116 | check_available(offset + 1 + length); 117 | return { reinterpret_cast(m_first + offset + 1), length }; 118 | } 119 | } 120 | 121 | std::u16string_view as_u16string_constant() const 122 | { 123 | return { reinterpret_cast(m_first), size() / 2 }; 124 | } 125 | 126 | template 127 | auto as_array(uint32_t const offset, uint32_t const count) const 128 | { 129 | check_available(offset + count * sizeof(T)); 130 | return reinterpret_cast(m_first + offset); 131 | } 132 | 133 | private: 134 | 135 | void check_available(uint32_t const offset) const 136 | { 137 | if (m_first + offset > m_last) 138 | { 139 | impl::throw_invalid("Buffer too small"); 140 | } 141 | } 142 | 143 | uint8_t const* m_first{}; 144 | uint8_t const* m_last{}; 145 | }; 146 | 147 | struct file_view : byte_view 148 | { 149 | file_view(file_view const&) = delete; 150 | file_view& operator=(file_view const&) = delete; 151 | file_view(file_view&&) noexcept = default; 152 | file_view& operator=(file_view&&) noexcept = default; 153 | 154 | file_view(std::string_view const& path) : byte_view{ open_file(path) }, m_backed_by_file{ true } 155 | { 156 | } 157 | 158 | file_view(uint8_t const* const first, uint8_t const* const last) noexcept : byte_view{ first, last }, m_backed_by_file{ false } 159 | { 160 | } 161 | 162 | ~file_view() noexcept 163 | { 164 | if (m_backed_by_file) 165 | { 166 | #if defined(_WIN32) 167 | UnmapViewOfFile(begin()); 168 | #else 169 | munmap(const_cast(reinterpret_cast(begin())), size()); 170 | #endif 171 | } 172 | } 173 | 174 | private: 175 | 176 | bool m_backed_by_file; 177 | 178 | #if defined(_WIN32) 179 | struct handle 180 | { 181 | HANDLE value{}; 182 | 183 | ~handle() noexcept 184 | { 185 | if (value) 186 | { 187 | CloseHandle(value); 188 | } 189 | } 190 | 191 | explicit operator bool() const noexcept 192 | { 193 | return value != 0; 194 | } 195 | }; 196 | #endif 197 | 198 | struct file_handle 199 | { 200 | #if defined(_WIN32) 201 | using handle_type = HANDLE; 202 | #else 203 | using handle_type = int; 204 | static constexpr handle_type INVALID_HANDLE_VALUE = -1; 205 | #endif 206 | 207 | handle_type value{ INVALID_HANDLE_VALUE }; 208 | 209 | ~file_handle() noexcept 210 | { 211 | if (value != INVALID_HANDLE_VALUE) 212 | { 213 | #if defined(_WIN32) 214 | CloseHandle(value); 215 | #else 216 | close(value); 217 | #endif 218 | } 219 | } 220 | 221 | explicit operator bool() const noexcept 222 | { 223 | return value != INVALID_HANDLE_VALUE; 224 | } 225 | }; 226 | 227 | static byte_view open_file(std::string_view const& path) 228 | { 229 | #if defined(_WIN32) 230 | auto input = impl::c_str(path); 231 | 232 | auto const input_length = static_cast(path.length() + 1); 233 | int buffer_length = MultiByteToWideChar(CP_UTF8, 0, input, input_length, 0, 0); 234 | std::vector output = std::vector(buffer_length); 235 | int result = MultiByteToWideChar(CP_UTF8, 0, input, input_length, output.data(), buffer_length); 236 | 237 | if (result == 0) 238 | { 239 | switch (GetLastError()) 240 | { 241 | case ERROR_INSUFFICIENT_BUFFER: 242 | impl::throw_invalid("Insufficient buffer size"); 243 | case ERROR_NO_UNICODE_TRANSLATION: 244 | impl::throw_invalid("Untranslatable path"); 245 | default: 246 | impl::throw_invalid("Could not convert path"); 247 | } 248 | } 249 | 250 | file_handle file{ CreateFile2(output.data(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr) }; 251 | 252 | if (!file) 253 | { 254 | impl::throw_invalid("Could not open file '", path, "'"); 255 | } 256 | 257 | LARGE_INTEGER size{}; 258 | GetFileSizeEx(file.value, &size); 259 | 260 | if (!size.QuadPart) 261 | { 262 | return{}; 263 | } 264 | 265 | handle mapping{ CreateFileMappingW(file.value, nullptr, PAGE_READONLY, 0, 0, nullptr) }; 266 | 267 | if (!mapping) 268 | { 269 | impl::throw_invalid("Could not open file '", path, "'"); 270 | } 271 | 272 | auto const first{ static_cast(MapViewOfFile(mapping.value, FILE_MAP_READ, 0, 0, 0)) }; 273 | return{ first, first + size.QuadPart }; 274 | #else 275 | file_handle file{ open(c_str(path), O_RDONLY, 0) }; 276 | if (!file) 277 | { 278 | throw_invalid("Could not open file '", path, "'"); 279 | } 280 | 281 | struct stat st; 282 | int ret = fstat(file.value, &st); 283 | if (ret < 0) 284 | { 285 | throw_invalid("Could not open file '", path, "'"); 286 | } 287 | if (!st.st_size) 288 | { 289 | return{}; 290 | } 291 | 292 | auto const first = static_cast(mmap(nullptr, st.st_size, PROT_READ, MAP_PRIVATE | MAP_POPULATE, file.value, 0)); 293 | if (first == MAP_FAILED) 294 | { 295 | throw_invalid("Could not open file '", path, "'"); 296 | } 297 | 298 | return{ first, first + st.st_size }; 299 | #endif 300 | } 301 | }; 302 | } 303 | -------------------------------------------------------------------------------- /cppwin32/winmd/readme.md: -------------------------------------------------------------------------------- 1 | This is a fork of https://github.com/microsoft/winmd adding some needed features. Things that weren't needed in winmd for winrt types: 2 | - Reading pointers from signatures (ELEMENT_TYPE_PTR) 3 | - Reading ELEMENT_TYPE_VOID from signatures 4 | - Nested types and the NestedClass table 5 | 6 | So far, these changes are purely additive and won't harm other winmd consumers in any way, and will just improve the completeness of the the winmd library. 7 | 8 | As long as this holds, we should aim to integrate these additions back into winmd. 9 | 10 | One thing to consider is that the support for arrays and pointers in signatures is a little underwhelming, and some aspects of the signature blob design are awkward and wordy. There's a case to be made to revise and improve this part of the winmd library, but we'll have to see if its few consumers can tolerate or welcome such a change. 11 | -------------------------------------------------------------------------------- /cppwin32/winmd/readme.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | Microsoft.Windows.WinMD C++ metadata parsing library 3 | ======================================================================== 4 | 5 | The Microsoft.Windows.WinMD NuGet package provides a pure C++ header metadata parsing library. 6 | Adding a reference to this package adds the library to the project's additional include directories. 7 | 8 | ======================================================================== 9 | For more information, visit: 10 | https://github.com/microsoft/winmd/ 11 | ======================================================================== 12 | -------------------------------------------------------------------------------- /cppwin32/winmd/winmd_reader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "impl/base.h" 4 | #include "impl/winmd_reader/pe.h" 5 | #include "impl/winmd_reader/view.h" 6 | #include "impl/winmd_reader/enum.h" 7 | #include "impl/winmd_reader/enum_traits.h" 8 | #include "impl/winmd_reader/flags.h" 9 | #include "impl/winmd_reader/table.h" 10 | #include "impl/winmd_reader/index.h" 11 | #include "impl/winmd_reader/signature.h" 12 | #include "impl/winmd_reader/schema.h" 13 | #include "impl/winmd_reader/database.h" 14 | #include "impl/winmd_reader/column.h" 15 | #include "impl/winmd_reader/type_helpers.h" 16 | #include "impl/winmd_reader/key.h" 17 | #include "impl/winmd_reader/cache.h" 18 | #include "impl/winmd_reader/filter.h" 19 | #include "impl/winmd_reader/custom_attribute.h" 20 | #include "impl/winmd_reader/helpers.h" 21 | -------------------------------------------------------------------------------- /test/SampleD3DApp/SampleD3DApp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30621.155 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleD3DApp", "SampleD3DApp\SampleD3DApp.vcxproj", "{9A6A1EC0-7A23-49B1-9C43-089C17ED3266}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {9A6A1EC0-7A23-49B1-9C43-089C17ED3266}.Debug|x64.ActiveCfg = Debug|x64 17 | {9A6A1EC0-7A23-49B1-9C43-089C17ED3266}.Debug|x64.Build.0 = Debug|x64 18 | {9A6A1EC0-7A23-49B1-9C43-089C17ED3266}.Debug|x86.ActiveCfg = Debug|Win32 19 | {9A6A1EC0-7A23-49B1-9C43-089C17ED3266}.Debug|x86.Build.0 = Debug|Win32 20 | {9A6A1EC0-7A23-49B1-9C43-089C17ED3266}.Release|x64.ActiveCfg = Release|x64 21 | {9A6A1EC0-7A23-49B1-9C43-089C17ED3266}.Release|x64.Build.0 = Release|x64 22 | {9A6A1EC0-7A23-49B1-9C43-089C17ED3266}.Release|x86.ActiveCfg = Release|Win32 23 | {9A6A1EC0-7A23-49B1-9C43-089C17ED3266}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {17B10698-FE2C-48AB-8546-C08244C57D9D} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /test/SampleD3DApp/SampleD3DApp/D3D12HelloWindow.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "D3D12HelloWindow.h" 4 | 5 | using namespace win32; 6 | using namespace win32::Windows::Win32; 7 | using namespace win32::Windows::Win32::Direct3D12; 8 | using namespace win32::Windows::Win32::SystemServices; 9 | using namespace win32::Windows::Win32::Dxgi; 10 | using namespace win32::Windows::Win32::Direct3D11; 11 | 12 | void D3D12HelloWindow::OnInit() 13 | { 14 | LoadPipeline(); 15 | LoadAssets(); 16 | } 17 | 18 | void D3D12HelloWindow::OnUpdate() 19 | { 20 | 21 | } 22 | 23 | void D3D12HelloWindow::OnRender() 24 | { 25 | 26 | } 27 | void D3D12HelloWindow::OnDestroy() 28 | { 29 | 30 | } 31 | 32 | void D3D12HelloWindow::LoadPipeline() 33 | { 34 | uint32_t dxgiFactoryFlags = 0; 35 | 36 | #if defined(_DEBUG) 37 | com_ptr debugController; 38 | if (D3D12GetDebugInterface((guid*)(&guid_of()), debugController.put_void()).Value == 0) 39 | { 40 | debugController->EnableDebugLayer(); 41 | dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG; 42 | } 43 | #endif 44 | 45 | com_ptr factory; 46 | CreateDXGIFactory2(dxgiFactoryFlags, (guid*)(&guid_of()), factory.put_void()); 47 | 48 | auto adapter = GetHardwareAdapter(factory.get()); 49 | D3D12CreateDevice(adapter.get(), D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_11_0, (guid*)(&guid_of()), m_device.put_void()); 50 | 51 | D3D12_COMMAND_QUEUE_DESC queueDesc{}; 52 | queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAGS::D3D12_COMMAND_QUEUE_FLAG_NONE; 53 | queueDesc.Type = D3D12_COMMAND_LIST_TYPE::D3D12_COMMAND_LIST_TYPE_DIRECT; 54 | 55 | m_device->CreateCommandQueue(&queueDesc, (guid*)(&guid_of()), m_commandQueue.put_void()); 56 | } 57 | 58 | void D3D12HelloWindow::LoadAssets() 59 | { 60 | 61 | } 62 | -------------------------------------------------------------------------------- /test/SampleD3DApp/SampleD3DApp/D3D12HelloWindow.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "DXSample.h" 4 | 5 | struct D3D12HelloWindow : public DXSample 6 | { 7 | using DXSample::DXSample; 8 | 9 | void OnInit() override; 10 | void OnUpdate() override; 11 | void OnRender() override; 12 | void OnDestroy() override; 13 | 14 | private: 15 | win32::com_ptr m_device; 16 | win32::com_ptr m_commandQueue; 17 | uint32_t m_rtvDescriptorSize = 0; 18 | 19 | uint32_t m_frameIndex = 0; 20 | 21 | void LoadPipeline(); 22 | void LoadAssets(); 23 | }; -------------------------------------------------------------------------------- /test/SampleD3DApp/SampleD3DApp/DXSample.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "DXSample.h" 3 | 4 | using namespace win32; 5 | using namespace win32::Windows::Win32; 6 | using namespace win32::Windows::Win32::Dxgi; 7 | using namespace win32::Windows::Win32::SystemServices; 8 | using namespace win32::Windows::Win32::Direct3D12; 9 | using namespace win32::Windows::Win32::Direct3D11; 10 | 11 | win32::com_ptr DXSample::GetHardwareAdapter( 12 | IDXGIFactory1* factory, 13 | bool requestHighPerformanceAdapter) 14 | { 15 | win32::com_ptr adapter; 16 | for (uint32_t adapterIndex = 0; DXGI_ERROR_NOT_FOUND != factory->EnumAdapters1(adapterIndex, adapter.put()).Value; ++adapterIndex, adapter = nullptr) 17 | { 18 | DXGI_ADAPTER_DESC1 desc; 19 | adapter->GetDesc1(&desc); 20 | 21 | if (desc.Flags & (uint32_t)DXGI_ADAPTER_FLAG::DXGI_ADAPTER_FLAG_SOFTWARE) 22 | { 23 | // Don't select the Basic Render Driver adapter. 24 | // If you want a software adapter, pass in "/warp" on the command line. 25 | continue; 26 | } 27 | 28 | // Check to see whether the adapter supports Direct3D 12, but don't create the 29 | // actual device yet. 30 | if (0 == D3D12CreateDevice(adapter.get(), D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_11_0, (guid*)&guid_of(), nullptr).Value) 31 | { 32 | break; 33 | } 34 | } 35 | return adapter; 36 | } 37 | -------------------------------------------------------------------------------- /test/SampleD3DApp/SampleD3DApp/DXSample.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "pch.h" 4 | 5 | struct DXSample 6 | { 7 | DXSample(int32_t width, int32_t height, std::wstring&& title) noexcept 8 | : m_width(width) 9 | , m_height(height) 10 | , m_title(std::move(title)) 11 | { 12 | } 13 | 14 | virtual ~DXSample() noexcept = default; 15 | 16 | virtual void OnInit() = 0; 17 | virtual void OnUpdate() = 0; 18 | virtual void OnRender() = 0; 19 | virtual void OnDestroy() = 0; 20 | 21 | auto Width() const noexcept { return m_width; } 22 | auto Height() const noexcept { return m_height; } 23 | auto const& Title() const noexcept { return m_title; } 24 | 25 | protected: 26 | win32::com_ptr GetHardwareAdapter( 27 | win32::Windows::Win32::Dxgi::IDXGIFactory1* factory, 28 | bool requestHighPerformanceAdapter = false); 29 | 30 | int32_t m_width; 31 | int32_t m_height; 32 | 33 | private: 34 | std::wstring m_title; 35 | }; -------------------------------------------------------------------------------- /test/SampleD3DApp/SampleD3DApp/Main.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "D3D12HelloWindow.h" 3 | 4 | using namespace win32; 5 | using namespace win32::Windows::Win32; 6 | using namespace win32::Windows::Win32::SystemServices; 7 | using namespace win32::Windows::Win32::WindowsAndMessaging; 8 | using namespace win32::Windows::Win32::DisplayDevices; 9 | using namespace win32::Windows::Win32::MenusAndResources; 10 | 11 | LRESULT __stdcall WindowProc(HWND hwnd, uint32_t message, WPARAM wParam, LPARAM lParam); 12 | 13 | int run(DXSample* sample); 14 | 15 | int main() 16 | { 17 | D3D12HelloWindow sample(1280, 720, L"D3D12 Hello Window"); 18 | run(&sample); 19 | } 20 | 21 | int run(DXSample* sample) 22 | { 23 | HINSTANCE hInstance{ GetModuleHandleW(nullptr) }; 24 | 25 | WNDCLASSEXW windowClass{}; 26 | windowClass.cbSize = sizeof(WNDCLASSEXW); 27 | windowClass.style = CS_HREDRAW | CS_VREDRAW; 28 | windowClass.lpfnWndProc = WindowProc; 29 | windowClass.hInstance = hInstance; 30 | windowClass.hCursor = LoadCursorW(HINSTANCE{}, (uint16_t*)(IDC_ARROW)); // Ugly cast tracked by metadata bug https://github.com/microsoft/win32metadata/issues/69 31 | windowClass.lpszClassName = (uint16_t*)(L"DXSampleClass"); 32 | 33 | RegisterClassExW(&windowClass); 34 | 35 | RECT rect{ 0, 0, sample->Width(), sample->Height()}; 36 | AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, BOOL{0}); 37 | 38 | auto hwnd = CreateWindowExW( 39 | 0, 40 | windowClass.lpszClassName, 41 | (uint16_t*)(sample->Title().c_str()), 42 | WS_OVERLAPPEDWINDOW, 43 | CW_USEDEFAULT, 44 | CW_USEDEFAULT, 45 | 640, 46 | 480, 47 | HWND{}, 48 | HMENU{}, 49 | hInstance, 50 | sample); 51 | 52 | sample->OnInit(); 53 | 54 | ShowWindow(hwnd, SW_SHOWDEFAULT); 55 | 56 | MSG msg; 57 | do 58 | { 59 | if (PeekMessageW(&msg, HWND{}, 0, 0, PM_REMOVE).Value != 0) 60 | { 61 | TranslateMessage(&msg); 62 | DispatchMessageW(&msg); 63 | } 64 | } while (msg.message != WM_QUIT); 65 | 66 | sample->OnDestroy(); 67 | 68 | return 0; 69 | } 70 | 71 | LRESULT __stdcall WindowProc(HWND hwnd, uint32_t message, WPARAM wParam, LPARAM lParam) 72 | { 73 | auto sample = reinterpret_cast(GetWindowLongW(hwnd, GWLP_USERDATA)); 74 | 75 | switch (message) 76 | { 77 | case WM_CREATE: 78 | { 79 | auto create_struct = reinterpret_cast(lParam.Value); 80 | SetWindowLongW( 81 | hwnd, 82 | GWLP_USERDATA, 83 | reinterpret_cast(create_struct->lpCreateParams)); 84 | return LRESULT{ 0 }; 85 | } 86 | 87 | case WM_PAINT: 88 | if (sample) 89 | { 90 | sample->OnUpdate(); 91 | sample->OnRender(); 92 | } 93 | return LRESULT{ 0 }; 94 | 95 | case WM_DESTROY: 96 | PostQuitMessage(0); 97 | return LRESULT{ 0 }; 98 | } 99 | return DefWindowProcW(hwnd, message, wParam, lParam); 100 | } 101 | -------------------------------------------------------------------------------- /test/SampleD3DApp/SampleD3DApp/SampleD3DApp.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {9a6a1ec0-7a23-49b1-9c43-089c17ed3266} 25 | SampleD3DApp 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | $(ProjectDir)..\..\..\Generated Files;$(IncludePath) 76 | 77 | 78 | false 79 | $(ProjectDir)..\..\..\Generated Files;$(IncludePath) 80 | 81 | 82 | true 83 | $(ProjectDir)..\..\..\Generated Files;$(IncludePath) 84 | 85 | 86 | false 87 | $(ProjectDir)..\..\..\Generated Files;$(IncludePath) 88 | 89 | 90 | 91 | Level4 92 | true 93 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 94 | true 95 | stdcpp17 96 | Use 97 | pch.h 98 | 99 | 100 | Console 101 | true 102 | d3d12.lib;dxgi.lib;%(AdditionalDependencies) 103 | 104 | 105 | 106 | 107 | Level4 108 | true 109 | true 110 | true 111 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 112 | true 113 | stdcpp17 114 | Use 115 | pch.h 116 | 117 | 118 | Console 119 | true 120 | true 121 | true 122 | d3d12.lib;dxgi.lib;%(AdditionalDependencies) 123 | 124 | 125 | 126 | 127 | Level4 128 | true 129 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 130 | true 131 | stdcpp17 132 | Use 133 | pch.h 134 | 135 | 136 | Console 137 | true 138 | d3d12.lib;dxgi.lib;%(AdditionalDependencies) 139 | 140 | 141 | 142 | 143 | Level4 144 | true 145 | true 146 | true 147 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 148 | true 149 | stdcpp17 150 | Use 151 | pch.h 152 | 153 | 154 | Console 155 | true 156 | true 157 | true 158 | d3d12.lib;dxgi.lib;%(AdditionalDependencies) 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | Create 167 | Create 168 | Create 169 | Create 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /test/SampleD3DApp/SampleD3DApp/SampleD3DApp.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | 32 | 33 | Header Files 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files 40 | 41 | 42 | -------------------------------------------------------------------------------- /test/SampleD3DApp/SampleD3DApp/pch.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | -------------------------------------------------------------------------------- /test/SampleD3DApp/SampleD3DApp/pch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #define IID_PPV_ARGS(ppType) win32::guid_of<**(ppType)>(), IID_PPV_ARGS_Helper(ppType) 14 | -------------------------------------------------------------------------------- /test/Windows.Win32.Interop.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/cppwin32/8a6b2507734dd9e9892059b5794f35109688fc20/test/Windows.Win32.Interop.dll -------------------------------------------------------------------------------- /test/Windows.Win32.winmd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/cppwin32/8a6b2507734dd9e9892059b5794f35109688fc20/test/Windows.Win32.winmd --------------------------------------------------------------------------------