summaryrefslogtreecommitdiff
path: root/src/tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/.gitmirror1
-rw-r--r--src/tools/CMakeLists.txt1
-rw-r--r--src/tools/GenClrDebugResource/.gitmirror1
-rw-r--r--src/tools/GenClrDebugResource/CMakeLists.txt7
-rw-r--r--src/tools/GenClrDebugResource/GenClrDebugResource.cpp219
-rw-r--r--src/tools/GenClrDebugResource/GenClrDebugResource.nativeproj26
-rw-r--r--src/tools/GenClrDebugResource/native.rc7
-rw-r--r--src/tools/InjectResource/.gitmirror1
-rw-r--r--src/tools/InjectResource/CMakeLists.txt10
-rw-r--r--src/tools/InjectResource/InjectResource.cpp158
-rw-r--r--src/tools/InjectResource/InjectResource.nativeproj27
-rw-r--r--src/tools/InjectResource/native.rc7
-rw-r--r--src/tools/crossgen/.gitmirror1
-rw-r--r--src/tools/crossgen/CMakeLists.txt75
-rw-r--r--src/tools/crossgen/Native.rc7
-rw-r--r--src/tools/crossgen/compare.bat186
-rw-r--r--src/tools/crossgen/crossgen.cpp1031
-rw-r--r--src/tools/crossgen/crossgen.nativeproj94
-rw-r--r--src/tools/dirs.proj77
-rw-r--r--src/tools/metainfo/.gitmirrorall1
-rw-r--r--src/tools/metainfo/Native.rc8
-rw-r--r--src/tools/metainfo/mdinfo.cpp4350
-rw-r--r--src/tools/metainfo/mdinfo.h207
-rw-r--r--src/tools/metainfo/mdobj.cpp298
-rw-r--r--src/tools/metainfo/metainfo.cpp190
-rw-r--r--src/tools/metainfo/metainfo.nativeproj42
-rw-r--r--src/tools/util/.gitmirror1
-rw-r--r--src/tools/util/consoleargs.cpp958
-rw-r--r--src/tools/util/consoleargs.h72
-rw-r--r--src/tools/util/file_can.h69
-rw-r--r--src/tools/util/list.h25
-rw-r--r--src/tools/util/tree.h242
32 files changed, 8399 insertions, 0 deletions
diff --git a/src/tools/.gitmirror b/src/tools/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/tools/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt
new file mode 100644
index 0000000000..5443e0ddb6
--- /dev/null
+++ b/src/tools/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(crossgen)
diff --git a/src/tools/GenClrDebugResource/.gitmirror b/src/tools/GenClrDebugResource/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/tools/GenClrDebugResource/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/tools/GenClrDebugResource/CMakeLists.txt b/src/tools/GenClrDebugResource/CMakeLists.txt
new file mode 100644
index 0000000000..ad2598a373
--- /dev/null
+++ b/src/tools/GenClrDebugResource/CMakeLists.txt
@@ -0,0 +1,7 @@
+add_definitions(-MT)
+add_executable(GenClrDebugResource GenClrDebugResource.cpp)
+
+target_link_libraries(GenClrDebugResource
+ ${STATIC_MT_CRT_LIB}
+ ${STATIC_MT_VCRT_LIB}
+)
diff --git a/src/tools/GenClrDebugResource/GenClrDebugResource.cpp b/src/tools/GenClrDebugResource/GenClrDebugResource.cpp
new file mode 100644
index 0000000000..de016de845
--- /dev/null
+++ b/src/tools/GenClrDebugResource/GenClrDebugResource.cpp
@@ -0,0 +1,219 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/* This app writes out the data for a special resource which is embedded in clr.dll
+ * The resource serves two purposes, to differentiate a random dll named clr.dll from
+ * an official microsoft clr dll (it isn't foolproof but it should prevent anyone from
+ * accidentally appearing to be a clr) and to provide file information about DAC and DBI
+ * which correspond to this build of the CLR.
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <windows.h>
+#include <clrinternal.h>
+
+char* g_appName;
+
+
+struct ClrDebugResource
+{
+ DWORD dwVersion;
+ GUID signature;
+ DWORD dwDacTimeStamp;
+ DWORD dwDacSizeOfImage;
+ DWORD dwDbiTimeStamp;
+ DWORD dwDbiSizeOfImage;
+};
+
+BOOL
+GetBinFileData(__in_z char* binFileName, DWORD* pTimeStamp, DWORD* pSizeOfImage)
+{
+ HANDLE binFileHandle;
+ DWORD peHeaderOffset;
+ ULONG done;
+
+ binFileHandle = CreateFileA(binFileName, GENERIC_READ, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, 0, NULL);
+ if (!binFileHandle || binFileHandle == INVALID_HANDLE_VALUE)
+ {
+ printf("%s: Unable to open '%s', %d\n", g_appName,
+ binFileName, GetLastError());
+ goto error;
+ }
+
+ // Read the 4 byte value at 0x3c, which is the offset to PE header
+ if (INVALID_SET_FILE_POINTER == SetFilePointer(binFileHandle, 0x3c, NULL, FILE_BEGIN))
+ {
+ printf("%s: Unable to move file pointer '%s', %d\n", g_appName,
+ binFileName, GetLastError());
+ goto error;
+ }
+
+ if (!ReadFile(binFileHandle, &peHeaderOffset, 4, &done, NULL) ||
+ done != 4)
+ {
+ printf("%s: Unable to read '%s', %d\n", g_appName,
+ binFileName, GetLastError());
+ goto error;
+ }
+
+ // Read the 4 byte value at 8 bytes after peHeader, that is the timestamp
+ if (INVALID_SET_FILE_POINTER == SetFilePointer(binFileHandle, peHeaderOffset + 8, NULL, FILE_BEGIN))
+ {
+ printf("%s: Unable to move file pointer '%s', %d\n", g_appName,
+ binFileName, GetLastError());
+ goto error;
+ }
+
+ if (!ReadFile(binFileHandle, pTimeStamp, 4, &done, NULL) ||
+ done != 4)
+ {
+ printf("%s: Unable to read '%s', %d\n", g_appName,
+ binFileName, GetLastError());
+ goto error;
+ }
+
+ // Read the 4 byte value at 80 bytes after peHeader, that is the sizeOfImage
+ if (INVALID_SET_FILE_POINTER == SetFilePointer(binFileHandle, peHeaderOffset + 80, NULL, FILE_BEGIN))
+ {
+ printf("%s: Unable to move file pointer '%s', %d\n", g_appName,
+ binFileName, GetLastError());
+ goto error;
+ }
+
+ if (!ReadFile(binFileHandle, pSizeOfImage, 4, &done, NULL) ||
+ done != 4)
+ {
+ printf("%s: Unable to read '%s', %d\n", g_appName,
+ binFileName, GetLastError());
+ goto error;
+ }
+
+ CloseHandle(binFileHandle);
+ return TRUE;
+
+error:
+ CloseHandle(binFileHandle);
+ return FALSE;
+}
+
+void
+Usage(void)
+{
+ printf("Usage: %s [options]\n", g_appName);
+ printf("Options are:\n");
+ printf(" /out:<file> - output binary file that contains the raw resource data\n");
+ printf(" /dac:<file> - path to mscordacwks that should be referenced\n");
+ printf(" /dbi:<file> - path to mscordbi that should be referenced\n");
+ printf(" /sku:<sku_name> - Either clr, coreclr, or phoneclr indicating the CLR sku\n");
+}
+
+void __cdecl
+main(int argc, __in_z char** argv)
+{
+ char* outFile = NULL;
+ char* dacFile = NULL;
+ char* dbiFile = NULL;
+ char* sku = NULL;
+
+ g_appName = argv[0];
+
+ while (--argc)
+ {
+ argv++;
+
+ if (!strncmp(*argv, "/out:", 5))
+ {
+ outFile = *argv + 5;
+ }
+ else if (!strncmp(*argv, "/dac:", 5))
+ {
+ dacFile = *argv + 5;
+ }
+ else if (!strncmp(*argv, "/dbi:", 5))
+ {
+ dbiFile = *argv + 5;
+ }
+ else if (!strncmp(*argv, "/sku:", 5))
+ {
+ sku = *argv + 5;
+ }
+ else
+ {
+ Usage();
+ exit(1);
+ }
+ }
+
+ if (!outFile || !dacFile || !dbiFile || !sku)
+ {
+ Usage();
+ exit(1);
+ }
+
+ ClrDebugResource res;
+ res.dwVersion = 0;
+
+ if(strcmp(sku, "clr")==0)
+ {
+ res.signature = CLR_ID_V4_DESKTOP;
+ }
+ else if(strcmp(sku, "coreclr")==0)
+ {
+ res.signature = CLR_ID_CORECLR;
+ }
+ else if(strcmp(sku, "phoneclr")==0)
+ {
+ res.signature = CLR_ID_PHONE_CLR;
+ }
+ else if (strcmp(sku, "onecoreclr") == 0)
+ {
+ res.signature = CLR_ID_ONECORE_CLR;
+ }
+ else
+ {
+ printf("Error: Unrecognized sku option: %s\n", sku);
+ Usage();
+ exit(1);
+ }
+
+ printf("%s: Reading data from DAC: %s\n", g_appName, dacFile);
+ if(!GetBinFileData(dacFile, &(res.dwDacTimeStamp), &(res.dwDacSizeOfImage)))
+ exit(1);
+ printf("%s: DAC timeStamp = 0x%x sizeOfImage = 0x%x\n", g_appName, res.dwDacTimeStamp, res.dwDacSizeOfImage);
+
+ printf("%s: Reading data from DBI: %s\n", g_appName, dbiFile);
+ if(!GetBinFileData(dbiFile, &(res.dwDbiTimeStamp), &(res.dwDbiSizeOfImage)))
+ exit(1);
+ printf("%s: DBI timeStamp = 0x%x sizeOfImage = 0x%x\n", g_appName, res.dwDbiTimeStamp, res.dwDbiSizeOfImage);
+
+ printf("%s: Writing binary resource file: %s\n", g_appName, outFile);
+ HANDLE outFileHandle = CreateFileA(outFile, GENERIC_WRITE, 0,
+ NULL, CREATE_ALWAYS, 0, NULL);
+ if (!outFileHandle || outFileHandle == INVALID_HANDLE_VALUE)
+ {
+ printf("%s: Unable to create '%s', %d\n",
+ g_appName, outFile, GetLastError());
+ goto error;
+ }
+
+
+ DWORD done = 0;
+ if(!WriteFile(outFileHandle, &res, sizeof(res), &done, NULL) || done != sizeof(res))
+ {
+ printf("%s: Unable to write file data '%s', %d\n",
+ g_appName, outFile, GetLastError());
+ goto error;
+ }
+
+ CloseHandle(outFileHandle);
+ printf("%s: Success. Returning 0\n", g_appName);
+ exit(0);
+
+error:
+ CloseHandle(outFileHandle);
+ exit(1);
+}
diff --git a/src/tools/GenClrDebugResource/GenClrDebugResource.nativeproj b/src/tools/GenClrDebugResource/GenClrDebugResource.nativeproj
new file mode 100644
index 0000000000..9bd544d8d0
--- /dev/null
+++ b/src/tools/GenClrDebugResource/GenClrDebugResource.nativeproj
@@ -0,0 +1,26 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <!--*****************************************************-->
+ <!--This MSBuild project file was automatically generated-->
+ <!--from the original SOURCES/DIRS file by the KBC tool.-->
+ <!--*****************************************************-->
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+ <!--Leaf project Properties-->
+ <PropertyGroup>
+ <OutputName>GenClrDebugResource</OutputName>
+ <TargetType>PROGRAM</TargetType>
+ <LinkSubsystem>console</LinkSubsystem>
+ <LinkGenerateManifest>true</LinkGenerateManifest>
+ <LinkAdditionalOptions>$(LinkAdditionalOptions) /MANIFEST</LinkAdditionalOptions>
+ <UseMsvcrt>false</UseMsvcrt>
+ </PropertyGroup>
+ <!--Leaf Project Items-->
+ <ItemGroup>
+ <CppCompile Include="GenClrDebugResource.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <RCResourceFile Include="native.rc" />
+ </ItemGroup>
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" />
+</Project> \ No newline at end of file
diff --git a/src/tools/GenClrDebugResource/native.rc b/src/tools/GenClrDebugResource/native.rc
new file mode 100644
index 0000000000..4c1007fd9a
--- /dev/null
+++ b/src/tools/GenClrDebugResource/native.rc
@@ -0,0 +1,7 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+#define FX_VER_FILEDESCRIPTION_STR "Microsoft\0"
+
+#include <fxver.h>
+#include <fxver.rc>
diff --git a/src/tools/InjectResource/.gitmirror b/src/tools/InjectResource/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/tools/InjectResource/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/tools/InjectResource/CMakeLists.txt b/src/tools/InjectResource/CMakeLists.txt
new file mode 100644
index 0000000000..a4fd538662
--- /dev/null
+++ b/src/tools/InjectResource/CMakeLists.txt
@@ -0,0 +1,10 @@
+remove_definitions(-DUNICODE)
+remove_definitions(-D_UNICODE)
+add_definitions(-MT)
+
+add_executable(InjectResource InjectResource.cpp)
+
+target_link_libraries(InjectResource
+ ${STATIC_MT_CRT_LIB}
+ ${STATIC_MT_VCRT_LIB}
+) \ No newline at end of file
diff --git a/src/tools/InjectResource/InjectResource.cpp b/src/tools/InjectResource/InjectResource.cpp
new file mode 100644
index 0000000000..1d5470f3f9
--- /dev/null
+++ b/src/tools/InjectResource/InjectResource.cpp
@@ -0,0 +1,158 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <windows.h>
+#include <daccess.h>
+
+char* g_appName;
+
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+
+void
+AddBinaryResourceToDll(__in_z char* dllName,
+ __in_z char* resName,
+ PVOID resData,
+ ULONG resDataSize)
+{
+ // a retry loop in case we get transient file access issues
+ // does exponential backoff with retries after 1,2,4,8,16, and 32 seconds
+ for(int seconds = 0; seconds < 60; seconds = MAX(seconds*2,1))
+ {
+ if(seconds != 0)
+ Sleep(seconds * 1000);
+
+ HANDLE dllUpdate = BeginUpdateResourceA(dllName, FALSE);
+ if (!dllUpdate)
+ {
+ printf("Unable to open '%s' for update, error=%d\n",
+ dllName, GetLastError());
+ continue;
+ }
+
+ if (!UpdateResourceA(dllUpdate,
+ RT_RCDATA,
+ resName,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
+ resData,
+ resDataSize))
+ {
+ printf("Unable to update '%s', error=%d\n",
+ dllName, GetLastError());
+ continue;
+ }
+
+ if(!EndUpdateResource(dllUpdate, FALSE))
+ {
+ printf("Unable to write updates to '%s', error=%d\n",
+ dllName, GetLastError());
+ continue;
+ }
+
+ return;
+ }
+
+ printf("Stopping after excessive failures\n");
+ exit(1);
+}
+
+void
+GetBinFileData(__in_z char* binFileName, PVOID* binData, PULONG binDataSize)
+{
+ HANDLE binFileHandle;
+ PVOID data;
+ ULONG size, done;
+
+ binFileHandle = CreateFileA(binFileName, GENERIC_READ, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, 0, NULL);
+ if (!binFileHandle || binFileHandle == INVALID_HANDLE_VALUE)
+ {
+ printf("Unable to open '%s', %d\n",
+ binFileName, GetLastError());
+ exit(1);
+ }
+
+ size = GetFileSize(binFileHandle, NULL);
+ data = malloc(size);
+ if (!data)
+ {
+ printf("Out of memory\n");
+ exit(1);
+ }
+
+ if (!ReadFile(binFileHandle, data, size, &done, NULL) ||
+ done != size)
+ {
+ printf("Unable to read '%s', %d\n",
+ binFileName, GetLastError());
+ exit(1);
+ }
+
+ CloseHandle(binFileHandle);
+
+ *binData = data;
+ *binDataSize = size;
+}
+
+void
+Usage(void)
+{
+ printf("Usage: %s [options]\n", g_appName);
+ printf("Options are:\n");
+ printf(" /bin:<file> - Binary data to attach to DLL\n");
+ printf(" /dll:<file> - DLL to modify\n");
+ printf(" /name:<name> - resource name [Optional]\n");
+ exit(1);
+}
+
+void __cdecl
+main(int argc, __in_z char** argv)
+{
+ char* binFile = NULL;
+ char* dllFile = NULL;
+ char* resName = NULL;
+
+ g_appName = argv[0];
+
+ while (--argc)
+ {
+ argv++;
+
+ if (!strncmp(*argv, "/bin:", 5))
+ {
+ binFile = *argv + 5;
+ }
+ else if (!strncmp(*argv, "/dll:", 5))
+ {
+ dllFile = *argv + 5;
+ }
+ else if (!strncmp(*argv, "/name:", 6))
+ {
+ resName = *argv + 6;
+ }
+ else
+ {
+ Usage();
+ }
+ }
+
+ if (!binFile || !dllFile)
+ {
+ Usage();
+ }
+
+ PVOID resData;
+ ULONG resDataSize;
+
+ GetBinFileData(binFile, &resData, &resDataSize);
+
+ AddBinaryResourceToDll(dllFile, resName?resName:DACCESS_TABLE_RESOURCE,
+ resData, resDataSize);
+
+ free(resData);
+
+ printf("Updated %s\n", dllFile);
+}
diff --git a/src/tools/InjectResource/InjectResource.nativeproj b/src/tools/InjectResource/InjectResource.nativeproj
new file mode 100644
index 0000000000..057d01f4ec
--- /dev/null
+++ b/src/tools/InjectResource/InjectResource.nativeproj
@@ -0,0 +1,27 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <!--*****************************************************-->
+ <!--This MSBuild project file was automatically generated-->
+ <!--from the original SOURCES/DIRS file by the KBC tool.-->
+ <!--*****************************************************-->
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+ <!--Leaf project Properties-->
+ <PropertyGroup>
+ <OutputName>InjectResource</OutputName>
+ <TargetType>PROGRAM</TargetType>
+ <LinkSubsystem>console</LinkSubsystem>
+ <BinplaceSymbols>true</BinplaceSymbols>
+ <LinkGenerateManifest>true</LinkGenerateManifest>
+ <LinkAdditionalOptions>$(LinkAdditionalOptions) /MANIFEST</LinkAdditionalOptions>
+ <UseMsvcrt>false</UseMsvcrt>
+ </PropertyGroup>
+ <!--Leaf Project Items-->
+ <ItemGroup>
+ <CppCompile Include="InjectResource.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <RCResourceFile Include="native.rc" />
+ </ItemGroup>
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" />
+</Project> \ No newline at end of file
diff --git a/src/tools/InjectResource/native.rc b/src/tools/InjectResource/native.rc
new file mode 100644
index 0000000000..4c1007fd9a
--- /dev/null
+++ b/src/tools/InjectResource/native.rc
@@ -0,0 +1,7 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+#define FX_VER_FILEDESCRIPTION_STR "Microsoft\0"
+
+#include <fxver.h>
+#include <fxver.rc>
diff --git a/src/tools/crossgen/.gitmirror b/src/tools/crossgen/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/tools/crossgen/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/tools/crossgen/CMakeLists.txt b/src/tools/crossgen/CMakeLists.txt
new file mode 100644
index 0000000000..3b9c5ba8db
--- /dev/null
+++ b/src/tools/crossgen/CMakeLists.txt
@@ -0,0 +1,75 @@
+project(crossgen)
+
+include(${CLR_DIR}/crossgen.cmake)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+include_directories(../util)
+include_directories(../../pal/prebuilt/corerror)
+
+set(crossgen_SOURCES crossgen.cpp ../util/consoleargs.cpp)
+if(WIN32)
+ set(crossgen_RESOURCES Native.rc)
+ add_definitions(-D_CRT_NON_CONFORMING_WCSTOK)
+endif()
+
+if(CLR_CMAKE_PLATFORM_UNIX)
+ add_compile_options(-fPIE)
+ add_definitions(-DNO_NGENPDB)
+endif(CLR_CMAKE_PLATFORM_UNIX)
+
+add_definitions(-DFX_VER_INTERNALNAME_STR=crossgen.exe)
+
+add_executable_clr(crossgen
+ ${crossgen_SOURCES}
+ ${crossgen_RESOURCES}
+)
+
+if(FEATURE_MERGE_JIT_AND_ENGINE)
+ set(CLRJIT_CROSSGEN clrjit_crossgen)
+endif(FEATURE_MERGE_JIT_AND_ENGINE)
+
+target_link_libraries(crossgen
+ cee_crossgen
+ mdcompiler_crossgen
+ mdruntime_crossgen
+ mdruntimerw_crossgen
+ mdhotdata_crossgen
+ corguids
+ ${CLRJIT_CROSSGEN}
+ gcinfo_crossgen
+ corzap_crossgen
+ mscorlib_crossgen
+ strongname_crossgen
+ utilcode_crossgen
+ v3binder_crossgen
+)
+
+if(CLR_CMAKE_PLATFORM_UNIX)
+ target_link_libraries(crossgen
+ mscorrc_debug
+ coreclrpal
+ palrt
+ )
+else()
+ target_link_libraries(crossgen
+ advapi32
+ ole32
+ oleaut32
+ uuid
+ user32
+ version
+ shlwapi
+ bcrypt
+ mdwinmd_crossgen
+ ${STATIC_MT_CRT_LIB}
+ ${STATIC_MT_VCRT_LIB}
+ )
+
+endif(CLR_CMAKE_PLATFORM_UNIX)
+
+add_subdirectory(../../zap/crossgen ../../zap/crossgen)
+add_subdirectory(../../vm/crossgen ../../vm/crossgen)
+add_subdirectory(../../vm/crossgen_mscorlib ../../vm/crossgen_mscorlib)
+
+# add the install targets
+install_clr(crossgen)
diff --git a/src/tools/crossgen/Native.rc b/src/tools/crossgen/Native.rc
new file mode 100644
index 0000000000..25b5fe5e67
--- /dev/null
+++ b/src/tools/crossgen/Native.rc
@@ -0,0 +1,7 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#define FX_VER_FILEDESCRIPTION_STR "Microsoft Common Language Runtime native cross compiler\0"
+
+#include "..\..\dlls\mscorrc\mscorrc.rc"
diff --git a/src/tools/crossgen/compare.bat b/src/tools/crossgen/compare.bat
new file mode 100644
index 0000000000..290cc06fc0
--- /dev/null
+++ b/src/tools/crossgen/compare.bat
@@ -0,0 +1,186 @@
+::mscorlib
+::System
+::System.Core
+::System.Xml
+::System.Configuration
+::System.Drawing
+::System.Data
+::System.Windows.Forms
+::System.Runtime.Remoting
+::System.Serviceprocess
+::System.Management
+::Accessibility
+::Microsoft.VisualBasic
+::System.DirectoryServices
+::System.Transactions
+::System.Web.Services
+::CustomMarshalers
+::System.Configuration.Install
+::System.Xaml
+::WindowsBase
+::System.Net.Http
+::System.Xml.Linq
+::System.Runtime.WindowsRuntime
+::System.Runtime.WindowsRuntime.UI.Xaml
+::System.Runtime.Serialization
+::System.ServiceModel
+::PresentationCore
+::PresentationFramework
+::System.EnterpriseServices
+::System.Collections.Concurrent
+::System.Collections
+::System.ComponentModel.Annotations
+::System.ComponentModel
+::System.ComponentModel.EventBasedAsync
+::System.Diagnostics.Contracts
+::System.Diagnostics.Debug
+::System.Diagnostics.Tools
+::System.Diagnostics.Tracing
+::System.Dynamic.Runtime
+::System.Globalization
+::System.IO
+::System.Linq
+::System.Linq.Expressions
+::System.Linq.Parallel
+::System.Linq.Queryable
+::System.Net.Http.Rtc
+::System.Net.NetworkInformation
+::System.Net.Primitives
+::System.Net.Requests
+::System.ObjectModel
+::System.Reflection
+::System.Reflection.Emit
+::System.Reflection.Emit.ILGeneration
+::System.Reflection.Emit.Lightweight
+::System.Reflection.Extensions
+::System.Reflection.Primitives
+::System.Resources.ResourceManager
+::System.Runtime
+::System.Runtime.Extensions
+::System.Runtime.InteropServices
+::System.Runtime.InteropServices.WindowsRuntime
+::System.Runtime.Numerics
+::System.Runtime.Serialization.Json
+::System.Runtime.Serialization.Primitives
+::System.Runtime.Serialization.Xml
+::System.Security.Principal
+::System.ServiceModel.Duplex
+::System.ServiceModel.Http
+::System.ServiceModel.NetTcp
+::System.ServiceModel.Primitives
+::System.ServiceModel.Security
+::System.Text.Encoding
+::System.Text.Encoding.Extensions
+::System.Text.RegularExpressions
+::System.Threading
+::System.Threading.Tasks
+::System.Threading.Tasks.Parallel
+::System.Windows
+::System.Xml.ReaderWriter
+::System.Xml.XDocument
+::System.Xml.XmlSerializer
+::Windows.ApplicationModel
+::Windows.Data
+::Windows.Devices
+::Windows.Foundation
+::Windows.Globalization
+::Windows.Graphics
+::Windows.Management
+::Windows.Media
+::Windows.Networking
+::Windows.Security
+::Windows.Storage
+::Windows.System
+::Windows.UI
+::Windows.UI.Xaml
+::Windows.Web
+::END_OF_LIST
+
+@echo off
+
+rem
+rem This script compares ngen and crossgen output for framework assemblies
+rem
+
+SETLOCAL ENABLEDELAYEDEXPANSION
+
+set BITNESS=
+IF /I "%_BuildArch%" == "amd64" set BITNESS=64
+set FRAMEWORKDIR=%SYSTEMROOT%\Microsoft.NET\Framework%BITNESS%\%COMPlus_Version%
+IF "%BITNESS%" == "" set BITNESS=32
+
+set NATIVEIMAGEPATH=%FRAMEWORKDIR%\assembly\NativeImages_%COMPlus_Version%_%BITNESS%
+
+rem rmdir /S /Q %NATIVEIMAGEPATH%
+rem %FRAMEWORKDIR%\ngen install mscorlib
+rem %FRAMEWORKDIR%\ngen update
+
+%FRAMEWORKDIR%\gacutil /if %_NTTREE%\System.Runtime.WindowsRuntime.dll
+%FRAMEWORKDIR%\gacutil /if %_NTTREE%\System.Runtime.WindowsRuntime.UI.Xaml.dll
+
+set ILIMAGEPATH=%_NTTREE%\il
+rmdir /S /Q %ILIMAGEPATH%
+if not exist %ILIMAGEPATH% mkdir %ILIMAGEPATH%
+
+rem Collect all files from the GAC into ILIMAGEPATH directory to guaranteed that we get the exact same IL images
+rem between ngen and crossgen. It is important on non-x86 builds because of non-x86 layouts pull files from x86 build.
+forfiles /P %FRAMEWORKDIR%\assembly\GAC_%BITNESS% /M *.dll /S /C "cmd /c copy @path %ILIMAGEPATH%\@file > nul"
+forfiles /P %FRAMEWORKDIR%\assembly\GAC_MSIL /M *.dll /S /C "cmd /c copy @path %ILIMAGEPATH%\@file > nul"
+rem clr.dll and clrjit.dll are required for timestamps
+copy %FRAMEWORKDIR%\clr.dll %ILIMAGEPATH%\clr.dll >nul
+copy %FRAMEWORKDIR%\clrjit.dll %ILIMAGEPATH%\clrjit.dll >nul
+
+set CROSSGENIMAGEPATH=%_NTTREE%\ni
+rmdir /S /Q %CROSSGENIMAGEPATH%
+if not exist %CROSSGENIMAGEPATH% mkdir %CROSSGENIMAGEPATH%
+
+set WINMDPATH=%WINDIR%\System32\WinMetadata
+
+set SELF=%~fd0
+set FAILED=
+
+for /f "eol=; usebackq tokens=1,2,3* delims=,:" %%I in ("%SELF%") DO (
+ if "%%I"=="END_OF_LIST" goto LDone
+ call :ProcessFile %%I
+ if "!FAILED!"=="1" goto LFailed
+)
+
+:LDone
+echo DONE
+exit /B 0
+
+:LFailed
+echo FAILED
+exit /B 1
+
+:ProcessFile
+
+set FILEPATH=
+call :ProbeFile %ILIMAGEPATH%\%1.dll
+call :ProbeFile %WINMDPATH%\%1.winmd
+
+if "%FILEPATH%" == "" ( echo File not found: %1 & goto LError )
+
+echo.
+echo ========= COMPILE and COMPARE %1 ==========
+echo ngen install /nodependencies %FILEPATH%
+ngen install /nodependencies %FILEPATH%
+echo.
+echo %_NTTREE%\crossgen /platform_assemblies_paths %ILIMAGEPATH%;%CROSSGENIMAGEPATH% /Platform_Winmd_Paths %WINMDPATH% /in %FILEPATH% /out %CROSSGENIMAGEPATH%\%1.ni.dll
+%_NTTREE%\crossgen /platform_assemblies_paths %ILIMAGEPATH%;%CROSSGENIMAGEPATH% /Platform_Winmd_Paths %WINMDPATH% /in %FILEPATH% /out %CROSSGENIMAGEPATH%\%1.ni.dll
+IF NOT "%ERRORLEVEL%"=="0" set FAILED=1
+echo.
+forfiles /P %NATIVEIMAGEPATH% /M %1.ni.dll /S /C "cmd /c echo Compare: @path & fc /B @path %CROSSGENIMAGEPATH%\%1.ni.dll > %CROSSGENIMAGEPATH%\diff.txt & IF NOT ERRORLEVEL 1 del %CROSSGENIMAGEPATH%\diff.txt"
+IF not exist %CROSSGENIMAGEPATH%\diff.txt goto LExit
+echo ----- DIFFERENT -----
+:LError
+set FAILED=1
+goto LExit
+
+:ProbeFile
+if NOT "%FILEPATH%" == "" goto LExit
+if NOT exist "%1" goto LExit
+set FILEPATH=%1
+goto LExit
+
+:LExit
diff --git a/src/tools/crossgen/crossgen.cpp b/src/tools/crossgen/crossgen.cpp
new file mode 100644
index 0000000000..960bcf51cd
--- /dev/null
+++ b/src/tools/crossgen/crossgen.cpp
@@ -0,0 +1,1031 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+// TO DO: we currently use raw printf() for output. Maybe we need to pick up something like ngen's Output() handling
+// to handle multiple code pages, etc, better.
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <io.h>
+
+#include <windows.h>
+#include <fxver.h>
+#include <mscorsvc.h>
+
+#include "palclr.h"
+
+#include <sstring.h>
+#include "ex.h"
+
+#include "coregen.h"
+#include "consoleargs.h"
+
+// Return values from wmain() in case of error
+enum ReturnValues
+{
+ FAILURE_RESULT = 1,
+ CLR_INIT_ERROR = -2,
+ ASSEMBLY_NOT_FOUND = -3,
+ INVALID_ARGUMENTS = -4
+};
+
+#define NumItems(s) (sizeof(s) / sizeof(s[0]))
+
+STDAPI CreatePDBWorker(LPCWSTR pwzAssemblyPath, LPCWSTR pwzPlatformAssembliesPaths, LPCWSTR pwzTrustedPlatformAssemblies, LPCWSTR pwzPlatformResourceRoots, LPCWSTR pwzAppPaths, LPCWSTR pwzAppNiPaths, LPCWSTR pwzPdbPath, BOOL fGeneratePDBLinesInfo, LPCWSTR pwzManagedPdbSearchPath, LPCWSTR pwzPlatformWinmdPaths, LPCWSTR pwzDiasymreaderPath);
+STDAPI NGenWorker(LPCWSTR pwzFilename, DWORD dwFlags, LPCWSTR pwzPlatformAssembliesPaths, LPCWSTR pwzTrustedPlatformAssemblies, LPCWSTR pwzPlatformResourceRoots, LPCWSTR pwzAppPaths, LPCWSTR pwzOutputFilename=NULL, LPCWSTR pwzPlatformWinmdPaths=NULL, ICorSvcLogger *pLogger = NULL, LPCWSTR pwszCLRJITPath = nullptr);
+void SetSvcLogger(ICorSvcLogger *pCorSvcLogger);
+#ifdef FEATURE_CORECLR
+void SetMscorlibPath(LPCWSTR wzSystemDirectory);
+#endif
+
+/* --------------------------------------------------------------------------- *
+ * Console stuff
+ * --------------------------------------------------------------------------- */
+
+void Output(LPCWSTR str)
+{
+ wprintf(W("%s"), str);
+}
+
+void Outputf(LPCWSTR szFormat, ...)
+{
+ va_list args;
+ va_start(args, szFormat);
+ vfwprintf(stdout, szFormat, args);
+ va_end(args);
+}
+
+void OutputErr(LPCWSTR str)
+{
+ fwprintf(stderr, W("%s"), str);
+}
+
+void OutputErrf(LPCWSTR szFormat, ...)
+{
+ va_list args;
+ va_start(args, szFormat);
+ vfwprintf(stderr, szFormat, args);
+ va_end(args);
+}
+
+void ErrorHR(HRESULT hr)
+{
+ OutputErrf(W("Error: failed to initialize CoreCLR: 0x%08x\n"), hr);
+}
+
+void ErrorWin32(DWORD err)
+{
+ ErrorHR(HRESULT_FROM_WIN32(err));
+}
+
+// Some error messages are useless to callers, so make them generic, except in debug builds, where we want as much
+// information as possible.
+
+#ifdef _DEBUG
+#define ERROR_HR(msg,hr) Outputf(msg, hr)
+#define ERROR_WIN32(msg,err) Outputf(msg, err)
+#else // _DEBUG
+#define ERROR_HR(msg,hr) ErrorHR(hr)
+#define ERROR_WIN32(msg,err) ErrorWin32(err)
+#endif // _DEBUG
+
+
+void PrintLogoHelper()
+{
+#ifdef FEATURE_CORECLR
+ Output(W("Microsoft (R) CoreCLR Native Image "));
+#else
+ Output(W("Microsoft (R) CLR Native Image "));
+#endif
+ Outputf(W("Generator - Version %S\n"), VER_FILEVERSION_STR);
+ Outputf(W("%S\n"), VER_LEGALCOPYRIGHT_LOGO_STR);
+ Output(W("\n"));
+}
+
+void PrintUsageHelper()
+{
+ // Always print the logo when we print the usage, even if they've specified /nologo and we've parsed that already.
+ PrintLogoHelper();
+
+ Output(
+ W("Usage: crossgen [args] <assembly name>\n")
+ W("\n")
+ W(" /? or /help - Display this screen\n")
+ W(" /nologo - Prevents displaying the logo\n")
+ W(" @response.rsp - Process command line arguments from specified\n")
+ W(" response file\n")
+#ifdef FEATURE_CORECLR
+ W(" /partialtrust - Assembly will be run in a partial trust domain.\n")
+#endif
+ W(" /in <file> - Specifies input filename (optional)\n")
+ W(" /out <file> - Specifies output filename (optional)\n")
+#ifdef FEATURE_CORECLR
+ W(" /Trusted_Platform_Assemblies <path[;path]>\n")
+ W(" - List of assemblies treated as trusted platform\n")
+ W(" - Cannot be used with Platform_Assemblies_Paths\n")
+ W(" /Platform_Resource_Roots <path[;path]>\n")
+ W(" - List of paths containing localized assembly directories\n")
+ W(" /App_Paths <path> - List of paths containing user-application assemblies and resources\n")
+#ifndef NO_NGENPDB
+ W(" /App_Ni_Paths <path[;path]>\n")
+ W(" - List of paths containing user-application native images\n")
+ W(" - Must be used with /CreatePDB switch\n")
+#endif // NO_NGENPDB
+#endif // FEATURE_CORECLR
+
+ W(" /Platform_Assemblies_Paths\n")
+ W(" - List of paths containing target platform assemblies\n")
+#ifdef FEATURE_CORECLR
+ // If Platform_Assemblies_Paths, we will use it to build the TPA list and thus,
+ // TPA list cannot be explicitly specified.
+ W(" - Cannot be used with Trusted_Platform_Assemblies\n")
+#endif // FEATURE_CORECLR
+
+#ifdef FEATURE_COMINTEROP
+ W(" /Platform_Winmd_Paths\n")
+ W(" - List of paths containing target platform WinMDs used\n")
+ W(" for emulating RoResolveNamespace\n")
+#endif
+ W(" /MissingDependenciesOK\n")
+ W(" - Specifies that crossgen should attempt not to fail\n")
+ W(" if a dependency is missing.\n")
+#if 0
+ W(" /Tuning - Generate an instrumented image to collect\n")
+ W(" scenario traces, which can be used with ibcmerge.exe\n")
+#endif
+#if defined(FEATURE_CORECLR) && !defined(FEATURE_MERGE_JIT_AND_ENGINE)
+ W(" /JITPath\n")
+ W(" - Specifies the absolute file path to JIT compiler to be used.\n")
+#endif // defined(FEATURE_CORECLR) && !defined(FEATURE_MERGE_JIT_AND_ENGINE)
+#ifdef FEATURE_READYTORUN_COMPILER
+ W(" /ReadyToRun - Generate images resilient to the runtime and\n")
+ W(" dependency versions\n")
+#endif
+#ifdef FEATURE_WINMD_RESILIENT
+ W(" WinMD Parameters\n")
+ W(" /WinMDResilient - Generate images resilient to WinMD dependency changes.\n")
+#endif
+#ifdef FEATURE_CORECLR
+ W(" Size on Disk Parameters\n")
+ W(" /NoMetaData - Do not copy metadata and IL into native image.\n")
+#endif // FEATURE_CORECLR
+#ifndef NO_NGENPDB
+ W(" Debugging Parameters\n")
+ W(" /CreatePDB <Dir to store PDB> [/lines [<search path for managed PDB>] ]\n")
+ W(" When specifying /CreatePDB, the native image should be created\n")
+ W(" first, and <assembly name> should be the path to the NI.\n")
+#ifdef FEATURE_CORECLR
+ W(" /DiasymreaderPath <Path to diasymreader.dll>\n")
+ W(" - Specifies the absolute file path to diasymreader.dll to be used.\n")
+#endif // FEATURE_CORECLR
+#elif defined(FEATURE_PERFMAP)
+ W(" Debugging Parameters\n")
+ W(" /CreatePerfMap <Dir to store perf map>\n")
+ W(" When specifying /CreatePerfMap, the native image should be created\n")
+ W(" first, and <assembly name> should be the path to the NI.\n")
+#endif
+ );
+}
+
+class CrossgenLogger : public ICorSvcLogger
+{
+ STDMETHODIMP_(ULONG) AddRef() {return E_NOTIMPL;}
+ STDMETHODIMP_(ULONG) Release() {return E_NOTIMPL;}
+ STDMETHODIMP QueryInterface(REFIID riid,void ** ppv)
+ {
+ if (ppv==0)
+ return E_POINTER;
+
+ *ppv = NULL;
+
+ if (IsEqualIID(riid, IID_ICorSvcLogger) || IsEqualIID(riid, IID_IUnknown))
+ {
+ *ppv = this;
+ return S_OK;
+ }
+ else
+ {
+ return E_NOINTERFACE;
+ }
+ }
+
+ HRESULT STDMETHODCALLTYPE Log(
+ /*[in] */CorSvcLogLevel logLevel,
+ /*[in] */BSTR message
+ )
+ {
+ if (logLevel == LogLevel_Error)
+ OutputErr(message);
+ else
+ Output(message);
+ return S_OK;
+ }
+};
+
+CrossgenLogger g_CrossgenLogger;
+
+//
+// Tests whether szArg, the currently indexed argv matches the specified parameter name, szTestParamName.
+// Specify szTestParamName without a switch. This method handles testing for - and / switches.
+//
+bool MatchParameter(LPCWSTR szArg, LPCWSTR szTestParamName)
+{
+ if (wcslen(szArg) == 0)
+ {
+ return false;
+ }
+
+ if (szArg[0] != W('/') && szArg[0] != W('-'))
+ {
+ return false;
+ }
+
+ return !_wcsicmp(szArg + 1, szTestParamName) || !_wcsicmp(szArg + 1, szTestParamName);
+}
+
+//
+// Returns true if pwzString ends with the string in pwzCandidate
+// Ignores case
+//
+bool StringEndsWith(LPCWSTR pwzString, LPCWSTR pwzCandidate)
+{
+ size_t stringLength = wcslen(pwzString);
+ size_t candidateLength = wcslen(pwzCandidate);
+
+ if (candidateLength > stringLength || stringLength == 0 || candidateLength == 0)
+ {
+ return false;
+ }
+
+ LPCWSTR pwzStringEnd = pwzString + stringLength - candidateLength;
+
+ return !_wcsicmp(pwzStringEnd, pwzCandidate);
+}
+
+#ifdef FEATURE_CORECLR
+//
+// When using the Phone binding model (TrustedPlatformAssemblies), automatically
+// detect which path CoreLib.[ni.]dll lies in.
+//
+bool ComputeMscorlibPathFromTrustedPlatformAssemblies(SString& pwzMscorlibPath, LPCWSTR pwzTrustedPlatformAssemblies)
+{
+ LPWSTR wszTrustedPathCopy = new WCHAR[wcslen(pwzTrustedPlatformAssemblies) + 1];
+ wcscpy_s(wszTrustedPathCopy, wcslen(pwzTrustedPlatformAssemblies) + 1, pwzTrustedPlatformAssemblies);
+ wchar_t *context;
+ LPWSTR wszSingleTrustedPath = wcstok_s(wszTrustedPathCopy, PATH_SEPARATOR_STR_W, &context);
+
+ while (wszSingleTrustedPath != NULL)
+ {
+ size_t pathLength = wcslen(wszSingleTrustedPath);
+ // Strip off enclosing quotes, if present
+ if (wszSingleTrustedPath[0] == W('\"') && wszSingleTrustedPath[pathLength-1] == W('\"'))
+ {
+ wszSingleTrustedPath[pathLength-1] = '\0';
+ wszSingleTrustedPath++;
+ }
+
+ if (StringEndsWith(wszSingleTrustedPath, DIRECTORY_SEPARATOR_STR_W CoreLibName_IL_W) ||
+ StringEndsWith(wszSingleTrustedPath, DIRECTORY_SEPARATOR_STR_W CoreLibName_NI_W))
+ {
+ pwzMscorlibPath.Set(wszSingleTrustedPath);
+ SString::Iterator pwzSeparator = pwzMscorlibPath.End();
+ bool retval = true;
+
+ if (!SUCCEEDED(CopySystemDirectory(pwzMscorlibPath, pwzMscorlibPath)))
+ {
+ retval = false;
+ }
+
+ delete [] wszTrustedPathCopy;
+ return retval;
+ }
+
+ wszSingleTrustedPath = wcstok_s(NULL, PATH_SEPARATOR_STR_W, &context);
+ }
+ delete [] wszTrustedPathCopy;
+
+ return false;
+}
+
+// Given a path terminated with "\\" and a search mask, this function will add
+// the enumerated files, corresponding to the search mask, from the path into
+// the refTPAList.
+void PopulateTPAList(SString path, LPCWSTR pwszMask, SString &refTPAList, bool fCompilingMscorlib, bool fCreatePDB)
+{
+ _ASSERTE(path.GetCount() > 0);
+ ClrDirectoryEnumerator folderEnumerator(path.GetUnicode(), pwszMask);
+
+ while (folderEnumerator.Next())
+ {
+ // Got a valid enumeration handle and the data about the first file.
+ DWORD dwAttributes = folderEnumerator.GetFileAttributes();
+ if ((!(dwAttributes & FILE_ATTRIBUTE_DIRECTORY)) && (!(dwAttributes & FILE_ATTRIBUTE_DEVICE)))
+ {
+ bool fAddDelimiter = (refTPAList.GetCount() > 0)?true:false;
+ bool fAddFileToTPAList = true;
+ LPCWSTR pwszFilename = folderEnumerator.GetFileName();
+ if (fCompilingMscorlib)
+ {
+ // When compiling CoreLib, no ".ni.dll" should be on the TPAList.
+ if (StringEndsWith((LPWSTR)pwszFilename, W(".ni.dll")))
+ {
+ fAddFileToTPAList = false;
+ }
+ }
+ else
+ {
+ // When creating PDBs, we must ensure that .ni.dlls are in the TPAList
+ if (!fCreatePDB)
+ {
+ // Only CoreLib's ni.dll should be in the TPAList for the compilation of non-mscorlib assemblies.
+ if (StringEndsWith((LPWSTR)pwszFilename, W(".ni.dll")))
+ {
+ if (!StringEndsWith((LPWSTR)pwszFilename, CoreLibName_NI_W))
+ {
+ fAddFileToTPAList = false;
+ }
+ }
+ }
+
+ // Ensure that CoreLib's IL version is also not on the TPAlist for this case.
+ if (StringEndsWith((LPWSTR)pwszFilename, CoreLibName_IL_W))
+ {
+ fAddFileToTPAList = false;
+ }
+ }
+
+ if (fAddFileToTPAList)
+ {
+ if (fAddDelimiter)
+ {
+ // Add the path delimiter if we already have entries in the TPAList
+ refTPAList.Append(PATH_SEPARATOR_CHAR_W);
+ }
+ // Add the path to the TPAList
+ refTPAList.Append(path);
+ refTPAList.Append(pwszFilename);
+ }
+ }
+ }
+ }
+
+// Given a semi-colon delimited set of absolute folder paths (pwzPlatformAssembliesPaths), this function
+// will enumerate all EXE/DLL modules in those folders and add them to the TPAList buffer (refTPAList).
+void ComputeTPAListFromPlatformAssembliesPath(LPCWSTR pwzPlatformAssembliesPaths, SString &refTPAList, bool fCompilingMscorlib, bool fCreatePDB)
+{
+ // We should have a valid pointer to the paths
+ _ASSERTE(pwzPlatformAssembliesPaths != NULL);
+
+ SString ssPlatformAssembliesPath(pwzPlatformAssembliesPaths);
+
+ // Platform Assemblies Path List is semi-colon delimited
+ if(ssPlatformAssembliesPath.GetCount() > 0)
+ {
+ SString::CIterator start = ssPlatformAssembliesPath.Begin();
+ SString::CIterator itr = ssPlatformAssembliesPath.Begin();
+ SString::CIterator end = ssPlatformAssembliesPath.End();
+ SString qualifiedPath;
+
+ while (itr != end)
+ {
+ start = itr;
+ BOOL found = ssPlatformAssembliesPath.Find(itr, PATH_SEPARATOR_CHAR_W);
+ if (!found)
+ {
+ itr = end;
+ }
+
+ SString qualifiedPath(ssPlatformAssembliesPath,start,itr);
+
+ if (found)
+ {
+ itr++;
+ }
+
+ unsigned len = qualifiedPath.GetCount();
+
+ if (len > 0)
+ {
+ if (qualifiedPath[len-1]!=DIRECTORY_SEPARATOR_CHAR_W)
+ {
+ qualifiedPath.Append(DIRECTORY_SEPARATOR_CHAR_W);
+ }
+
+ // Enumerate the EXE/DLL modules within this path and add them to the TPAList
+ EX_TRY
+ {
+ PopulateTPAList(qualifiedPath, W("*.exe"), refTPAList, fCompilingMscorlib, fCreatePDB);
+ PopulateTPAList(qualifiedPath, W("*.dll"), refTPAList, fCompilingMscorlib, fCreatePDB);
+ }
+ EX_CATCH
+ {
+ Outputf(W("Warning: Error enumerating files under %s.\n"), qualifiedPath.GetUnicode());
+ }
+ EX_END_CATCH(SwallowAllExceptions);
+ }
+ }
+ }
+}
+#endif // FEATURE_CORECLR
+
+extern HMODULE g_hThisInst;
+
+int _cdecl wmain(int argc, __in_ecount(argc) WCHAR **argv)
+{
+#ifndef FEATURE_PAL
+ g_hThisInst = WszGetModuleHandle(NULL);
+#endif
+
+ /////////////////////////////////////////////////////////////////////////
+ //
+ // Parse the arguments
+ //
+ bool fDisplayLogo = true;
+ DWORD dwFlags = 0;
+ LPCWSTR pwzFilename = NULL;
+ LPCWSTR pwzPlatformResourceRoots = nullptr;
+ LPCWSTR pwzTrustedPlatformAssemblies = nullptr;
+ LPCWSTR pwzAppPaths = nullptr;
+ LPCWSTR pwzAppNiPaths = nullptr;
+ LPCWSTR pwzPlatformAssembliesPaths = nullptr;
+ LPCWSTR pwzPlatformWinmdPaths = nullptr;
+ StackSString wzDirectoryToStorePDB;
+ bool fCreatePDB = false;
+ bool fGeneratePDBLinesInfo = false;
+ LPWSTR pwzSearchPathForManagedPDB = NULL;
+ LPCWSTR pwzOutputFilename = NULL;
+ LPCWSTR pwzPublicKeys = nullptr;
+
+#if defined(FEATURE_CORECLR) && !defined(FEATURE_MERGE_JIT_AND_ENGINE)
+ LPCWSTR pwszCLRJITPath = nullptr;
+#endif // defined(FEATURE_CORECLR) && !defined(FEATURE_MERGE_JIT_AND_ENGINE)
+
+ LPCWSTR pwzDiasymreaderPath = nullptr;
+
+ HRESULT hr;
+
+#ifndef PLATFORM_UNIX
+ // This is required to properly display Unicode characters
+ _setmode(_fileno(stdout), _O_U8TEXT);
+#endif
+
+ // Skip this executable path
+ argv++;
+ argc--;
+
+ ConsoleArgs consoleArgs;
+ int argc2;
+ LPWSTR *argv2;
+
+ if (argc == 0)
+ {
+ PrintUsageHelper();
+ exit(INVALID_ARGUMENTS);
+ }
+
+ if (!consoleArgs.ExpandResponseFiles(argc, argv, &argc2, &argv2))
+ {
+ if (consoleArgs.ErrorMessage() != nullptr)
+ {
+ wprintf(consoleArgs.ErrorMessage());
+ exit(FAILURE_RESULT);
+ }
+ }
+
+ argc = argc2;
+ argv = argv2;
+
+ // By default, Crossgen will assume code-generation for fulltrust domains unless /PartialTrust switch is specified
+ dwFlags |= NGENWORKER_FLAGS_FULLTRUSTDOMAIN;
+
+#ifdef FEATURE_CORECLR
+ // By default, Crossgen will generate readytorun images unless /FragileNonVersionable switch is specified
+ dwFlags |= NGENWORKER_FLAGS_READYTORUN;
+#endif
+
+ while (argc > 0)
+ {
+ if (MatchParameter(*argv, W("?"))
+ || MatchParameter(*argv, W("help")))
+ {
+ PrintUsageHelper();
+ exit(INVALID_ARGUMENTS);
+ }
+ else if (MatchParameter(*argv, W("nologo")))
+ {
+ fDisplayLogo = false;
+ }
+ else if (MatchParameter(*argv, W("Tuning")))
+ {
+ dwFlags |= NGENWORKER_FLAGS_TUNING;
+ }
+ else if (MatchParameter(*argv, W("MissingDependenciesOK")))
+ {
+ dwFlags |= NGENWORKER_FLAGS_MISSINGDEPENDENCIESOK;
+ }
+#ifdef FEATURE_CORECLR
+ else if (MatchParameter(*argv, W("PartialTrust")))
+ {
+ // Clear the /fulltrust flag
+ dwFlags = dwFlags & ~NGENWORKER_FLAGS_FULLTRUSTDOMAIN;
+ }
+ else if (MatchParameter(*argv, W("FullTrust")))
+ {
+ // Keep the "/fulltrust" switch around but let it be no-nop. Without this, any usage of /fulltrust will result in crossgen command-line
+ // parsing failure. Considering that scripts all over (CLR, Phone Build, etc) specify that switch, we let it be as opposed to going
+ // and fixing all the scripts.
+ //
+ // We dont explicitly set the flag here again so that if "/PartialTrust" is specified, then it will successfully override the default
+ // fulltrust behaviour.
+ }
+#if !defined(FEATURE_MERGE_JIT_AND_ENGINE)
+ else if (MatchParameter(*argv, W("JITPath")) && (argc > 1))
+ {
+ pwszCLRJITPath = argv[1];
+
+ // skip JIT Path
+ argv++;
+ argc--;
+ }
+#endif // !defined(FEATURE_MERGE_JIT_AND_ENGINE)
+#endif
+#ifdef FEATURE_WINMD_RESILIENT
+ else if (MatchParameter(*argv, W("WinMDResilient")))
+ {
+ dwFlags |= NGENWORKER_FLAGS_WINMD_RESILIENT;
+ }
+#endif
+#ifdef FEATURE_READYTORUN_COMPILER
+ else if (MatchParameter(*argv, W("ReadyToRun")))
+ {
+ dwFlags |= NGENWORKER_FLAGS_READYTORUN;
+ }
+ else if (MatchParameter(*argv, W("FragileNonVersionable")))
+ {
+ dwFlags &= ~NGENWORKER_FLAGS_READYTORUN;
+ }
+#endif
+#ifdef FEATURE_CORECLR
+ else if (MatchParameter(*argv, W("NoMetaData")))
+ {
+ dwFlags |= NGENWORKER_FLAGS_NO_METADATA;
+ }
+#endif
+ else if (MatchParameter(*argv, W("out")))
+ {
+ if (pwzOutputFilename != NULL)
+ {
+ Output(W("Cannot specify multiple output files.\n"));
+ exit(INVALID_ARGUMENTS);
+ }
+ pwzOutputFilename = argv[1];
+ argv++;
+ argc--;
+ }
+ else if (MatchParameter(*argv, W("in")))
+ {
+ if (pwzFilename != NULL)
+ {
+ Output(W("Cannot specify multiple input files.\n"));
+ exit(INVALID_ARGUMENTS);
+ }
+ pwzFilename = argv[1];
+ argv++;
+ argc--;
+ }
+#ifdef FEATURE_CORECLR
+ else if (MatchParameter(*argv, W("Trusted_Platform_Assemblies")) && (argc > 1))
+ {
+ pwzTrustedPlatformAssemblies = argv[1];
+
+ // skip path list
+ argv++;
+ argc--;
+ }
+ else if (MatchParameter(*argv, W("Platform_Resource_Roots")) && (argc > 1))
+ {
+ pwzPlatformResourceRoots = argv[1];
+
+ // skip path list
+ argv++;
+ argc--;
+ }
+ else if (MatchParameter(*argv, W("App_Paths")) && (argc > 1))
+ {
+ pwzAppPaths = argv[1];
+
+ // skip User app path
+ argv++;
+ argc--;
+ }
+#ifndef NO_NGENPDB
+ else if (MatchParameter(*argv, W("App_Ni_Paths")) && (argc > 1))
+ {
+ pwzAppNiPaths = argv[1];
+
+ // skip User app path
+ argv++;
+ argc--;
+ }
+#endif // NO_NGENPDB
+#endif // FEATURE_CORECLR
+ else if (MatchParameter(*argv, W("Platform_Assemblies_Paths")) && (argc > 1))
+ {
+ pwzPlatformAssembliesPaths = argv[1];
+
+ // skip path list
+ argv++;
+ argc--;
+ }
+#ifdef FEATURE_COMINTEROP
+ else if (MatchParameter(*argv, W("Platform_Winmd_Paths")) && (argc > 1))
+ {
+ pwzPlatformWinmdPaths = argv[1];
+
+ // skip User app path
+ argv++;
+ argc--;
+ }
+#endif // FEATURE_COMINTEROP
+#ifndef NO_NGENPDB
+ else if (MatchParameter(*argv, W("CreatePDB")) && (argc > 1))
+ {
+ // syntax: /CreatePDB <directory to store PDB> [/lines [<search path for managed PDB>] ]
+
+ // Parse: /CreatePDB
+ fCreatePDB = true;
+ argv++;
+ argc--;
+
+ // Clear the /fulltrust flag - /CreatePDB does not work with any other flags.
+ dwFlags = dwFlags & ~(NGENWORKER_FLAGS_FULLTRUSTDOMAIN | NGENWORKER_FLAGS_READYTORUN);
+
+ // Parse: <directory to store PDB>
+ wzDirectoryToStorePDB.Set(argv[0]);
+ argv++;
+ argc--;
+
+ // Ensure output dir ends in a backslash, or else diasymreader has issues
+ if (wzDirectoryToStorePDB[wzDirectoryToStorePDB.GetCount()-1] != DIRECTORY_SEPARATOR_CHAR_W)
+ {
+ wzDirectoryToStorePDB.Append(DIRECTORY_SEPARATOR_STR_W);
+ }
+
+ if (argc == 0)
+ {
+ Output(W("The /CreatePDB switch requires <directory to store PDB> and <assembly name>.\n"));
+ exit(FAILURE_RESULT);
+ }
+
+ // [/lines [<search path for managed PDB>] ]
+ if (MatchParameter(*argv, W("lines")) && (argc > 1))
+ {
+ // Parse: /lines
+ fGeneratePDBLinesInfo = true;
+ argv++;
+ argc--;
+
+ if (argc == 0)
+ {
+ Output(W("The /CreatePDB switch requires <directory to store PDB> and <assembly name>.\n"));
+ exit(FAILURE_RESULT);
+ }
+
+ if (argc > 1)
+ {
+ // Parse: <search path for managed PDB>
+ pwzSearchPathForManagedPDB = argv[0];
+ argv++;
+ argc--;
+ }
+ }
+
+ // Undo last arg iteration, since we do it for all cases at the bottom of
+ // the loop
+ argv--;
+ argc++;
+ }
+#ifdef FEATURE_CORECLR
+ else if (MatchParameter(*argv, W("DiasymreaderPath")) && (argc > 1))
+ {
+ pwzDiasymreaderPath = argv[1];
+
+ // skip diasymreader Path
+ argv++;
+ argc--;
+ }
+#endif // FEATURE_CORECLR
+#endif // NO_NGENPDB
+#ifdef FEATURE_PERFMAP
+ else if (MatchParameter(*argv, W("CreatePerfMap")) && (argc > 1))
+ {
+ // syntax: /CreatePerfMap <directory to store perfmap>
+
+ // Parse: /CreatePerfMap
+ // NOTE: We use the same underlying PDB logic.
+ fCreatePDB = true;
+ argv++;
+ argc--;
+
+ // Clear the /fulltrust flag - /CreatePerfMap does not work with any other flags.
+ dwFlags = dwFlags & ~NGENWORKER_FLAGS_FULLTRUSTDOMAIN;
+
+ // Clear the /ready to run flag - /CreatePerfmap does not work with any other flags.
+ dwFlags = dwFlags & ~NGENWORKER_FLAGS_READYTORUN;
+
+ // Parse: <directory to store PDB>
+ wzDirectoryToStorePDB.Set(argv[0]);
+ argv++;
+ argc--;
+
+ // Ensure output dir ends in a backslash
+ if (wzDirectoryToStorePDB[wcslen(wzDirectoryToStorePDB)-1] != DIRECTORY_SEPARATOR_CHAR_W)
+ {
+ wzDirectoryToStorePDB.Append(DIRECTORY_SEPARATOR_STR_W);
+ }
+
+ if (argc == 0)
+ {
+ Output(W("The /CreatePerfMap switch requires <directory to store perfmap> and <assembly name>.\n"));
+ exit(FAILURE_RESULT);
+ }
+
+ // Undo last arg iteration, since we do it for all cases at the bottom of
+ // the loop
+ argv--;
+ argc++;
+ }
+#endif // FEATURE_PERFMAP
+ else
+ {
+ if (argc == 1)
+ {
+#if !defined(FEATURE_PAL)
+ // When not running on Mac, which can have forward-slash pathnames, we know
+ // a command switch here means an invalid argument.
+ if (*argv[0] == W('-') || *argv[0] == W('/'))
+ {
+ Outputf(W("Invalid parameter: %s\n"), *argv);
+ exit(INVALID_ARGUMENTS);
+ }
+#endif //!FEATURE_PAL
+ // The last thing on the command line is an assembly name or path, and
+ // because we got this far is not an argument like /nologo. Because this
+ // code works on Mac, with forward-slash pathnames, we can't assume
+ // anything with a forward slash is an argument. So we just always
+ // assume the last thing on the command line must be an assembly name.
+
+ if (pwzFilename != NULL)
+ {
+ Output(W("Cannot use /In and specify an input file as the last argument.\n"));
+ exit(INVALID_ARGUMENTS);
+ }
+
+ pwzFilename = *argv;
+ break;
+ }
+ else
+ {
+ Outputf(W("Invalid parameter: %s\n"), *argv);
+ exit(INVALID_ARGUMENTS);
+ }
+ }
+
+ argv++;
+ argc--;
+ }
+
+ if (pwzFilename == NULL)
+ {
+ Output(W("You must specify an assembly to compile\n"));
+ exit(INVALID_ARGUMENTS);
+ }
+
+ if (fCreatePDB && (dwFlags != 0))
+ {
+ Output(W("The /CreatePDB switch cannot be used with other switches, except /lines and the various path switches.\n"));
+ exit(FAILURE_RESULT);
+ }
+
+ if (pwzAppNiPaths != nullptr && !fCreatePDB)
+ {
+ Output(W("The /App_Ni_Paths switch can only be used with the /CreatePDB switch.\n"));
+ exit(FAILURE_RESULT);
+ }
+
+#if defined(FEATURE_CORECLR) && !defined(FEATURE_MERGE_JIT_AND_ENGINE)
+ if (pwszCLRJITPath != nullptr && fCreatePDB)
+ {
+ Output(W("The /JITPath switch can not be used with the /CreatePDB switch.\n"));
+ exit(FAILURE_RESULT);
+ }
+#endif // defined(FEATURE_CORECLR) && !defined(FEATURE_MERGE_JIT_AND_ENGINE)
+
+#if defined(FEATURE_CORECLR) && !defined(NO_NGENPDB)
+ if (pwzDiasymreaderPath != nullptr && !fCreatePDB)
+ {
+ Output(W("The /DiasymreaderPath switch can only be used with the /CreatePDB switch.\n"));
+ exit(FAILURE_RESULT);
+ }
+#endif // defined(FEATURE_CORECLR) && !defined(NO_NGENPDB)
+
+#if defined(FEATURE_CORECLR)
+ if ((pwzTrustedPlatformAssemblies != nullptr) && (pwzPlatformAssembliesPaths != nullptr))
+ {
+ Output(W("The /Trusted_Platform_Assemblies and /Platform_Assemblies_Paths switches cannot be both specified.\n"));
+ exit(FAILURE_RESULT);
+ }
+
+ if ((dwFlags & NGENWORKER_FLAGS_NO_METADATA) != 0)
+ {
+ const size_t windowsDotWinmdLength = 13; // Length of string "Windows.winmd"
+ size_t filenameLength = wcslen(pwzFilename);
+ bool isWindowsDotWinmd = true;
+ if (filenameLength < windowsDotWinmdLength ||
+ _wcsicmp(pwzFilename + filenameLength - windowsDotWinmdLength, W("windows.winmd")) != 0)
+ {
+ isWindowsDotWinmd = false;
+ }
+ else if (filenameLength > windowsDotWinmdLength)
+ {
+ WCHAR pathSeparator = pwzFilename[filenameLength - windowsDotWinmdLength - 1];
+ if (pathSeparator != W('\\') && pathSeparator != W('/') && pathSeparator != W(':'))
+ {
+ isWindowsDotWinmd = false;
+ }
+ }
+ if (!isWindowsDotWinmd)
+ {
+ Output(W("The /NoMetaData switch can only be used with Windows.winmd.\n"));
+ exit(FAILURE_RESULT);
+ }
+ }
+#endif // FEATURE_CORESYSTEM
+
+#ifdef FEATURE_READYTORUN_COMPILER
+ if (((dwFlags & NGENWORKER_FLAGS_TUNING) != 0) && ((dwFlags & NGENWORKER_FLAGS_READYTORUN) != 0))
+ {
+ Output(W("The /Tuning switch cannot be used with /ReadyToRun switch.\n"));
+ exit(FAILURE_RESULT);
+ }
+#endif
+
+ // All argument processing has happened by now. The only messages that should appear before here are errors
+ // related to argument parsing, such as the Usage message. Afterwards, other messages can appear.
+
+ /////////////////////////////////////////////////////////////////////////
+ //
+ // Start processing
+ //
+
+ if (fDisplayLogo)
+ {
+ PrintLogoHelper();
+ }
+
+ PathString wzTrustedPathRoot;
+
+#ifdef FEATURE_CORECLR
+ SString ssTPAList;
+
+ if (fCreatePDB)
+ {
+ // While creating PDB, assembly binder gives preference to files in TPA.
+ // This can create difficulties if the input file is not in TPA.
+ // To avoid this issue, put the input file as the first item in TPA.
+ ssTPAList.Append(pwzFilename);
+ }
+
+ // Are we compiling mscorlib.dll?
+ bool fCompilingMscorlib = StringEndsWith((LPWSTR)pwzFilename, CoreLibName_IL_W);
+
+ if (fCompilingMscorlib)
+ dwFlags &= ~NGENWORKER_FLAGS_READYTORUN;
+
+ if(pwzPlatformAssembliesPaths != nullptr)
+ {
+ // Platform_Assemblies_Paths command line switch has been specified.
+ _ASSERTE(pwzTrustedPlatformAssemblies == nullptr);
+
+ // Formulate the TPAList from Platform_Assemblies_Paths
+ ComputeTPAListFromPlatformAssembliesPath(pwzPlatformAssembliesPaths, ssTPAList, fCompilingMscorlib, fCreatePDB);
+ pwzTrustedPlatformAssemblies = (WCHAR *)ssTPAList.GetUnicode();
+ pwzPlatformAssembliesPaths = NULL;
+ }
+
+ if (pwzTrustedPlatformAssemblies != nullptr)
+ {
+ if (ComputeMscorlibPathFromTrustedPlatformAssemblies(wzTrustedPathRoot, pwzTrustedPlatformAssemblies))
+ {
+ pwzPlatformAssembliesPaths = wzTrustedPathRoot.GetUnicode();
+ SetMscorlibPath(pwzPlatformAssembliesPaths);
+ }
+ }
+#endif // FEATURE_CORECLR
+
+ if (pwzPlatformAssembliesPaths == NULL)
+ {
+ if (!WszGetModuleFileName(NULL, wzTrustedPathRoot))
+ {
+ ERROR_WIN32(W("Error: GetModuleFileName failed (%d)\n"), GetLastError());
+ exit(CLR_INIT_ERROR);
+ }
+
+ if (SUCCEEDED(CopySystemDirectory(wzTrustedPathRoot, wzTrustedPathRoot)))
+ {
+ pwzPlatformAssembliesPaths = wzTrustedPathRoot.GetUnicode();
+ }
+ else
+ {
+ ERROR_HR(W("Error: wcsrchr returned NULL; GetModuleFileName must have given us something bad\n"), E_UNEXPECTED);
+ exit(CLR_INIT_ERROR);
+ }
+
+
+ }
+
+ // Initialize the logger
+ SetSvcLogger(&g_CrossgenLogger);
+
+ //Step - Compile the assembly
+
+ if (fCreatePDB)
+ {
+ hr = CreatePDBWorker(
+ pwzFilename,
+ pwzPlatformAssembliesPaths,
+ pwzTrustedPlatformAssemblies,
+ pwzPlatformResourceRoots,
+ pwzAppPaths,
+ pwzAppNiPaths,
+ wzDirectoryToStorePDB,
+ fGeneratePDBLinesInfo,
+ pwzSearchPathForManagedPDB,
+ pwzPlatformWinmdPaths,
+ pwzDiasymreaderPath);
+
+ }
+ else
+ {
+ hr = NGenWorker(pwzFilename, dwFlags,
+ pwzPlatformAssembliesPaths,
+ pwzTrustedPlatformAssemblies,
+ pwzPlatformResourceRoots,
+ pwzAppPaths,
+ pwzOutputFilename,
+ pwzPlatformWinmdPaths
+#if defined(FEATURE_CORECLR) && !defined(FEATURE_MERGE_JIT_AND_ENGINE)
+ ,
+ NULL, // ICorSvcLogger
+ pwszCLRJITPath
+#endif // defined(FEATURE_CORECLR) && !defined(FEATURE_MERGE_JIT_AND_ENGINE)
+ );
+ }
+
+
+ if (FAILED(hr))
+ {
+ if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
+ {
+ OutputErrf(W("Error: file \"%s\" or one of its dependencies was not found\n"), pwzFilename);
+ exit(ASSEMBLY_NOT_FOUND);
+ }
+ else
+ {
+ OutputErrf(W("Error: compilation failed for \"%s\" (0x%08x)\n"), pwzFilename, hr);
+ exit(hr);
+ }
+ }
+
+ return 0;
+}
+
+#ifdef PLATFORM_UNIX
+int main(int argc, char *argv[])
+{
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAILURE_RESULT;
+ }
+
+ wchar_t **wargv = new wchar_t*[argc];
+ for (int i = 0; i < argc; i++)
+ {
+ size_t len = strlen(argv[i]) + 1;
+ wargv[i] = new wchar_t[len];
+ WszMultiByteToWideChar(CP_ACP, 0, argv[i], -1, wargv[i], len);
+ }
+
+ int ret = wmain(argc, wargv);
+
+ for (int i = 0; i < argc; i++)
+ {
+ delete[] wargv[i];
+ }
+ delete[] wargv;
+
+ return ret;
+}
+#endif // PLATFORM_UNIX
diff --git a/src/tools/crossgen/crossgen.nativeproj b/src/tools/crossgen/crossgen.nativeproj
new file mode 100644
index 0000000000..28e4741f4d
--- /dev/null
+++ b/src/tools/crossgen/crossgen.nativeproj
@@ -0,0 +1,94 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood">
+
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\xplat\SetCrossGen.props" />
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+ <!--Leaf project Properties-->
+ <PropertyGroup>
+ <BuildSysBinaries>true</BuildSysBinaries>
+ <ClAdditionalOptions>$(ClAdditionalOptions) -DUNICODE -D_UNICODE</ClAdditionalOptions>
+ <OutputName>crossgen</OutputName>
+ <TargetType>PROGRAM</TargetType>
+ <LinkSubsystem>console</LinkSubsystem>
+ <EntryPoint>wmain</EntryPoint>
+ <LinkGenerateManifest>true</LinkGenerateManifest>
+ <LinkAdditionalOptions>$(LinkAdditionalOptions) /MANIFEST</LinkAdditionalOptions>
+ <UserIncludes>$(UserIncludes);$(ClrSrcDirectory)tools\util</UserIncludes>
+ <IsDesktopTool>true</IsDesktopTool>
+ </PropertyGroup>
+ <!--Leaf Project Items-->
+ <ItemGroup>
+ <TargetLib Include="$(SdkLibPath)\ole32.lib" />
+ <TargetLib Include="$(SdkLibPath)\oleaut32.lib" />
+ <TargetLib Include="$(SdkLibPath)\uuid.lib" />
+ <TargetLib Include="$(SdkLibPath)\user32.lib" />
+ <TargetLib Include="$(SdkLibPath)\version.lib" />
+ <TargetLib Include="$(SdkLibPath)\shlwapi.lib" />
+ <TargetLib Include="$(SdkLibPath)\bcrypt.lib" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <TargetLib Condition="'$(_BuildArch)' != 'amd64'" Include="$(ClrLibPath)\corguids_x86.lib">
+ <ProjectReference>$(ClrSrcDirectory)incx86\corguids.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Condition="'$(_BuildArch)' == 'amd64'" Include="$(ClrLibPath)\corguids_amd64.lib">
+ <ProjectReference>$(ClrSrcDirectory)incamd64\corguids.nativeproj</ProjectReference>
+ </TargetLib>
+ <LinkPreCrtLibs Include="$(ClrLibPath)\utilcode_crossgen.lib" />
+ <TargetLib Include="$(ClrLibPath)\utilcode_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)utilcode\crossgen\utilcode_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Include="$(ClrLibPath)\corzap_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)zap\crossgen\zap_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+
+ <!-- We build RyuJIT only for amd64 and arm64, and use JIT32 for ARM and x86 -->
+ <TargetLib Include="$(ClrLibPath)\jit_crossgen.lib">
+ <ProjectReference Condition="'$(_BuildArch)' == 'amd64' or '$(_BuildArch)' == 'arm64'">$(ClrSrcDirectory)jit\crossgen\jit_crossgen.nativeproj</ProjectReference>
+ <ProjectReference Condition="'$(_BuildArch)' != 'amd64' and '$(_BuildArch)' != 'arm64'">$(ClrSrcDirectory)jit32\crossgen\jit_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+
+ <TargetLib Include="$(ClrLibPath)\gcinfo_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)gcinfo\crossgen\gcinfo_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Include="$(ClrLibPath)\gcdump_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)gcdump\crossgen\gcdump_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Include="$(ClrLibPath)\strongname_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)strongname\api\crossgen\strongname_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Include="$(ClrLibPath)\mdcompiler_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)md\compiler\crossgen\mdcompiler_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Include="$(ClrLibPath)\mdwinmd_crossgen.lib" Condition="'$(FeatureCominterop)' == 'true'">
+ <ProjectReference>$(ClrSrcDirectory)md\winmd\crossgen\mdwinmd_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Include="$(ClrLibPath)\mdruntimerw_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)md\enc\crossgen\mdruntimerw_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Include="$(ClrLibPath)\mdhotdata_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)md\hotdata\crossgen\mdhotdata_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Include="$(ClrLibPath)\mdruntime_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)md\runtime\crossgen\mdruntime_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Include="$(ClrLibPath)\cee_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)vm\crossgen\wks_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Include="$(ClrLibPath)\mscorlib_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)vm\crossgen_mscorlib\mscorlib_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Include="$(ClrLibPath)\v3binder_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)binder\v3binder_crossgen\v3binder_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+ </ItemGroup>
+ <ItemGroup>
+ <RCResourceFile Include="native.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <CppCompile Include="crossgen.cpp" />
+ <CppCompile Include="$(ClrSrcDirectory)\tools\util\consoleargs.cpp" />
+ </ItemGroup>
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" />
+
+</Project>
diff --git a/src/tools/dirs.proj b/src/tools/dirs.proj
new file mode 100644
index 0000000000..5f21b67fe9
--- /dev/null
+++ b/src/tools/dirs.proj
@@ -0,0 +1,77 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+
+ <PropertyGroup>
+ <BuildInPhase1>true</BuildInPhase1>
+ <BuildInPhaseDefault>false</BuildInPhaseDefault>
+ <BuildCoreBinaries>true</BuildCoreBinaries>
+ <BuildSysBinaries>true</BuildSysBinaries>
+ </PropertyGroup>
+
+ <ItemDefinitionGroup>
+ <ProjectFile>
+ <ProductGroups>FX</ProductGroups>
+ </ProjectFile>
+ </ItemDefinitionGroup>
+
+ <!--The following projects will build during PHASE 1-->
+ <ItemGroup Condition="'$(BuildExePhase)' == '1' and '$(FeatureCoreClr)' != 'true'">
+ <ProjectFile Include="allocationsprofiler\allocationsprofiler.nativeproj" />
+ <ProjectFile Include="appcompatgenerator\appcompatgenerator.nativeproj" />
+ <ProjectFile Include="applaunch\applaunch.nativeproj" />
+ <ProjectFile Include="asmlist\asmlist.nativeproj" />
+ <ProjectFile Include="asmmeta\asmmeta.nativeproj" />
+ <ProjectFile Include="bbsweep\bbsweep.nativeproj" />
+ <ProjectFile Include="bindingsnapshot\bindingsnapshot.nativeproj" />
+ <ProjectFile Include="clrver\clrver.nativeproj" />
+ <ProjectFile Include="cordmpmerge\cordmpmerge.nativeproj" />
+ <ProjectFile Include="corflags\corflags.nativeproj" />
+ <ProjectFile Include="fixpdbpath\fixpdbpath.nativeproj" />
+ <ProjectFile Include="gac\dirs.proj" />
+ <ProjectFile Include="installhook\dirs.proj" />
+ <ProjectFile Include="ismgd\ismgd.nativeproj" />
+ <ProjectFile Include="jitmanager\jitmgr.nativeproj" />
+ <ProjectFile Include="ldr64\ldr64.nativeproj" Condition="'$(BuildArchitecture)' == 'amd64'" />
+ <ProjectFile Include="logdiff\Logdiff.csproj" />
+ <ProjectFile Include="mdepends\mdepends.nativeproj" />
+ <ProjectFile Include="metainfo\metainfo.nativeproj" />
+ <ProjectFile Include="ngen\ngen.nativeproj" />
+ <ProjectFile Include="ngenoffline\ngenoffline.nativeproj" />
+ <ProjectFile Include="nidump\nidump.nativeproj" />
+ <ProjectFile Include="ndpsetup\ndpsetup.nativeproj" />
+ <ProjectFile Include="peverify\dirs.proj" />
+ <ProjectFile Include="profpick\profpick.nativeproj" />
+ <ProjectFile Include="regtlb\regtlb.nativeproj" />
+ <ProjectFile Include="resetdelaysign\resetdelaysign.nativeproj" />
+ <ProjectFile Include="showname\showname.nativeproj" />
+ <ProjectFile Include="strikers\strikers.nativeproj" />
+ <ProjectFile Include="tlbref\tlbref.nativeproj" />
+ <ProjectFile Include="verifyasmhash\verifyasmhash.nativeproj" />
+ <ProjectFile Include="verstamp\verstamp.nativeproj" Condition="'$(BuildArchitecture)' == 'i386'" />
+ <ProjectFile Include="ngentask\ngentask.csproj"/>
+ <ProjectFile Include="ngentasklauncher\ngentasklauncher.csproj"/>
+ <ProjectFile Include="McjProfofileUtil\McjProfileUtil.csproj" Condition="'$(BuildArchitecture)' != 'arm' and '$(BuildArchitecture)' != 'arm64'" />
+ <ProjectFile Include="winphoneintegrate\winphoneintegrate.csproj" />
+ <ProjectFile Include="crossgen\crossgen.nativeproj" />
+ <ProjectFile Include="GenClrDebugResource\GenClrDebugResource.nativeproj" >
+ <ProductGroups>FX;PK</ProductGroups>
+ </ProjectFile>
+ <ProjectFile Include="InjectResource\InjectResource.nativeproj" Condition="'$(BuildArchitecture)' == 'i386'">
+ <ProductGroups>FX;PK</ProductGroups>
+ </ProjectFile>
+ </ItemGroup>
+
+ <!-- CoreClr -->
+ <ItemGroup Condition="'$(BuildExePhase)' == '1' and '$(FeatureCoreClr)' == 'true'">
+ <ProjectFile Include="bbsweep\bbsweep.nativeproj" Condition="'$(BuildProjectName)' == 'CoreSys'" />
+ <ProjectFile Condition="'$(BuildArchitecture)' != 'arm' and '$(BuildArchitecture)' != 'arm64' and '$(BuildProjectName)' != 'CoreSys'" Include="ildbsymbols\ildbsymbols.nativeproj" />
+ <ProjectFile Include="coregen\coregen.nativeproj" />
+ <ProjectFile Include="nidump\nidump.nativeproj" Condition="!('$(BuildProjectName)' == 'CoreSys' and ('$(BuildArchitecture)' == 'arm' or '$(BuildArchitecture)' == 'arm64'))"/>
+ <ProjectFile Include="crossgen\crossgen.nativeproj" />
+ <ProjectFile Include="spawnnowow\spawnnowow.nativeproj" Condition="('$(BuildArchitecture)' == 'i386' or '$(BuildArchitecture)' == 'amd64' or '$(BuildArchitecture)' == 'ia64') and '$(BuildProjectName)' != 'CoreSys'" />
+ <ProjectFile Condition="'$(BuildProjectName)' == 'CoreSys'" Include="winphoneintegrate\winphoneintegrate.csproj" />
+ </ItemGroup>
+
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\tools\Microsoft.DevDiv.Traversal.targets" />
+</Project>
diff --git a/src/tools/metainfo/.gitmirrorall b/src/tools/metainfo/.gitmirrorall
new file mode 100644
index 0000000000..9ee5c57b99
--- /dev/null
+++ b/src/tools/metainfo/.gitmirrorall
@@ -0,0 +1 @@
+This folder will be mirrored by the Git-TFS Mirror recursively. \ No newline at end of file
diff --git a/src/tools/metainfo/Native.rc b/src/tools/metainfo/Native.rc
new file mode 100644
index 0000000000..fbe8437475
--- /dev/null
+++ b/src/tools/metainfo/Native.rc
@@ -0,0 +1,8 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#define FX_VER_FILEDESCRIPTION_STR "Microsoft Common Language Runtime Metadata Info\0"
+
+#include <fxver.h>
+#include <fxver.rc>
diff --git a/src/tools/metainfo/mdinfo.cpp b/src/tools/metainfo/mdinfo.cpp
new file mode 100644
index 0000000000..70dfa28bcf
--- /dev/null
+++ b/src/tools/metainfo/mdinfo.cpp
@@ -0,0 +1,4350 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include <stdio.h>
+#include <windows.h>
+#include <objbase.h>
+#include <crtdbg.h>
+#include <assert.h>
+
+#include <corpriv.h>
+#include <cor.h>
+#include "assert.h"
+#include "corerror.h"
+#include <winwrap.h>
+#include <prettyprintsig.h>
+
+#include <cahlpr.h>
+#include <limits.h>
+
+#include "mdinfo.h"
+
+#define LEGACY_ACTIVATION_SHIM_LOAD_LIBRARY WszLoadLibrary
+#define LEGACY_ACTIVATION_SHIM_DEFINE_CoInitializeEE
+#ifndef FEATURE_CORECLR
+#include "LegacyActivationShim.h"
+#endif
+
+#define ENUM_BUFFER_SIZE 10
+#define TAB_SIZE 8
+
+#define NumItems(s) (sizeof(s) / sizeof(s[0]))
+
+#define ISFLAG(p,x) if (Is##p##x(flags)) strcat_s(sFlags,STRING_BUFFER_LEN, "["#x "] ");
+
+extern HRESULT _FillVariant(
+ BYTE bCPlusTypeFlag,
+ void const *pValue,
+ ULONG cbValue,
+ VARIANT *pvar);
+
+// Validator declarations.
+extern DWORD g_ValModuleType;
+#include <ivehandler.h>
+
+// Tables for mapping element type to text
+const char *g_szMapElementType[] =
+{
+ "End", // 0x0
+ "Void", // 0x1
+ "Boolean",
+ "Char",
+ "I1",
+ "UI1",
+ "I2", // 0x6
+ "UI2",
+ "I4",
+ "UI4",
+ "I8",
+ "UI8",
+ "R4",
+ "R8",
+ "String",
+ "Ptr", // 0xf
+ "ByRef", // 0x10
+ "ValueClass",
+ "Class",
+ "Var",
+ "MDArray", // 0x14
+ "GenericInst",
+ "TypedByRef",
+ "VALUEARRAY",
+ "I",
+ "U",
+ "R", // 0x1a
+ "FNPTR",
+ "Object",
+ "SZArray",
+ "MVar",
+ "CMOD_REQD",
+ "CMOD_OPT",
+ "INTERNAL",
+};
+
+const char *g_szMapUndecorateType[] =
+{
+ "", // 0x0
+ "void",
+ "boolean",
+ "Char",
+ "byte",
+ "unsigned byte",
+ "short",
+ "unsigned short",
+ "int",
+ "unsigned int",
+ "long",
+ "unsigned long",
+ "float",
+ "double",
+ "String",
+ "*", // 0xf
+ "ByRef",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "Function Pointer",
+ "Object",
+ "",
+ "",
+ "CMOD_REQD",
+ "CMOD_OPT",
+ "INTERNAL",
+};
+
+// Provide enough entries for IMAGE_CEE_CS_CALLCONV_MASK (defined in CorHdr.h)
+const char *g_strCalling[] =
+{
+ "[DEFAULT]",
+ "[C]",
+ "[STDCALL]",
+ "[THISCALL]",
+ "[FASTCALL]",
+ "[VARARG]",
+ "[FIELD]",
+ "[LOCALSIG]",
+ "[PROPERTY]",
+ "[UNMANAGED]",
+ "[GENERICINST]",
+ "[NATIVEVARARG]",
+ "[INVALID]",
+ "[INVALID]",
+ "[INVALID]",
+ "[INVALID]"
+};
+
+const char *g_szNativeType[] =
+{
+ "NATIVE_TYPE_END(DEPRECATED!)", // = 0x0, //DEPRECATED
+ "NATIVE_TYPE_VOID(DEPRECATED!)", // = 0x1, //DEPRECATED
+ "NATIVE_TYPE_BOOLEAN", // = 0x2, // (4 byte boolean value: TRUE = non-zero, FALSE = 0)
+ "NATIVE_TYPE_I1", // = 0x3,
+ "NATIVE_TYPE_U1", // = 0x4,
+ "NATIVE_TYPE_I2", // = 0x5,
+ "NATIVE_TYPE_U2", // = 0x6,
+ "NATIVE_TYPE_I4", // = 0x7,
+ "NATIVE_TYPE_U4", // = 0x8,
+ "NATIVE_TYPE_I8", // = 0x9,
+ "NATIVE_TYPE_U8", // = 0xa,
+ "NATIVE_TYPE_R4", // = 0xb,
+ "NATIVE_TYPE_R8", // = 0xc,
+ "NATIVE_TYPE_SYSCHAR(DEPRECATED!)", // = 0xd, //DEPRECATED
+ "NATIVE_TYPE_VARIANT(DEPRECATED!)", // = 0xe, //DEPRECATED
+ "NATIVE_TYPE_CURRENCY", // = 0xf,
+ "NATIVE_TYPE_PTR(DEPRECATED!)", // = 0x10, //DEPRECATED
+
+ "NATIVE_TYPE_DECIMAL(DEPRECATED!)", // = 0x11, //DEPRECATED
+ "NATIVE_TYPE_DATE(DEPRECATED!)", // = 0x12, //DEPRECATED
+ "NATIVE_TYPE_BSTR", // = 0x13,
+ "NATIVE_TYPE_LPSTR", // = 0x14,
+ "NATIVE_TYPE_LPWSTR", // = 0x15,
+ "NATIVE_TYPE_LPTSTR", // = 0x16,
+ "NATIVE_TYPE_FIXEDSYSSTRING", // = 0x17,
+ "NATIVE_TYPE_OBJECTREF(DEPRECATED!)", // = 0x18, //DEPRECATED
+ "NATIVE_TYPE_IUNKNOWN", // = 0x19,
+ "NATIVE_TYPE_IDISPATCH", // = 0x1a,
+ "NATIVE_TYPE_STRUCT", // = 0x1b,
+ "NATIVE_TYPE_INTF", // = 0x1c,
+ "NATIVE_TYPE_SAFEARRAY", // = 0x1d,
+ "NATIVE_TYPE_FIXEDARRAY", // = 0x1e,
+ "NATIVE_TYPE_INT", // = 0x1f,
+ "NATIVE_TYPE_UINT", // = 0x20,
+
+ "NATIVE_TYPE_NESTEDSTRUCT(DEPRECATED!)", // = 0x21, //DEPRECATED (use "NATIVE_TYPE_STRUCT)
+
+ "NATIVE_TYPE_BYVALSTR", // = 0x22,
+
+ "NATIVE_TYPE_ANSIBSTR", // = 0x23,
+
+ "NATIVE_TYPE_TBSTR", // = 0x24, // select BSTR or ANSIBSTR depending on platform
+
+
+ "NATIVE_TYPE_VARIANTBOOL", // = 0x25, // (2-byte boolean value: TRUE = -1, FALSE = 0)
+ "NATIVE_TYPE_FUNC", // = 0x26,
+ "NATIVE_TYPE_LPVOID", // = 0x27, // blind pointer (no deep marshaling)
+
+ "NATIVE_TYPE_ASANY", // = 0x28,
+ "<UNDEFINED NATIVE TYPE 0x29>",
+ "NATIVE_TYPE_ARRAY", // = 0x2a,
+ "NATIVE_TYPE_LPSTRUCT", // = 0x2b,
+ "NATIVE_TYPE_CUSTOMMARSHALER", // = 0x2c, // Custom marshaler.
+ "NATIVE_TYPE_ERROR", // = 0x2d, // VT_HRESULT when exporting to a typelib.
+};
+
+
+size_t g_cbCoffNames = 0;
+
+mdMethodDef g_tkEntryPoint = 0; // integration with ILDASM
+
+
+
+// helper to init signature buffer
+void MDInfo::InitSigBuffer()
+{
+ strcpy_s((LPSTR)m_sigBuf.Ptr(), 1, "");
+} // void MDInfo::InitSigBuffer()
+
+// helper to append a string into the signature buffer. If size of signature buffer is not big enough,
+// we will grow it.
+HRESULT MDInfo::AddToSigBuffer(__in_z __in const char *string)
+{
+ HRESULT hr;
+ size_t LL = strlen((LPSTR)m_sigBuf.Ptr()) + strlen(string) + 1;
+ IfFailRet( m_sigBuf.ReSizeNoThrow(LL) );
+ strcat_s((LPSTR)m_sigBuf.Ptr(), LL, string);
+ return NOERROR;
+} // HRESULT MDInfo::AddToSigBuffer()
+
+MDInfo::MDInfo(IMetaDataImport2 *pImport, IMetaDataAssemblyImport *pAssemblyImport, LPCWSTR szScope, strPassBackFn inPBFn, ULONG DumpFilter)
+{ // This constructor is specific to ILDASM/MetaInfo integration
+
+ _ASSERTE(pImport != NULL);
+ _ASSERTE(NumItems(g_szMapElementType) == NumItems(g_szMapUndecorateType));
+ _ASSERTE(NumItems(g_szMapElementType) == ELEMENT_TYPE_MAX);
+
+ Init(inPBFn, (DUMP_FILTER)DumpFilter);
+
+ m_pImport = pImport;
+ m_pImport->AddRef();
+ if ((m_pAssemblyImport = pAssemblyImport))
+ m_pAssemblyImport->AddRef();
+ else
+ {
+ HRESULT hr = m_pImport->QueryInterface(IID_IMetaDataAssemblyImport, (void**) &m_pAssemblyImport);
+ if (FAILED(hr))
+ Error("QueryInterface failed for IID_IMetaDataAssemblyImport.", hr);
+ }
+
+} // MDInfo::MDInfo()
+
+MDInfo::MDInfo(IMetaDataDispenserEx *pDispenser, LPCWSTR szScope, strPassBackFn inPBFn, ULONG DumpFilter)
+{
+ HRESULT hr = S_OK;
+ VARIANT value;
+
+ _ASSERTE(pDispenser != NULL && inPBFn != NULL);
+ _ASSERTE(NumItems(g_szMapElementType) == NumItems(g_szMapUndecorateType));
+ _ASSERTE(NumItems(g_szMapElementType) == ELEMENT_TYPE_MAX);
+
+ Init(inPBFn, (DUMP_FILTER)DumpFilter);
+
+ // Attempt to open scope on given file
+ V_VT(&value) = VT_UI4;
+ V_UI4(&value) = MDImportOptionAll;
+ if (FAILED(hr = pDispenser->SetOption(MetaDataImportOption, &value)))
+ Error("SetOption failed.", hr);
+
+ hr = pDispenser->OpenScope(szScope, ofNoTransform, IID_IMetaDataImport2, (IUnknown**)&m_pImport);
+ if (hr == CLDB_E_BADUPDATEMODE)
+ {
+ V_VT(&value) = VT_UI4;
+ V_UI4(&value) = MDUpdateIncremental;
+ if (FAILED(hr = pDispenser->SetOption(MetaDataSetUpdate, &value)))
+ Error("SetOption failed.", hr);
+ hr = pDispenser->OpenScope(szScope, ofNoTransform, IID_IMetaDataImport2, (IUnknown**)&m_pImport);
+ }
+ if (FAILED(hr))
+ Error("OpenScope failed", hr);
+
+ // Query for the IMetaDataAssemblyImport interface.
+ hr = m_pImport->QueryInterface(IID_IMetaDataAssemblyImport, (void**) &m_pAssemblyImport);
+ if (FAILED(hr))
+ Error("QueryInterface failed for IID_IMetaDataAssemblyImport.", hr);
+
+} // MDInfo::MDInfo()
+
+
+MDInfo::MDInfo(IMetaDataDispenserEx *pDispenser, PBYTE pbMetaData, DWORD dwSize, strPassBackFn inPBFn, ULONG DumpFilter)
+{
+ _ASSERTE(pDispenser != NULL && inPBFn != NULL);
+ _ASSERTE(NumItems(g_szMapElementType) == NumItems(g_szMapUndecorateType));
+ _ASSERTE(NumItems(g_szMapElementType) == ELEMENT_TYPE_MAX);
+
+ Init(inPBFn, (DUMP_FILTER)DumpFilter);
+
+ // Attempt to open scope on manifest. It's valid for this to fail, because
+ // the blob we open may just be the assembly resources (the space is
+ // overloaded until we remove LM -a assemblies, at which point this
+ // constructor should probably be removed too).
+ HRESULT hr;
+ VARIANT value;
+ V_VT(&value) = VT_UI4;
+ V_UI4(&value) = MDImportOptionAll;
+ if (FAILED(hr = pDispenser->SetOption(MetaDataImportOption, &value)))
+ Error("SetOption failed.", hr);
+ if (SUCCEEDED(hr = pDispenser->OpenScopeOnMemory(pbMetaData, dwSize, ofNoTransform,
+ IID_IMetaDataImport2, (IUnknown**)&m_pImport)))
+ {
+ // Query for the IMetaDataAssemblyImport interface.
+ hr = m_pImport->QueryInterface(IID_IMetaDataAssemblyImport, (void**) &m_pAssemblyImport);
+ if (FAILED(hr))
+ Error("QueryInterface failed for IID_IMetaDataAssemblyImport.", hr);
+ }
+
+} // MDInfo::MDInfo()
+
+void MDInfo::Init(
+ strPassBackFn inPBFn, // Callback to write text.
+ DUMP_FILTER DumpFilter) // Flags to control the dump.
+{
+ m_VEHandlerReporterPtr = 0;
+ m_pbFn = inPBFn;
+ m_DumpFilter = DumpFilter;
+ m_pTables = NULL;
+ m_pTables2 = NULL;
+ m_pImport = NULL;
+ m_pAssemblyImport = NULL;
+} // void MDInfo::Init()
+
+// Destructor
+MDInfo::~MDInfo()
+{
+ if (m_pImport)
+ m_pImport->Release();
+ if (m_pAssemblyImport)
+ m_pAssemblyImport->Release();
+ if (m_pTables)
+ m_pTables->Release();
+ if (m_pTables2)
+ m_pTables2->Release();
+} // MDInfo::~MDInfo()
+
+//=====================================================================================================================
+//#define EXTERNAL_VE_HANDLER_FOR_MD_VALIDATION
+#ifndef EXTERNAL_VE_HANDLER_FOR_MD_VALIDATION
+
+HINSTANCE GetModuleInst()
+{
+ return NULL;
+} // HINSTANCE GetModuleInst()
+
+typedef HRESULT (*REPORTFCTN)(LPCWSTR, VEContext, HRESULT);
+HRESULT DefaultReporter( // Return status.
+ LPCWSTR szMsg, // Error message.
+ VEContext Context, // Error context (offset,token)
+ HRESULT hrRpt) // Original HRESULT
+{
+ if(szMsg)
+ {
+ printf("%S", szMsg);
+ // include token and offset from Context
+ if(Context.Token) printf(" [token:0x%08X]",Context.Token);
+ if(Context.uOffset) printf(" [at:0x%X]",Context.uOffset);
+ printf(" [hr:0x%08X]\n",hrRpt);
+ fflush(stdout);
+ }
+ return S_OK;
+} // HRESULT DefaultReporter()
+
+
+#ifdef FEATURE_METADATA_VALIDATOR
+class MDVEHandlerClass : public IVEHandler
+{
+public:
+ LONG m_refCount;
+ REPORTFCTN m_fnReport;
+
+ MDVEHandlerClass() { m_refCount=0; m_fnReport=DefaultReporter; };
+ virtual ~MDVEHandlerClass() { };
+
+ //-----------------------------------------------------------
+ // IUnknown support
+ //-----------------------------------------------------------
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, void** pInterface)
+ {
+ if (id == IID_IVEHandler)
+ *pInterface = (IVEHandler*)this;
+ /*
+ else if (id == IID_IUnknown)
+ *pInterface = (IUnknown*)(IVEHandler*)this;
+ */
+ else
+ {
+ *pInterface = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+ }
+ ULONG STDMETHODCALLTYPE AddRef()
+ {
+ return InterlockedIncrement(&m_refCount);
+ }
+
+ ULONG STDMETHODCALLTYPE Release()
+ {
+ LONG refCount = InterlockedDecrement(&m_refCount);
+ if (refCount == 0) delete this;
+ return (refCount);
+ }
+ //-----------------------------------------------------------
+ // IVEHandler support
+ //-----------------------------------------------------------
+ HRESULT STDMETHODCALLTYPE SetReporterFtn(__int64 lFnPtr)
+ {
+ m_fnReport = lFnPtr ? reinterpret_cast<REPORTFCTN>(lFnPtr)
+ : DefaultReporter;
+ return S_OK;
+ };
+
+//*****************************************************************************
+// The Verification Event Handler itself. Declared in VEHandler.h as virtual, may be overridden
+//*****************************************************************************
+ HRESULT STDMETHODCALLTYPE VEHandler(HRESULT hrRpt, VEContext Context, SAFEARRAY *psa)
+ {
+ WCHAR rcBuf[1024]; // Resource string.
+ WCHAR rcMsg[1024]; // Error message.
+ BYTE *marker; // User text.
+ HRESULT hr;
+ ULONG32 k;
+ WCHAR *pWsz[1024]; // is more than 1024 string arguments likely?
+
+ // Return warnings without text.
+ if (!FAILED(hrRpt))
+ return (hrRpt);
+ memset(pWsz,0,sizeof(pWsz));
+
+ ULONG32 nVars;
+ // Convert safearray of variants into va_list
+ if(psa && (nVars = psa->rgsabound[0].cElements))
+ {
+ WCHAR *pwsz;
+ VARIANT *pVar;
+ ULONG32 i,l;
+ BYTE *pval;
+
+ _ASSERTE(psa->fFeatures & FADF_VARIANT);
+ _ASSERTE(psa->cDims == 1);
+ marker = new BYTE[nVars*sizeof(double)]; // double being the largest variant element
+ for(i=0,pVar=(VARIANT *)(psa->pvData),pval=marker; i < nVars; pVar++,i++)
+ {
+ switch(V_VT(pVar))
+ {
+ case VT_I1:
+ *(int *)pval = V_I1(pVar);
+ pval += sizeof(int);
+ break;
+
+ case VT_UI1:
+ *(int *)pval = V_UI1(pVar);
+ pval += sizeof(int);
+ break;
+
+
+ case VT_I2:
+ *(int *)pval = V_I2(pVar);
+ pval += sizeof(int);
+ break;
+
+ case VT_UI2:
+ *(int *)pval = V_UI2(pVar);
+ pval += sizeof(int);
+ break;
+
+ case VT_I8:
+ case VT_UI8:
+ *(INT64 *)pval = V_I8(pVar);
+ pval += sizeof(INT64);
+ break;
+
+
+ case VT_BYREF|VT_I1:
+ case VT_BYREF|VT_UI1: // it's ASCII string, convert it to UNICODE
+ {
+ PBYTE pb = V_UI1REF(pVar);
+ l = (ULONG32)strlen((char *)pb)+1;
+ pwsz = new WCHAR[l];
+ WszMultiByteToWideChar(CP_ACP,0,(char*)pb,-1,pwsz,l);
+ for(k=0; pWsz[k]; k++);
+ pWsz[k] = pwsz;
+
+ *(WCHAR **)pval = pwsz;
+ pval += sizeof(WCHAR *);
+ break;
+ }
+
+ default:
+ *(int *)pval = V_I4(pVar);
+ pval += sizeof(int);
+ break;
+ }
+ }
+ }
+ else
+ marker = NULL;
+
+ // If this is one of our errors, then grab the error from the rc file.
+ if (HRESULT_FACILITY(hrRpt) == FACILITY_URT)
+ {
+ hr = UtilLoadStringRC(LOWORD(hrRpt), rcBuf, NumItems(rcBuf), true);
+ if (hr == S_OK)
+ {
+ // Format the error.
+ vswprintf_s(rcMsg, NumItems(rcMsg), rcBuf, (va_list) marker);
+ rcMsg[NumItems(rcMsg) - 1] = 0;
+ }
+ }
+ // Otherwise it isn't one of ours, so we need to see if the system can
+ // find the text for it.
+ else
+ {
+ if (WszFormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
+ 0, hrRpt, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ rcMsg, NumItems(rcMsg), 0))
+ {
+ hr = S_OK;
+
+ // System messages contain a trailing \r\n, which we don't want normally.
+ int iLen = lstrlenW(rcMsg);
+ if (iLen > 3 && rcMsg[iLen - 2] == '\r' && rcMsg[iLen - 1] == '\n')
+ rcMsg[iLen - 2] = '\0';
+ }
+ else
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ if(marker) delete [] marker;
+
+ // If we failed to find the message anywhere, then issue a hard coded message.
+ if (FAILED(hr))
+ {
+ swprintf_s(rcMsg, NumItems(rcMsg), W("COM+ Runtime Internal error: 0x%08x"), hrRpt);
+ //DEBUG_STMT(DbgWriteEx(rcMsg));
+ }
+
+ // delete WCHAR buffers allocated above (if any)
+ for(k=0; pWsz[k]; k++)
+ {
+ if(pWsz[k])
+ {
+ delete [] pWsz[k];
+ pWsz[k] = NULL;
+ }
+ }
+
+ return (m_fnReport(rcMsg, Context,hrRpt) == S_OK ? S_OK : E_FAIL);
+ };
+
+ static HRESULT STDMETHODCALLTYPE CreateObject(REFIID id, void **object)
+ { return E_NOTIMPL; }
+};
+#endif // FEATURE_METADATA_VALIDATOR
+
+#endif
+//=====================================================================================================================
+// DisplayMD() function
+//
+// Displays the meta data content of a file
+
+void MDInfo::DisplayMD()
+{
+ if ((m_DumpFilter & dumpAssem) && m_pAssemblyImport)
+ DisplayAssemblyInfo();
+ WriteLine("===========================================================");
+ // Metadata itself: Raw or normal view
+ if (m_DumpFilter & (dumpSchema | dumpHeader | dumpCSV | dumpRaw | dumpStats | dumpRawHeaps))
+ DisplayRaw();
+ else
+ {
+ DisplayVersionInfo();
+ DisplayScopeInfo();
+ WriteLine("===========================================================");
+ DisplayGlobalFunctions();
+ DisplayGlobalFields();
+ DisplayGlobalMemberRefs();
+ DisplayTypeDefs();
+ DisplayTypeRefs();
+ DisplayTypeSpecs();
+ DisplayMethodSpecs();
+ DisplayModuleRefs();
+ DisplaySignatures();
+ DisplayAssembly();
+ DisplayUserStrings();
+
+ // WriteLine("============================================================");
+ // WriteLine("Unresolved MemberRefs");
+ // DisplayMemberRefs(0x00000001, "\t");
+
+ VWrite("\n\nCoff symbol name overhead: %d\n", g_cbCoffNames);
+ }
+ WriteLine("===========================================================");
+ if (m_DumpFilter & dumpUnsat)
+ DisplayUnsatInfo();
+ WriteLine("===========================================================");
+#ifdef FEATURE_METADATA_VALIDATOR
+ if (m_DumpFilter & dumpValidate)
+ {
+ IMetaDataValidate *pValidate = 0;
+#ifndef EXTERNAL_VE_HANDLER_FOR_MD_VALIDATION
+ MDVEHandlerClass *pVEHandler = 0;
+#else
+ IVEHandler *pVEHandler = 0;
+#endif
+ const char *szErrStr = 0;
+ HRESULT hr = S_OK;
+
+ // Get a pointer to the Validator interface.
+ hr = m_pImport->QueryInterface(IID_IMetaDataValidate, (void **) &pValidate);
+ if (FAILED(hr))
+ {
+ szErrStr = "QueryInterface failed for IMetaDataValidate.";
+ goto ErrExit;
+ }
+
+ // Get a pointer to the VEHandler interface.
+#ifndef EXTERNAL_VE_HANDLER_FOR_MD_VALIDATION
+ if((pVEHandler = new MDVEHandlerClass())) hr = S_OK;
+ else hr = E_FAIL;
+#else
+ hr = CoCreateInstance(CLSID_VEHandlerClass,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_IVEHandler,
+ (void **)&pVEHandler);
+#endif
+ if (FAILED(hr))
+ {
+#ifndef EXTERNAL_VE_HANDLER_FOR_MD_VALIDATION
+ szErrStr = "Failed to create VEHandler.";
+#else
+ szErrStr = "CoCreateInstance(VEHandler) failed.";
+#endif
+ goto ErrExit;
+ }
+
+ if(m_VEHandlerReporterPtr) pVEHandler->SetReporterFtn((__int64)m_VEHandlerReporterPtr);
+
+ hr = pValidate->ValidatorInit(g_ValModuleType, pVEHandler);
+ if (FAILED(hr))
+ {
+ szErrStr = "ValidatorInit failed.";
+ goto ErrExit;
+ }
+
+ hr = pValidate->ValidateMetaData();
+ if (FAILED(hr))
+ {
+ szErrStr = "ValidateMetaData failed to run successfully.";
+ goto ErrExit;
+ }
+ if (hr == S_OK)
+ WriteLine("No warnings or errors found.");
+ else if (hr == VLDTR_S_WRN)
+ WriteLine("Warnings found.");
+ else if (hr == VLDTR_S_ERR)
+ WriteLine("Errors found.");
+ else if (hr == VLDTR_S_WRNERR)
+ WriteLine("Warnings and Errors found.");
+ else
+ VWriteLine("Validator returned unexpected success code, hr=0x%08x.", hr);
+ErrExit:
+ if (pValidate)
+ pValidate->Release();
+#ifdef EXTERNAL_VE_HANDLER_FOR_MD_VALIDATION
+ if (pVEHandler)
+ pVEHandler->Release();
+#endif
+ if (szErrStr)
+ Error(szErrStr, hr);
+ }
+#endif // FEATURE_METADATA_VALIDATOR
+ WriteLine("===========================================================");
+} // MDVEHandlerClass()
+
+int MDInfo::WriteLine(__in_z __in const char *str)
+{
+ ULONG32 count = (ULONG32) strlen(str);
+
+ m_pbFn(str);
+ m_pbFn("\n");
+ return count;
+} // int MDInfo::WriteLine()
+
+int MDInfo::Write(__in_z __in const char *str)
+{
+ ULONG32 count = (ULONG32) strlen(str);
+
+ m_pbFn(str);
+ return count;
+} // int MDInfo::Write()
+
+int MDInfo::VWriteLine(__in_z __in const char *str, ...)
+{
+ va_list marker;
+ int count;
+
+ va_start(marker, str);
+ count = VWriteMarker(str, marker);
+ m_pbFn("\n");
+ va_end(marker);
+ return count;
+} // int MDInfo::VWriteLine()
+
+int MDInfo::VWrite(__in_z __in const char *str, ...)
+{
+ va_list marker;
+ int count;
+
+ va_start(marker, str);
+ count = VWriteMarker(str, marker);
+ va_end(marker);
+ return count;
+} // int MDInfo::VWrite()
+
+int MDInfo::VWriteMarker(__in_z __in const char *str, va_list marker)
+{
+ HRESULT hr;
+ int count = -1;
+ // Used to allocate 1K, then if not enough, 2K, then 4K.
+ // Faster to allocate 32K right away and be done with it,
+ // we're not running on Commodore 64
+ if (FAILED(hr = m_output.ReSizeNoThrow(STRING_BUFFER_LEN * 8)))
+ Error("ReSize failed.", hr);
+ else
+ {
+ count = vsprintf_s((char *)m_output.Ptr(), STRING_BUFFER_LEN * 8, str, marker);
+ m_pbFn((char *)m_output.Ptr());
+ }
+ return count;
+} // int MDInfo::VWriteToBuffer()
+
+// Error() function -- prints an error and returns
+void MDInfo::Error(const char* szError, HRESULT hr)
+{
+ printf("\n%s\n",szError);
+ if (hr != S_OK)
+ {
+ printf("Failed return code: 0x%08x\n", hr);
+
+ IErrorInfo *pIErr = NULL; // Error interface.
+ BSTR bstrDesc = NULL; // Description text.
+#ifdef FEATURE_COMINTEROP
+ // Try to get an error info object and display the message.
+ if (GetErrorInfo(0, &pIErr) == S_OK &&
+ pIErr->GetDescription(&bstrDesc) == S_OK)
+ {
+ printf("%ls ", bstrDesc);
+ SysFreeString(bstrDesc);
+ }
+#endif
+ // Free the error interface.
+ if (pIErr)
+ pIErr->Release();
+
+ }
+#ifndef FEATURE_CORECLR
+ LegacyActivationShim::CoUninitializeCor();
+#ifndef FEATURE_PAL
+ CoUninitialize();
+#endif
+#endif
+ exit(hr);
+} // void MDInfo::Error()
+
+// Print out the optional version info included in the MetaData.
+
+void MDInfo::DisplayVersionInfo()
+{
+ if (!(m_DumpFilter & MDInfo::dumpNoLogo))
+ {
+ LPCUTF8 pVersionStr;
+ HRESULT hr = S_OK;
+
+ if (m_pTables == 0)
+ {
+ if (m_pImport)
+ hr = m_pImport->QueryInterface(IID_IMetaDataTables, (void**)&m_pTables);
+ else if (m_pAssemblyImport)
+ hr = m_pAssemblyImport->QueryInterface(IID_IMetaDataTables, (void**)&m_pTables);
+ else
+ return;
+ if (FAILED(hr))
+ Error("QueryInterface failed for IID_IMetaDataTables.", hr);
+ }
+
+ hr = m_pTables->GetString(1, &pVersionStr);
+ if (FAILED(hr))
+ Error("GetString() failed.", hr);
+ if (strstr(pVersionStr, "Version of runtime against which the binary is built : ")
+ == pVersionStr)
+ {
+ WriteLine(const_cast<char *>(pVersionStr));
+ }
+ }
+} // void MDInfo::DisplayVersionInfo()
+
+// Prints out information about the scope
+
+void MDInfo::DisplayScopeInfo()
+{
+ HRESULT hr;
+ mdModule mdm;
+ GUID mvid;
+ WCHAR scopeName[STRING_BUFFER_LEN];
+ WCHAR guidString[STRING_BUFFER_LEN];
+
+ hr = m_pImport->GetScopeProps( scopeName, STRING_BUFFER_LEN, 0, &mvid);
+ if (FAILED(hr)) Error("GetScopeProps failed.", hr);
+
+ VWriteLine("ScopeName : %ls",scopeName);
+
+ if (!(m_DumpFilter & MDInfo::dumpNoLogo))
+ VWriteLine("MVID : %ls",GUIDAsString(mvid, guidString, STRING_BUFFER_LEN));
+
+ hr = m_pImport->GetModuleFromScope(&mdm);
+ if (FAILED(hr)) Error("GetModuleFromScope failed.", hr);
+ DisplayPermissions(mdm, "");
+ DisplayCustomAttributes(mdm, "\t");
+} // void MDInfo::DisplayScopeInfo()
+
+void MDInfo::DisplayRaw()
+{
+ int iDump; // Level of info to dump.
+
+ if (m_pTables == 0)
+ m_pImport->QueryInterface(IID_IMetaDataTables, (void**)&m_pTables);
+ if (m_pTables == 0)
+ Error("Can't get table info.");
+ if (m_pTables2 == 0)
+ m_pImport->QueryInterface(IID_IMetaDataTables2, (void**)&m_pTables2);
+
+ if (m_DumpFilter & dumpCSV)
+ DumpRawCSV();
+ if (m_DumpFilter & (dumpSchema | dumpHeader | dumpRaw | dumpStats))
+ {
+ if (m_DumpFilter & dumpRaw)
+ iDump = 3;
+ else
+ if (m_DumpFilter & dumpSchema)
+ iDump = 2;
+ else
+ iDump = 1;
+
+ DumpRaw(iDump, (m_DumpFilter & dumpStats) != 0);
+ }
+ if (m_DumpFilter & dumpRawHeaps)
+ DumpRawHeaps();
+} // void MDInfo::DisplayRaw()
+
+// return the name of the type of token passed in
+
+const char *MDInfo::TokenTypeName(mdToken inToken)
+{
+ switch(TypeFromToken(inToken))
+ {
+ case mdtTypeDef: return "TypeDef";
+ case mdtInterfaceImpl: return "InterfaceImpl";
+ case mdtMethodDef: return "MethodDef";
+ case mdtFieldDef: return "FieldDef";
+ case mdtTypeRef: return "TypeRef";
+ case mdtMemberRef: return "MemberRef";
+ case mdtCustomAttribute:return "CustomAttribute";
+ case mdtParamDef: return "ParamDef";
+ case mdtProperty: return "Property";
+ case mdtEvent: return "Event";
+ case mdtTypeSpec: return "TypeSpec";
+ default: return "[UnknownTokenType]";
+ }
+} // char *MDInfo::TokenTypeName()
+
+// Prints out name of the given memberref
+//
+
+LPCWSTR MDInfo::MemberRefName(mdMemberRef inMemRef, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen)
+{
+ HRESULT hr;
+
+
+ hr = m_pImport->GetMemberRefProps( inMemRef, NULL, buffer, bufLen,
+ NULL, NULL, NULL);
+ if (FAILED(hr)) Error("GetMemberRefProps failed.", hr);
+
+ return buffer;
+} // LPCWSTR MDInfo::MemberRefName()
+
+
+// Prints out information about the given memberref
+//
+
+void MDInfo::DisplayMemberRefInfo(mdMemberRef inMemRef, const char *preFix)
+{
+ HRESULT hr;
+ WCHAR memRefName[STRING_BUFFER_LEN];
+ ULONG nameLen;
+ mdToken token;
+ PCCOR_SIGNATURE pbSigBlob;
+ ULONG ulSigBlob;
+ char newPreFix[STRING_BUFFER_LEN];
+
+
+ hr = m_pImport->GetMemberRefProps( inMemRef, &token, memRefName, STRING_BUFFER_LEN,
+ &nameLen, &pbSigBlob, &ulSigBlob);
+ if (FAILED(hr)) Error("GetMemberRefProps failed.", hr);
+
+ VWriteLine("%s\t\tMember: (%8.8x) %ls: ", preFix, inMemRef, memRefName);
+
+ if (ulSigBlob)
+ DisplaySignature(pbSigBlob, ulSigBlob, preFix);
+ else
+ VWriteLine("%s\t\tERROR: no valid signature ", preFix);
+
+ sprintf_s (newPreFix, STRING_BUFFER_LEN, "\t\t%s", preFix);
+ DisplayCustomAttributes(inMemRef, newPreFix);
+} // void MDInfo::DisplayMemberRefInfo()
+
+// Prints out information about all memberrefs of the given typeref
+//
+
+void MDInfo::DisplayMemberRefs(mdToken tkParent, const char *preFix)
+{
+ HCORENUM memRefEnum = NULL;
+ HRESULT hr;
+ mdMemberRef memRefs[ENUM_BUFFER_SIZE];
+ ULONG count, totalCount = 1;
+
+
+ while (SUCCEEDED(hr = m_pImport->EnumMemberRefs( &memRefEnum, tkParent,
+ memRefs, NumItems(memRefs), &count)) &&
+ count > 0)
+ {
+ for (ULONG i = 0; i < count; i++, totalCount++)
+ {
+ VWriteLine("%s\tMemberRef #%d (%08x)", preFix, totalCount, memRefs[i]);
+ VWriteLine("%s\t-------------------------------------------------------", preFix);
+ DisplayMemberRefInfo(memRefs[i], preFix);
+ }
+ }
+ m_pImport->CloseEnum( memRefEnum);
+} // void MDInfo::DisplayMemberRefs()
+
+// Prints out information about all resources in the com object
+//
+
+// Iterates through each typeref and prints out the information of each
+//
+
+void MDInfo::DisplayTypeRefs()
+{
+ HCORENUM typeRefEnum = NULL;
+ mdTypeRef typeRefs[ENUM_BUFFER_SIZE];
+ ULONG count, totalCount=1;
+ HRESULT hr;
+
+ while (SUCCEEDED(hr = m_pImport->EnumTypeRefs( &typeRefEnum,
+ typeRefs, NumItems(typeRefs), &count)) &&
+ count > 0)
+ {
+ for (ULONG i = 0; i < count; i++, totalCount++)
+ {
+ VWriteLine("TypeRef #%d (%08x)", totalCount, typeRefs[i]);
+ WriteLine("-------------------------------------------------------");
+ DisplayTypeRefInfo(typeRefs[i]);
+ DisplayMemberRefs(typeRefs[i], "");
+ WriteLine("");
+ }
+ }
+ m_pImport->CloseEnum( typeRefEnum);
+} // void MDInfo::DisplayTypeRefs()
+
+void MDInfo::DisplayTypeSpecs()
+{
+ HCORENUM typespecEnum = NULL;
+ mdTypeSpec typespecs[ENUM_BUFFER_SIZE];
+ ULONG count, totalCount=1;
+ HRESULT hr;
+
+ while (SUCCEEDED(hr = m_pImport->EnumTypeSpecs( &typespecEnum,
+ typespecs, NumItems(typespecs), &count)) &&
+ count > 0)
+ {
+ for (ULONG i = 0; i < count; i++, totalCount++)
+ {
+ VWriteLine("TypeSpec #%d (%08x)", totalCount, typespecs[i]);
+ WriteLine("-------------------------------------------------------");
+ DisplayTypeSpecInfo(typespecs[i], "");
+ DisplayMemberRefs(typespecs[i], "");
+ WriteLine("");
+ }
+ }
+ m_pImport->CloseEnum( typespecEnum);
+} // void MDInfo::DisplayTypeSpecs()
+
+void MDInfo::DisplayMethodSpecs()
+{
+ HCORENUM MethodSpecEnum = NULL;
+ mdMethodSpec MethodSpecs[ENUM_BUFFER_SIZE];
+ ULONG count, totalCount=1;
+///// HRESULT hr;
+
+
+///// HACK until I implement EnumMethodSpecs!
+///// while (SUCCEEDED(hr = m_pImport->EnumMethodSpecs( &MethodSpecEnum,
+///// MethodSpecs, NumItems(MethodSpecs), &count)) &&
+///// count > 0)
+ for (ULONG rid=1; m_pImport->IsValidToken(TokenFromRid(rid, mdtMethodSpec)); ++rid)
+ {
+// More hackery
+count = 1;
+MethodSpecs[0] = TokenFromRid(rid, mdtMethodSpec);
+// More hackery
+ for (ULONG i = 0; i < count; i++, totalCount++)
+ {
+ VWriteLine("MethodSpec #%d (%08x)", totalCount, MethodSpecs[i]);
+ DisplayMethodSpecInfo(MethodSpecs[i], "");
+ WriteLine("");
+ }
+ }
+ m_pImport->CloseEnum( MethodSpecEnum);
+} // void MDInfo::DisplayMethodSpecs()
+
+
+
+// Called to display the information about all typedefs in the object.
+//
+
+void MDInfo::DisplayTypeDefs()
+{
+ HCORENUM typeDefEnum = NULL;
+ mdTypeDef typeDefs[ENUM_BUFFER_SIZE];
+ ULONG count, totalCount = 1;
+ HRESULT hr;
+
+ while (SUCCEEDED(hr = m_pImport->EnumTypeDefs( &typeDefEnum,
+ typeDefs, NumItems(typeDefs), &count)) &&
+ count > 0)
+ {
+ for (ULONG i = 0; i < count; i++, totalCount++)
+ {
+ VWriteLine("TypeDef #%d (%08x)", totalCount, typeDefs[i]);
+ WriteLine("-------------------------------------------------------");
+ DisplayTypeDefInfo(typeDefs[i]);
+ WriteLine("");
+ }
+ }
+ m_pImport->CloseEnum( typeDefEnum);
+} // void MDInfo::DisplayTypeDefs()
+
+// Called to display the information about all modulerefs in the object.
+//
+
+void MDInfo::DisplayModuleRefs()
+{
+ HCORENUM moduleRefEnum = NULL;
+ mdModuleRef moduleRefs[ENUM_BUFFER_SIZE];
+ ULONG count, totalCount = 1;
+ HRESULT hr;
+
+ while (SUCCEEDED(hr = m_pImport->EnumModuleRefs( &moduleRefEnum,
+ moduleRefs, NumItems(moduleRefs), &count)) &&
+ count > 0)
+ {
+ for (ULONG i = 0; i < count; i++, totalCount++)
+ {
+ VWriteLine("ModuleRef #%d (%08x)", totalCount, moduleRefs[i]);
+ WriteLine("-------------------------------------------------------");
+ DisplayModuleRefInfo(moduleRefs[i]);
+ DisplayMemberRefs(moduleRefs[i], "");
+ WriteLine("");
+ }
+ }
+ m_pImport->CloseEnum( moduleRefEnum);
+} // void MDInfo::DisplayModuleRefs()
+
+// Prints out information about the given moduleref
+//
+
+void MDInfo::DisplayModuleRefInfo(mdModuleRef inModuleRef)
+{
+ HRESULT hr;
+ WCHAR moduleRefName[STRING_BUFFER_LEN];
+ ULONG nameLen;
+
+
+ hr = m_pImport->GetModuleRefProps( inModuleRef, moduleRefName, STRING_BUFFER_LEN,
+ &nameLen);
+ if (FAILED(hr)) Error("GetModuleRefProps failed.", hr);
+
+ VWriteLine("\t\tModuleRef: (%8.8x) %ls: ", inModuleRef, moduleRefName);
+ DisplayCustomAttributes(inModuleRef, "\t\t");
+} // void MDInfo::DisplayModuleRefInfo()
+
+
+// Called to display the information about all signatures in the object.
+//
+
+void MDInfo::DisplaySignatures()
+{
+ HCORENUM signatureEnum = NULL;
+ mdSignature signatures[ENUM_BUFFER_SIZE];
+ ULONG count, totalCount = 1;
+ HRESULT hr;
+
+ while (SUCCEEDED(hr = m_pImport->EnumSignatures( &signatureEnum,
+ signatures, NumItems(signatures), &count)) &&
+ count > 0)
+ {
+ for (ULONG i = 0; i < count; i++, totalCount++)
+ {
+ VWriteLine("Signature #%d (%#08x)", totalCount, signatures[i]);
+ WriteLine("-------------------------------------------------------");
+ DisplaySignatureInfo(signatures[i]);
+ WriteLine("");
+ }
+ }
+ m_pImport->CloseEnum( signatureEnum);
+} // void MDInfo::DisplaySignatures()
+
+
+// Prints out information about the given signature
+//
+
+void MDInfo::DisplaySignatureInfo(mdSignature inSignature)
+{
+ HRESULT hr;
+ PCCOR_SIGNATURE pbSigBlob;
+ ULONG ulSigBlob;
+
+
+ hr = m_pImport->GetSigFromToken( inSignature, &pbSigBlob, &ulSigBlob );
+ if (FAILED(hr)) Error("GetSigFromToken failed.", hr);
+ if(ulSigBlob)
+ DisplaySignature(pbSigBlob, ulSigBlob, "");
+ else
+ VWriteLine("\t\tERROR: no valid signature ");
+} // void MDInfo::DisplaySignatureInfo()
+
+
+// returns the passed-in buffer which is filled with the name of the given
+// member in wide characters
+//
+
+LPCWSTR MDInfo::MemberName(mdToken inToken, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen)
+{
+ HRESULT hr;
+
+
+ hr = m_pImport->GetMemberProps( inToken, NULL, buffer, bufLen,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ if (FAILED(hr)) Error("GetMemberProps failed.", hr);
+
+ return (buffer);
+} // LPCWSTR MDInfo::MemberName()
+
+
+// displays information for the given method
+//
+
+void MDInfo::DisplayMethodInfo(mdMethodDef inMethod, DWORD *pflags)
+{
+ HRESULT hr;
+ mdTypeDef memTypeDef;
+ WCHAR memberName[STRING_BUFFER_LEN];
+ ULONG nameLen;
+ DWORD flags;
+ PCCOR_SIGNATURE pbSigBlob;
+ ULONG ulSigBlob;
+ ULONG ulCodeRVA;
+ ULONG ulImplFlags;
+
+
+ hr = m_pImport->GetMethodProps( inMethod, &memTypeDef, memberName, STRING_BUFFER_LEN,
+ &nameLen, &flags, &pbSigBlob, &ulSigBlob, &ulCodeRVA, &ulImplFlags);
+ if (FAILED(hr)) Error("GetMethodProps failed.", hr);
+ if (pflags)
+ *pflags = flags;
+
+ VWriteLine("\t\tMethodName: %ls (%8.8X)", memberName, inMethod);
+
+ char sFlags[STRING_BUFFER_LEN];
+
+ sFlags[0] = 0;
+ ISFLAG(Md, Public);
+ ISFLAG(Md, Private);
+ ISFLAG(Md, Family);
+ ISFLAG(Md, Assem);
+ ISFLAG(Md, FamANDAssem);
+ ISFLAG(Md, FamORAssem);
+ ISFLAG(Md, PrivateScope);
+ ISFLAG(Md, Static);
+ ISFLAG(Md, Final);
+ ISFLAG(Md, Virtual);
+ ISFLAG(Md, HideBySig);
+ ISFLAG(Md, ReuseSlot);
+ ISFLAG(Md, NewSlot);
+ ISFLAG(Md, Abstract);
+ ISFLAG(Md, SpecialName);
+ ISFLAG(Md, RTSpecialName);
+ ISFLAG(Md, PinvokeImpl);
+ ISFLAG(Md, UnmanagedExport);
+ if (!*sFlags)
+ strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]");
+
+ bool result = (((flags) & mdRTSpecialName) && !wcscmp((memberName), W(".ctor")));
+ if (result) strcat_s(sFlags, STRING_BUFFER_LEN, "[.ctor] ");
+ result = (((flags) & mdRTSpecialName) && !wcscmp((memberName), W(".cctor")));
+ if (result) strcat_s(sFlags,STRING_BUFFER_LEN, "[.cctor] ");
+ // "Reserved" flags
+ ISFLAG(Md, HasSecurity);
+ ISFLAG(Md, RequireSecObject);
+
+ VWriteLine("\t\tFlags : %s (%08x)", sFlags, flags);
+ VWriteLine("\t\tRVA : 0x%08x", ulCodeRVA);
+
+ flags = ulImplFlags;
+ sFlags[0] = 0;
+ ISFLAG(Mi, Native);
+ ISFLAG(Mi, IL);
+ ISFLAG(Mi, OPTIL);
+ ISFLAG(Mi, Runtime);
+ ISFLAG(Mi, Unmanaged);
+ ISFLAG(Mi, Managed);
+ ISFLAG(Mi, ForwardRef);
+ ISFLAG(Mi, PreserveSig);
+ ISFLAG(Mi, InternalCall);
+ ISFLAG(Mi, Synchronized);
+ ISFLAG(Mi, NoInlining);
+ if (!*sFlags)
+ strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]");
+
+ VWriteLine("\t\tImplFlags : %s (%08x)", sFlags, flags);
+
+ if (ulSigBlob)
+ DisplaySignature(pbSigBlob, ulSigBlob, "");
+ else
+ VWriteLine("\t\tERROR: no valid signature ");
+
+ DisplayGenericParams(inMethod, "\t\t");
+
+} // void MDInfo::DisplayMethodInfo()
+
+// displays the member information for the given field
+//
+
+void MDInfo::DisplayFieldInfo(mdFieldDef inField, DWORD *pdwFlags)
+{
+ HRESULT hr;
+ mdTypeDef memTypeDef;
+ WCHAR memberName[STRING_BUFFER_LEN];
+ ULONG nameLen;
+ DWORD flags;
+ PCCOR_SIGNATURE pbSigBlob;
+ ULONG ulSigBlob;
+ DWORD dwCPlusTypeFlag;
+ void const *pValue;
+ ULONG cbValue;
+#ifdef FEATURE_COMINTEROP
+ VARIANT defaultValue;
+
+ ::VariantInit(&defaultValue);
+#endif
+ hr = m_pImport->GetFieldProps( inField, &memTypeDef, memberName, STRING_BUFFER_LEN,
+ &nameLen, &flags, &pbSigBlob, &ulSigBlob, &dwCPlusTypeFlag,
+ &pValue, &cbValue);
+ if (FAILED(hr)) Error("GetFieldProps failed.", hr);
+
+ if (pdwFlags)
+ *pdwFlags = flags;
+
+#ifdef FEATURE_COMINTEROP
+ _FillVariant((BYTE)dwCPlusTypeFlag, pValue, cbValue, &defaultValue);
+#endif
+
+ char sFlags[STRING_BUFFER_LEN];
+
+ sFlags[0] = 0;
+ ISFLAG(Fd, Public);
+ ISFLAG(Fd, Private);
+ ISFLAG(Fd, Family);
+ ISFLAG(Fd, Assembly);
+ ISFLAG(Fd, FamANDAssem);
+ ISFLAG(Fd, FamORAssem);
+ ISFLAG(Fd, PrivateScope);
+ ISFLAG(Fd, Static);
+ ISFLAG(Fd, InitOnly);
+ ISFLAG(Fd, Literal);
+ ISFLAG(Fd, NotSerialized);
+ ISFLAG(Fd, SpecialName);
+ ISFLAG(Fd, RTSpecialName);
+ ISFLAG(Fd, PinvokeImpl);
+ // "Reserved" flags
+ ISFLAG(Fd, HasDefault);
+ if (!*sFlags)
+ strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]");
+
+ VWriteLine("\t\tField Name: %ls (%8.8X)", memberName, inField);
+ VWriteLine("\t\tFlags : %s (%08x)", sFlags, flags);
+#ifdef FEATURE_COMINTEROP
+ if (IsFdHasDefault(flags))
+ VWriteLine("\tDefltValue: (%s) %ls", g_szMapElementType[dwCPlusTypeFlag], VariantAsString(&defaultValue));
+#endif
+ if (!ulSigBlob) // Signature size should be non-zero for fields
+ VWriteLine("\t\tERROR: no valid signature ");
+ else
+ DisplaySignature(pbSigBlob, ulSigBlob, "");
+#ifdef FEATURE_COMINTEROP
+ ::VariantClear(&defaultValue);
+#endif
+} // void MDInfo::DisplayFieldInfo()
+
+// displays the RVA for the given global field.
+void MDInfo::DisplayFieldRVA(mdFieldDef inFieldDef)
+{
+ HRESULT hr;
+ ULONG ulRVA;
+
+ hr = m_pImport->GetRVA(inFieldDef, &ulRVA, 0);
+ if (FAILED(hr) && hr != CLDB_E_RECORD_NOTFOUND) Error("GetRVA failed.", hr);
+
+ VWriteLine("\t\tRVA : 0x%08x", ulRVA);
+} // void MDInfo::DisplayFieldRVA()
+
+// displays information about every global function.
+void MDInfo::DisplayGlobalFunctions()
+{
+ WriteLine("Global functions");
+ WriteLine("-------------------------------------------------------");
+ DisplayMethods(mdTokenNil);
+ WriteLine("");
+} // void MDInfo::DisplayGlobalFunctions()
+
+// displays information about every global field.
+void MDInfo::DisplayGlobalFields()
+{
+ WriteLine("Global fields");
+ WriteLine("-------------------------------------------------------");
+ DisplayFields(mdTokenNil, NULL, 0);
+ WriteLine("");
+} // void MDInfo::DisplayGlobalFields()
+
+// displays information about every global memberref.
+void MDInfo::DisplayGlobalMemberRefs()
+{
+ WriteLine("Global MemberRefs");
+ WriteLine("-------------------------------------------------------");
+ DisplayMemberRefs(mdTokenNil, "");
+ WriteLine("");
+} // void MDInfo::DisplayGlobalMemberRefs()
+
+// displays information about every method in a given typedef
+//
+
+void MDInfo::DisplayMethods(mdTypeDef inTypeDef)
+{
+ HCORENUM methodEnum = NULL;
+ mdToken methods[ENUM_BUFFER_SIZE];
+ DWORD flags;
+ ULONG count, totalCount = 1;
+ HRESULT hr;
+
+
+ while (SUCCEEDED(hr = m_pImport->EnumMethods( &methodEnum, inTypeDef,
+ methods, NumItems(methods), &count)) &&
+ count > 0)
+ {
+ for (ULONG i = 0; i < count; i++, totalCount++)
+ {
+ VWriteLine("\tMethod #%d (%08x) %s", totalCount, methods[i], (methods[i] == g_tkEntryPoint) ? "[ENTRYPOINT]" : "");
+ WriteLine("\t-------------------------------------------------------");
+ DisplayMethodInfo(methods[i], &flags);
+ DisplayParams(methods[i]);
+ DisplayCustomAttributes(methods[i], "\t\t");
+ DisplayPermissions(methods[i], "\t");
+ DisplayMemberRefs(methods[i], "\t");
+
+ // P-invoke data if present.
+ if (IsMdPinvokeImpl(flags))
+ DisplayPinvokeInfo(methods[i]);
+
+ WriteLine("");
+ }
+ }
+ m_pImport->CloseEnum( methodEnum);
+} // void MDInfo::DisplayMethods()
+
+
+// displays information about every field in a given typedef
+//
+
+void MDInfo::DisplayFields(mdTypeDef inTypeDef, COR_FIELD_OFFSET *rFieldOffset, ULONG cFieldOffset)
+{
+ HCORENUM fieldEnum = NULL;
+ mdToken fields[ENUM_BUFFER_SIZE];
+ ULONG count, totalCount = 1;
+ DWORD flags;
+ HRESULT hr;
+
+
+ while (SUCCEEDED(hr = m_pImport->EnumFields( &fieldEnum, inTypeDef,
+ fields, NumItems(fields), &count)) &&
+ count > 0)
+ {
+ for (ULONG i = 0; i < count; i++, totalCount++)
+ {
+ VWriteLine("\tField #%d (%08x)",totalCount, fields[i]);
+ WriteLine("\t-------------------------------------------------------");
+ DisplayFieldInfo(fields[i], &flags);
+ DisplayCustomAttributes(fields[i], "\t\t");
+ DisplayPermissions(fields[i], "\t");
+ DisplayFieldMarshal(fields[i]);
+
+ // RVA if its a global field.
+ if (inTypeDef == mdTokenNil)
+ DisplayFieldRVA(fields[i]);
+
+ // P-invoke data if present.
+ if (IsFdPinvokeImpl(flags))
+ DisplayPinvokeInfo(fields[i]);
+
+ // Display offset if present.
+ if (cFieldOffset)
+ {
+ bool found = false;
+ for (ULONG iLayout = 0; i < cFieldOffset; ++iLayout)
+ {
+ if (RidFromToken(rFieldOffset[iLayout].ridOfField) == RidFromToken(fields[i]))
+ {
+ found = true;
+ VWriteLine("\t\tOffset : 0x%08x", rFieldOffset[iLayout].ulOffset);
+ break;
+ }
+ }
+ _ASSERTE(found);
+ }
+ WriteLine("");
+ }
+ }
+ m_pImport->CloseEnum( fieldEnum);
+} // void MDInfo::DisplayFields()
+
+
+// displays information about every methodImpl in a given typedef
+//
+
+void MDInfo::DisplayMethodImpls(mdTypeDef inTypeDef)
+{
+ HCORENUM methodImplEnum = NULL;
+ mdMethodDef rtkMethodBody[ENUM_BUFFER_SIZE];
+ mdMethodDef rtkMethodDecl[ENUM_BUFFER_SIZE];
+
+ ULONG count, totalCount=1;
+ HRESULT hr;
+
+
+ while (SUCCEEDED(hr = m_pImport->EnumMethodImpls( &methodImplEnum, inTypeDef,
+ rtkMethodBody, rtkMethodDecl, NumItems(rtkMethodBody), &count)) &&
+ count > 0)
+ {
+ for (ULONG i = 0; i < count; i++, totalCount++)
+ {
+ VWriteLine("\n\tMethodImpl #%d (%08x)", totalCount, totalCount);
+ WriteLine("\t-------------------------------------------------------");
+ VWriteLine("\t\tMethod Body Token : 0x%08x", rtkMethodBody[i]);
+ VWriteLine("\t\tMethod Declaration Token : 0x%08x", rtkMethodDecl[i]);
+ WriteLine("");
+ }
+ }
+ m_pImport->CloseEnum( methodImplEnum);
+} // void MDInfo::DisplayMethodImpls()
+
+// displays information about the given parameter
+//
+
+void MDInfo::DisplayParamInfo(mdParamDef inParamDef)
+{
+ mdMethodDef md;
+ ULONG num;
+ WCHAR paramName[STRING_BUFFER_LEN];
+ ULONG nameLen;
+ DWORD flags;
+ VARIANT defValue;
+ DWORD dwCPlusFlags;
+ void const *pValue;
+ ULONG cbValue;
+
+#ifdef FEATURE_COMINTEROP
+ ::VariantInit(&defValue);
+#endif
+ HRESULT hr = m_pImport->GetParamProps( inParamDef, &md, &num, paramName, NumItems(paramName),
+ &nameLen, &flags, &dwCPlusFlags, &pValue, &cbValue);
+ if (FAILED(hr)) Error("GetParamProps failed.", hr);
+
+ _FillVariant((BYTE)dwCPlusFlags, pValue, cbValue, &defValue);
+
+ char sFlags[STRING_BUFFER_LEN];
+ sFlags[0] = 0;
+ ISFLAG(Pd, In);
+ ISFLAG(Pd, Out);
+ ISFLAG(Pd, Optional);
+ // "Reserved" flags.
+ ISFLAG(Pd, HasDefault);
+ ISFLAG(Pd, HasFieldMarshal);
+ if (!*sFlags)
+ strcpy_s(sFlags,STRING_BUFFER_LEN, "[none]");
+
+ VWrite("\t\t\t(%ld) ParamToken : (%08x) Name : %ls flags: %s (%08x)", num, inParamDef, paramName, sFlags, flags);
+#ifdef FEATURE_COMINTEROP
+ if (IsPdHasDefault(flags))
+ VWriteLine(" Default: (%s) %ls", g_szMapElementType[dwCPlusFlags], VariantAsString(&defValue));
+ else
+#endif
+ VWriteLine("");
+ DisplayCustomAttributes(inParamDef, "\t\t\t");
+
+#ifdef FEATURE_COMINTEROP
+ ::VariantClear(&defValue);
+#endif
+} // void MDInfo::DisplayParamInfo()
+
+
+// displays all parameters for a given memberdef
+//
+
+void MDInfo::DisplayParams(mdMethodDef inMethodDef)
+{
+ HCORENUM paramEnum = NULL;
+ mdParamDef params[ENUM_BUFFER_SIZE];
+ ULONG count, paramCount;
+ bool first = true;
+ HRESULT hr;
+
+
+ while (SUCCEEDED(hr = m_pImport->EnumParams( &paramEnum, inMethodDef,
+ params, NumItems(params), &count)) &&
+ count > 0)
+ {
+ if (first)
+ {
+ m_pImport->CountEnum( paramEnum, &paramCount);
+ VWriteLine("\t\t%d Parameters", paramCount);
+ }
+ for (ULONG i = 0; i < count; i++)
+ {
+ DisplayParamInfo(params[i]);
+ DisplayFieldMarshal(params[i]);
+ }
+ first = false;
+ }
+ m_pImport->CloseEnum( paramEnum);
+} // void MDInfo::DisplayParams()
+
+void MDInfo::DisplayGenericParams(mdToken tk, const char *prefix)
+{
+ HCORENUM paramEnum = NULL;
+ mdParamDef params[ENUM_BUFFER_SIZE];
+ ULONG count, paramCount;
+ bool first = true;
+ HRESULT hr;
+
+
+ while (SUCCEEDED(hr = m_pImport->EnumGenericParams( &paramEnum, tk,
+ params, NumItems(params), &count)) &&
+ count > 0)
+ {
+ if (first)
+ {
+ m_pImport->CountEnum( paramEnum, &paramCount);
+ VWriteLine("%s%d Generic Parameters", prefix, paramCount);
+ }
+ for (ULONG i = 0; i < count; i++)
+ {
+ DisplayGenericParamInfo(params[i], prefix);
+ }
+ first = false;
+ }
+ m_pImport->CloseEnum( paramEnum);
+}
+
+void MDInfo::DisplayGenericParamInfo(mdGenericParam tkParam, const char *prefix)
+{
+ ULONG ulSeq;
+ WCHAR paramName[STRING_BUFFER_LEN];
+ ULONG nameLen;
+ DWORD flags;
+ mdToken tkOwner;
+ char newprefix[30];
+ HCORENUM constraintEnum = NULL;
+ mdParamDef constraints[4];
+ ULONG count, constraintCount;
+ mdToken constraint;
+ mdToken owner;
+ bool first = true;
+
+ HRESULT hr = m_pImport->GetGenericParamProps(tkParam, &ulSeq, &flags, &tkOwner, NULL, paramName, NumItems(paramName), &nameLen);
+ if (FAILED(hr)) Error("GetGenericParamProps failed.", hr);
+
+ VWriteLine("%s\t(%ld) GenericParamToken : (%08x) Name : %ls flags: %08x Owner: %08x", prefix, ulSeq, tkParam, paramName, flags, tkOwner);
+
+ // Any constraints for the GenericParam
+ while (SUCCEEDED(hr = m_pImport->EnumGenericParamConstraints(&constraintEnum, tkParam,
+ constraints, NumItems(constraints), &count)) &&
+ count > 0)
+ {
+ if (first)
+ {
+ m_pImport->CountEnum( constraintEnum, &constraintCount);
+ VWriteLine("%s\t\t%d Constraint(s)", prefix, constraintCount);
+ }
+ VWrite("%s\t\t", prefix);
+ for (ULONG i=0; i< count; ++i)
+ {
+ hr = m_pImport->GetGenericParamConstraintProps(constraints[i], &owner, &constraint);
+ if (owner != tkParam)
+ VWrite("%08x (owner: %08x) ", constraint, owner);
+ else
+ VWrite("%08x ", constraint);
+ }
+ VWriteLine("");
+ }
+ m_pImport->CloseEnum(constraintEnum);
+
+ sprintf_s(newprefix, 30, "%s\t", prefix);
+ DisplayCustomAttributes(tkParam, newprefix);
+}
+
+LPCWSTR MDInfo::TokenName(mdToken inToken, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen)
+{
+ LPCUTF8 pName; // Token name in UTF8.
+
+ if (IsNilToken(inToken))
+ return W("");
+
+ m_pImport->GetNameFromToken(inToken, &pName);
+
+ WszMultiByteToWideChar(CP_UTF8,0, pName,-1, buffer,bufLen);
+
+ return buffer;
+} // LPCWSTR MDInfo::TokenName()
+
+// prints out name of typeref or typedef
+//
+
+LPCWSTR MDInfo::TypeDeforRefName(mdToken inToken, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen)
+{
+ if (RidFromToken(inToken))
+ {
+ if (TypeFromToken(inToken) == mdtTypeDef)
+ return (TypeDefName((mdTypeDef) inToken, buffer, bufLen));
+ else if (TypeFromToken(inToken) == mdtTypeRef)
+ return (TypeRefName((mdTypeRef) inToken, buffer, bufLen));
+ else if (TypeFromToken(inToken) == mdtTypeSpec)
+ return W("[TypeSpec]");
+ else
+ return W("[InvalidReference]");
+ }
+ else
+ return W("");
+} // LPCWSTR MDInfo::TypeDeforRefName()
+
+LPCWSTR MDInfo::MemberDeforRefName(mdToken inToken, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen)
+{
+ if (RidFromToken(inToken))
+ {
+ if (TypeFromToken(inToken) == mdtMethodDef || TypeFromToken(inToken) == mdtFieldDef)
+ return (MemberName(inToken, buffer, bufLen));
+ else if (TypeFromToken(inToken) == mdtMemberRef)
+ return (MemberRefName((mdMemberRef) inToken, buffer, bufLen));
+ else
+ return W("[InvalidReference]");
+ }
+ else
+ return W("");
+} // LPCWSTR MDInfo::MemberDeforRefName()
+
+// prints out only the name of the given typedef
+//
+//
+
+LPCWSTR MDInfo::TypeDefName(mdTypeDef inTypeDef, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen)
+{
+ HRESULT hr;
+
+ hr = m_pImport->GetTypeDefProps(
+ // [IN] The import scope.
+ inTypeDef, // [IN] TypeDef token for inquiry.
+ buffer, // [OUT] Put name here.
+ bufLen, // [IN] size of name buffer in wide chars.
+ NULL, // [OUT] put size of name (wide chars) here.
+ NULL, // [OUT] Put flags here.
+ NULL); // [OUT] Put base class TypeDef/TypeRef here.
+ if (FAILED(hr))
+ {
+ swprintf_s(buffer, bufLen, W("[Invalid TypeDef]"));
+ }
+
+ return buffer;
+} // LPCWSTR MDInfo::TypeDefName()
+
+// prints out all the properties of a given typedef
+//
+
+void MDInfo::DisplayTypeDefProps(mdTypeDef inTypeDef)
+{
+ HRESULT hr;
+ WCHAR typeDefName[STRING_BUFFER_LEN];
+ ULONG nameLen;
+ DWORD flags;
+ mdToken extends;
+ ULONG dwPacking; // Packing size of class, if specified.
+ ULONG dwSize; // Total size of class, if specified.
+
+ hr = m_pImport->GetTypeDefProps(
+ inTypeDef, // [IN] TypeDef token for inquiry.
+ typeDefName, // [OUT] Put name here.
+ STRING_BUFFER_LEN, // [IN] size of name buffer in wide chars.
+ &nameLen, // [OUT] put size of name (wide chars) here.
+ &flags, // [OUT] Put flags here.
+ &extends); // [OUT] Put base class TypeDef/TypeRef here.
+ if (FAILED(hr)) Error("GetTypeDefProps failed.", hr);
+
+ char sFlags[STRING_BUFFER_LEN];
+ WCHAR szTempBuf[STRING_BUFFER_LEN];
+
+ VWriteLine("\tTypDefName: %ls (%8.8X)",typeDefName,inTypeDef);
+ VWriteLine("\tFlags : %s (%08x)",ClassFlags(flags, sFlags), flags);
+ VWriteLine("\tExtends : %8.8X [%s] %ls",extends,TokenTypeName(extends),
+ TypeDeforRefName(extends, szTempBuf, NumItems(szTempBuf)));
+
+ hr = m_pImport->GetClassLayout(inTypeDef, &dwPacking, 0,0,0, &dwSize);
+ if (hr == S_OK)
+ VWriteLine("\tLayout : Packing:%d, Size:%d", dwPacking, dwSize);
+
+ if (IsTdNested(flags))
+ {
+ mdTypeDef tkEnclosingClass;
+
+ hr = m_pImport->GetNestedClassProps(inTypeDef, &tkEnclosingClass);
+ if (hr == S_OK)
+ {
+ VWriteLine("\tEnclosingClass : %ls (%8.8X)", TypeDeforRefName(tkEnclosingClass,
+ szTempBuf, NumItems(szTempBuf)), tkEnclosingClass);
+ }
+ else if (hr == CLDB_E_RECORD_NOTFOUND)
+ WriteLine("ERROR: EnclosingClass not found for NestedClass");
+ else
+ Error("GetNestedClassProps failed.", hr);
+ }
+} // void MDInfo::DisplayTypeDefProps()
+
+// Prints out the name of the given TypeRef
+//
+
+LPCWSTR MDInfo::TypeRefName(mdTypeRef tr, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen)
+{
+ HRESULT hr;
+
+ hr = m_pImport->GetTypeRefProps(
+ tr, // The class ref token.
+ NULL, // Resolution scope.
+ buffer, // Put the name here.
+ bufLen, // Size of the name buffer, wide chars.
+ NULL); // Put actual size of name here.
+ if (FAILED(hr))
+ {
+ swprintf_s(buffer, bufLen, W("[Invalid TypeRef]"));
+ }
+
+ return (buffer);
+} // LPCWSTR MDInfo::TypeRefName()
+
+// Prints out all the info of the given TypeRef
+//
+
+void MDInfo::DisplayTypeRefInfo(mdTypeRef tr)
+{
+ HRESULT hr;
+ mdToken tkResolutionScope;
+ WCHAR typeRefName[STRING_BUFFER_LEN];
+ ULONG nameLen;
+
+ hr = m_pImport->GetTypeRefProps(
+ tr, // The class ref token.
+ &tkResolutionScope, // ResolutionScope.
+ typeRefName, // Put the name here.
+ STRING_BUFFER_LEN, // Size of the name buffer, wide chars.
+ &nameLen); // Put actual size of name here.
+
+ if (FAILED(hr)) Error("GetTypeRefProps failed.", hr);
+
+ VWriteLine("Token: 0x%08x", tr);
+ VWriteLine("ResolutionScope: 0x%08x", tkResolutionScope);
+ VWriteLine("TypeRefName: %ls",typeRefName);
+
+ DisplayCustomAttributes(tr, "\t");
+} // void MDInfo::DisplayTypeRefInfo()
+
+
+void MDInfo::DisplayTypeSpecInfo(mdTypeSpec ts, const char *preFix)
+{
+ HRESULT hr;
+ PCCOR_SIGNATURE pvSig;
+ ULONG cbSig;
+ ULONG cb;
+
+ InitSigBuffer();
+
+ hr = m_pImport->GetTypeSpecFromToken(
+ ts, // The class ref token.
+ &pvSig,
+ &cbSig);
+
+ if (FAILED(hr)) Error("GetTypeSpecFromToken failed.", hr);
+
+// DisplaySignature(pvSig, cbSig, preFix);
+
+ if (FAILED(hr = GetOneElementType(pvSig, cbSig, &cb)))
+ goto ErrExit;
+
+ VWriteLine("%s\tTypeSpec :%s", preFix, (LPSTR)m_sigBuf.Ptr());
+
+ // Hex, too?
+ if (m_DumpFilter & dumpMoreHex)
+ {
+ char rcNewPrefix[80];
+ sprintf_s(rcNewPrefix, 80, "%s\tSignature", preFix);
+ DumpHex(rcNewPrefix, pvSig, cbSig, false, 24);
+ }
+ErrExit:
+ return;
+} // void MDInfo::DisplayTypeSpecInfo()
+
+void MDInfo::DisplayMethodSpecInfo(mdMethodSpec ms, const char *preFix)
+{
+ HRESULT hr;
+ PCCOR_SIGNATURE pvSig;
+ ULONG cbSig;
+ mdToken tk;
+
+ InitSigBuffer();
+
+ hr = m_pImport->GetMethodSpecProps(
+ ms, // The MethodSpec token
+ &tk, // The MethodDef or MemberRef
+ &pvSig, // Signature.
+ &cbSig); // Size of signature.
+
+ VWriteLine("%s\tParent : 0x%08x", preFix, tk);
+ DisplaySignature(pvSig, cbSig, preFix);
+//ErrExit:
+ return;
+} // void MDInfo::DisplayMethodSpecInfo()
+
+// Return the passed-in buffer filled with a string detailing the class flags
+// associated with the class.
+//
+
+char *MDInfo::ClassFlags(DWORD flags, __out_ecount(STRING_BUFFER_LEN) char *sFlags)
+{
+ sFlags[0] = 0;
+ ISFLAG(Td, NotPublic);
+ ISFLAG(Td, Public);
+ ISFLAG(Td, NestedPublic);
+ ISFLAG(Td, NestedPrivate);
+ ISFLAG(Td, NestedFamily);
+ ISFLAG(Td, NestedAssembly);
+ ISFLAG(Td, NestedFamANDAssem);
+ ISFLAG(Td, NestedFamORAssem);
+ ISFLAG(Td, AutoLayout);
+ ISFLAG(Td, SequentialLayout);
+ ISFLAG(Td, ExplicitLayout);
+ ISFLAG(Td, Class);
+ ISFLAG(Td, Interface);
+ ISFLAG(Td, Abstract);
+ ISFLAG(Td, Sealed);
+ ISFLAG(Td, SpecialName);
+ ISFLAG(Td, Import);
+ ISFLAG(Td, Serializable);
+ ISFLAG(Td, AnsiClass);
+ ISFLAG(Td, UnicodeClass);
+ ISFLAG(Td, AutoClass);
+ ISFLAG(Td, BeforeFieldInit);
+ ISFLAG(Td, Forwarder);
+ // "Reserved" flags
+ ISFLAG(Td, RTSpecialName);
+ ISFLAG(Td, HasSecurity);
+ ISFLAG(Td, WindowsRuntime);
+ if (!*sFlags)
+ strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]");
+
+ return sFlags;
+} // char *MDInfo::ClassFlags()
+
+// prints out all info on the given typeDef, including all information that
+// is specific to a given typedef
+//
+
+void MDInfo::DisplayTypeDefInfo(mdTypeDef inTypeDef)
+{
+ DisplayTypeDefProps(inTypeDef);
+
+ // Get field layout information.
+ HRESULT hr = NOERROR;
+ COR_FIELD_OFFSET *rFieldOffset = NULL;
+ ULONG cFieldOffset = 0;
+ hr = m_pImport->GetClassLayout(inTypeDef, NULL, rFieldOffset, 0, &cFieldOffset, NULL);
+ if (SUCCEEDED(hr) && cFieldOffset)
+ {
+ rFieldOffset = new COR_FIELD_OFFSET[cFieldOffset];
+ if (rFieldOffset == NULL)
+ Error("_calloc failed.", E_OUTOFMEMORY);
+ hr = m_pImport->GetClassLayout(inTypeDef, NULL, rFieldOffset, cFieldOffset, &cFieldOffset, NULL);
+ if (FAILED(hr)) { delete [] rFieldOffset; Error("GetClassLayout() failed.", hr); }
+ }
+
+ //No reason to display members if we're displaying fields and methods separately
+ DisplayGenericParams(inTypeDef, "\t");
+ DisplayFields(inTypeDef, rFieldOffset, cFieldOffset);
+ delete [] rFieldOffset;
+ DisplayMethods(inTypeDef);
+ DisplayProperties(inTypeDef);
+ DisplayEvents(inTypeDef);
+ DisplayMethodImpls(inTypeDef);
+ DisplayPermissions(inTypeDef, "");
+
+ DisplayInterfaceImpls(inTypeDef);
+ DisplayCustomAttributes(inTypeDef, "\t");
+} // void MDInfo::DisplayTypeDefInfo()
+
+// print out information about every the given typeDef's interfaceImpls
+//
+
+void MDInfo::DisplayInterfaceImpls(mdTypeDef inTypeDef)
+{
+ HCORENUM interfaceImplEnum = NULL;
+ mdTypeRef interfaceImpls[ENUM_BUFFER_SIZE];
+ ULONG count, totalCount = 1;
+ HRESULT hr;
+
+ while(SUCCEEDED(hr = m_pImport->EnumInterfaceImpls( &interfaceImplEnum,
+ inTypeDef,interfaceImpls,NumItems(interfaceImpls), &count)) &&
+ count > 0)
+ {
+ for (ULONG i = 0; i < count; i++, totalCount++)
+ {
+ VWriteLine("\tInterfaceImpl #%d (%08x)", totalCount, interfaceImpls[i]);
+ WriteLine("\t-------------------------------------------------------");
+ DisplayInterfaceImplInfo(interfaceImpls[i]);
+ DisplayPermissions(interfaceImpls[i], "\t");
+ WriteLine("");
+ }
+ }
+ m_pImport->CloseEnum( interfaceImplEnum);
+} // void MDInfo::DisplayInterfaceImpls()
+
+// print the information for the given interface implementation
+//
+
+void MDInfo::DisplayInterfaceImplInfo(mdInterfaceImpl inImpl)
+{
+ mdTypeDef typeDef;
+ mdToken token;
+ HRESULT hr;
+
+ WCHAR szTempBuf[STRING_BUFFER_LEN];
+
+ hr = m_pImport->GetInterfaceImplProps( inImpl, &typeDef, &token);
+ if (FAILED(hr)) Error("GetInterfaceImplProps failed.", hr);
+
+ VWriteLine("\t\tClass : %ls",TypeDeforRefName(typeDef, szTempBuf, NumItems(szTempBuf)));
+ VWriteLine("\t\tToken : %8.8X [%s] %ls",token,TokenTypeName(token), TypeDeforRefName(token, szTempBuf, NumItems(szTempBuf)));
+
+ DisplayCustomAttributes(inImpl, "\t\t");
+} // void MDInfo::DisplayInterfaceImplInfo()
+
+// displays the information for a particular property
+//
+
+void MDInfo::DisplayPropertyInfo(mdProperty inProp)
+{
+ HRESULT hr;
+ mdTypeDef typeDef;
+ WCHAR propName[STRING_BUFFER_LEN];
+ DWORD flags;
+#ifdef FEATURE_COMINTEROP
+ VARIANT defaultValue;
+#endif
+ void const *pValue;
+ ULONG cbValue;
+ DWORD dwCPlusTypeFlag;
+ mdMethodDef setter, getter, otherMethod[ENUM_BUFFER_SIZE];
+ ULONG others;
+ PCCOR_SIGNATURE pbSigBlob;
+ ULONG ulSigBlob;
+
+
+#ifdef FEATURE_COMINTEROP
+ ::VariantInit(&defaultValue);
+#endif
+ hr = m_pImport->GetPropertyProps(
+ inProp, // [IN] property token
+ &typeDef, // [OUT] typedef containing the property declarion.
+
+ propName, // [OUT] Property name
+ STRING_BUFFER_LEN, // [IN] the count of wchar of szProperty
+ NULL, // [OUT] actual count of wchar for property name
+
+ &flags, // [OUT] property flags.
+
+ &pbSigBlob, // [OUT] Signature Blob.
+ &ulSigBlob, // [OUT] Number of bytes in the signature blob.
+
+ &dwCPlusTypeFlag, // [OUT] default value
+ &pValue,
+ &cbValue,
+
+ &setter, // [OUT] setter method of the property
+ &getter, // [OUT] getter method of the property
+
+ otherMethod, // [OUT] other methods of the property
+ ENUM_BUFFER_SIZE, // [IN] size of rmdOtherMethod
+ &others); // [OUT] total number of other method of this property
+
+ if (FAILED(hr)) Error("GetPropertyProps failed.", hr);
+
+ VWriteLine("\t\tProp.Name : %ls (%8.8X)",propName,inProp);
+
+ char sFlags[STRING_BUFFER_LEN];
+
+ sFlags[0] = 0;
+ ISFLAG(Pr, SpecialName);
+ ISFLAG(Pr, RTSpecialName);
+ ISFLAG(Pr, HasDefault);
+ if (!*sFlags)
+ strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]");
+
+ VWriteLine("\t\tFlags : %s (%08x)", sFlags, flags);
+
+ if (ulSigBlob)
+ DisplaySignature(pbSigBlob, ulSigBlob, "");
+ else
+ VWriteLine("\t\tERROR: no valid signature ");
+
+ WCHAR szTempBuf[STRING_BUFFER_LEN];
+
+#ifdef FEATURE_COMINTEROP
+ _FillVariant((BYTE)dwCPlusTypeFlag, pValue, cbValue, &defaultValue);
+ VWriteLine("\t\tDefltValue: %ls",VariantAsString(&defaultValue));
+#endif
+
+ VWriteLine("\t\tSetter : (%08x) %ls",setter,MemberDeforRefName(setter, szTempBuf, NumItems(szTempBuf)));
+ VWriteLine("\t\tGetter : (%08x) %ls",getter,MemberDeforRefName(getter, szTempBuf, NumItems(szTempBuf)));
+
+ // do something with others?
+ VWriteLine("\t\t%ld Others",others);
+ DisplayCustomAttributes(inProp, "\t\t");
+
+#ifdef FEATURE_COMINTEROP
+ ::VariantClear(&defaultValue);
+#endif
+} // void MDInfo::DisplayPropertyInfo()
+
+// displays info for each property
+//
+
+void MDInfo::DisplayProperties(mdTypeDef inTypeDef)
+{
+ HCORENUM propEnum = NULL;
+ mdProperty props[ENUM_BUFFER_SIZE];
+ ULONG count, totalCount = 1;
+ HRESULT hr;
+
+
+ while(SUCCEEDED(hr = m_pImport->EnumProperties( &propEnum,
+ inTypeDef,props,NumItems(props), &count)) &&
+ count > 0)
+ {
+ for (ULONG i = 0; i < count; i++, totalCount++)
+ {
+ VWriteLine("\tProperty #%d (%08x)", totalCount, props[i]);
+ WriteLine("\t-------------------------------------------------------");
+ DisplayPropertyInfo(props[i]);
+ DisplayPermissions(props[i], "\t");
+ WriteLine("");
+ }
+ }
+ m_pImport->CloseEnum( propEnum);
+} // void MDInfo::DisplayProperties()
+
+// Display all information about a particular event
+//
+
+void MDInfo::DisplayEventInfo(mdEvent inEvent)
+{
+ HRESULT hr;
+ mdTypeDef typeDef;
+ WCHAR eventName[STRING_BUFFER_LEN];
+ DWORD flags;
+ mdToken eventType;
+ mdMethodDef addOn, removeOn, fire, otherMethod[ENUM_BUFFER_SIZE];
+ ULONG totalOther;
+
+
+ hr = m_pImport->GetEventProps(
+ // [IN] The scope.
+ inEvent, // [IN] event token
+ &typeDef, // [OUT] typedef containing the event declarion.
+
+ eventName, // [OUT] Event name
+ STRING_BUFFER_LEN, // [IN] the count of wchar of szEvent
+ NULL, // [OUT] actual count of wchar for event's name
+
+ &flags, // [OUT] Event flags.
+ &eventType, // [OUT] EventType class
+
+ &addOn, // [OUT] AddOn method of the event
+ &removeOn, // [OUT] RemoveOn method of the event
+ &fire, // [OUT] Fire method of the event
+
+ otherMethod, // [OUT] other method of the event
+ NumItems(otherMethod), // [IN] size of rmdOtherMethod
+ &totalOther); // [OUT] total number of other method of this event
+ if (FAILED(hr)) Error("GetEventProps failed.", hr);
+
+ VWriteLine("\t\tName : %ls (%8.8X)",eventName,inEvent);
+
+ char sFlags[STRING_BUFFER_LEN];
+
+ sFlags[0] = 0;
+ ISFLAG(Ev, SpecialName);
+ ISFLAG(Ev, RTSpecialName);
+ if (!*sFlags)
+ strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]");
+
+ VWriteLine("\t\tFlags : %s (%08x)", sFlags, flags);
+
+ WCHAR szTempBuf[STRING_BUFFER_LEN];
+
+ VWriteLine("\t\tEventType : %8.8X [%s]",eventType,TokenTypeName(eventType));
+ VWriteLine("\t\tAddOnMethd: (%08x) %ls",addOn,MemberDeforRefName(addOn, szTempBuf, NumItems(szTempBuf)));
+ VWriteLine("\t\tRmvOnMethd: (%08x) %ls",removeOn,MemberDeforRefName(removeOn, szTempBuf, NumItems(szTempBuf)));
+ VWriteLine("\t\tFireMethod: (%08x) %ls",fire,MemberDeforRefName(fire, szTempBuf, NumItems(szTempBuf)));
+
+ VWriteLine("\t\t%ld OtherMethods",totalOther);
+
+ DisplayCustomAttributes(inEvent, "\t\t");
+} // void MDInfo::DisplayEventInfo()
+
+// Display information about all events in a typedef
+//
+void MDInfo::DisplayEvents(mdTypeDef inTypeDef)
+{
+ HCORENUM eventEnum = NULL;
+ mdProperty events[ENUM_BUFFER_SIZE];
+ ULONG count, totalCount = 1;
+ HRESULT hr;
+
+
+ while(SUCCEEDED(hr = m_pImport->EnumEvents( &eventEnum,
+ inTypeDef,events,NumItems(events), &count)) &&
+ count > 0)
+ {
+ for (ULONG i = 0; i < count; i++, totalCount++)
+ {
+ VWriteLine("\tEvent #%d (%08x)", totalCount, events[i]);
+ WriteLine("\t-------------------------------------------------------");
+ DisplayEventInfo(events[i]);
+ DisplayPermissions(events[i], "\t");
+ WriteLine("");
+ }
+ }
+ m_pImport->CloseEnum( eventEnum);
+} // void MDInfo::DisplayEvents()
+
+
+// print info for the passed-in custom attribute
+// This function is used to print the custom attribute information for both TypeDefs and
+// MethodDefs which need slightly different formatting. preFix helps fix it up.
+//
+
+void MDInfo::DisplayCustomAttributeInfo(mdCustomAttribute inValue, const char *preFix)
+{
+ const BYTE *pValue; // The custom value.
+ ULONG cbValue; // Length of the custom value.
+ HRESULT hr; // A result.
+ mdToken tkObj; // Attributed object.
+ mdToken tkType; // Type of the custom attribute.
+ mdToken tk; // For name lookup.
+ LPCUTF8 pMethName=0; // Name of custom attribute ctor, if any.
+ CQuickBytes qSigName; // Buffer to pretty-print signature.
+ PCCOR_SIGNATURE pSig=0; // Signature of ctor.
+ ULONG cbSig; // Size of the signature.
+ BOOL bCoffSymbol = false; // true for coff symbol CA's.
+ WCHAR rcName[MAX_CLASS_NAME]; // Name of the type.
+
+ hr = m_pImport->GetCustomAttributeProps( // S_OK or error.
+ inValue, // The attribute.
+ &tkObj, // The attributed object
+ &tkType, // The attributes type.
+ (const void**)&pValue, // Put pointer to data here.
+ &cbValue); // Put size here.
+ if (FAILED(hr)) Error("GetCustomAttributeProps failed.", hr);
+
+ VWriteLine("%s\tCustomAttribute Type: %08x", preFix, tkType);
+
+ // Get the name of the memberref or methoddef.
+ tk = tkType;
+ rcName[0] = L'\0';
+ // Get the member name, and the parent token.
+ switch (TypeFromToken(tk))
+ {
+ case mdtMemberRef:
+ hr = m_pImport->GetNameFromToken(tk, &pMethName);
+ if (FAILED(hr)) Error("GetNameFromToken failed.", hr);
+ hr = m_pImport->GetMemberRefProps( tk, &tk, 0, 0, 0, &pSig, &cbSig);
+ if (FAILED(hr)) Error("GetMemberRefProps failed.", hr);
+ break;
+ case mdtMethodDef:
+ hr = m_pImport->GetNameFromToken(tk, &pMethName);
+ if (FAILED(hr)) Error("GetNameFromToken failed.", hr);
+ hr = m_pImport->GetMethodProps(tk, &tk, 0, 0, 0, 0, &pSig, &cbSig, 0, 0);
+ if (FAILED(hr)) Error("GetMethodProps failed.", hr);
+ break;
+ } // switch
+
+ // Get the type name.
+ switch (TypeFromToken(tk))
+ {
+ case mdtTypeDef:
+ hr = m_pImport->GetTypeDefProps(tk, rcName,MAX_CLASS_NAME,0, 0,0);
+ if (FAILED(hr)) Error("GetTypeDefProps failed.", hr);
+ break;
+ case mdtTypeRef:
+ hr = m_pImport->GetTypeRefProps(tk, 0, rcName,MAX_CLASS_NAME,0);
+ if (FAILED(hr)) Error("GetTypeRefProps failed.", hr);
+ break;
+ } // switch
+
+
+ if (pSig && pMethName)
+ {
+ int iLen;
+ LPWSTR pwzName = (LPWSTR)(new WCHAR[iLen= 1+(ULONG32)strlen(pMethName)]);
+ if(pwzName)
+ {
+ WszMultiByteToWideChar(CP_UTF8,0, pMethName,-1, pwzName,iLen);
+ PrettyPrintSigLegacy(pSig, cbSig, pwzName, &qSigName, m_pImport);
+ delete [] pwzName;
+ }
+ }
+
+ VWrite("%s\tCustomAttributeName: %ls", preFix, rcName);
+ if (pSig && pMethName)
+ VWrite(" :: %S", qSigName.Ptr());
+
+ // Keep track of coff overhead.
+ if (!wcscmp(W("__DecoratedName"), rcName))
+ {
+ bCoffSymbol = true;
+ g_cbCoffNames += cbValue + 6;
+ }
+ WriteLine("");
+
+ VWriteLine("%s\tLength: %ld", preFix, cbValue);
+ char newPreFix[40];
+ sprintf_s(newPreFix, 40, "%s\tValue ", preFix);
+ DumpHex(newPreFix, pValue, cbValue);
+ if (bCoffSymbol)
+ VWriteLine("%s\t %s", preFix, pValue);
+
+ // Try to decode the constructor blob. This is incomplete, but covers the most popular cases.
+ if (pSig)
+ { // Interpret the signature.
+ PCCOR_SIGNATURE ps = pSig;
+ ULONG cb;
+ ULONG ulData;
+ ULONG cParams;
+ ULONG ulVal;
+ UINT8 u1 = 0;
+ UINT16 u2 = 0;
+ UINT32 u4 = 0;
+ UINT64 u8 = 0;
+ unsigned __int64 uI64;
+ double dblVal;
+ ULONG cbVal;
+ LPCUTF8 pStr;
+ CustomAttributeParser CA(pValue, cbValue);
+ CA.ValidateProlog();
+
+ // Get the calling convention.
+ cb = CorSigUncompressData(ps, &ulData);
+ ps += cb;
+ // Get the count of params.
+ cb = CorSigUncompressData(ps, &cParams);
+ ps += cb;
+ // Get the return value.
+ cb = CorSigUncompressData(ps, &ulData);
+ ps += cb;
+ if (ulData == ELEMENT_TYPE_VOID)
+ {
+ VWrite("%s\tctor args: (", preFix);
+ // For each param...
+ for (ULONG i=0; i<cParams; ++i)
+ { // Get the next param type.
+ cb = CorSigUncompressData(ps, &ulData);
+ ps += cb;
+ if (i) Write(", ");
+ DoObject:
+ switch (ulData)
+ {
+ // For ET_OBJECT, the next byte in the blob is the ET of the actual data.
+ case ELEMENT_TYPE_OBJECT:
+ CA.GetU1(&u1);
+ ulData = u1;
+ goto DoObject;
+ case ELEMENT_TYPE_I1:
+ case ELEMENT_TYPE_U1:
+ CA.GetU1(&u1);
+ ulVal = u1;
+ goto PrintVal;
+ case ELEMENT_TYPE_I2:
+ case ELEMENT_TYPE_U2:
+ CA.GetU2(&u2);
+ ulVal = u2;
+ goto PrintVal;
+ case ELEMENT_TYPE_I4:
+ case ELEMENT_TYPE_U4:
+ CA.GetU4(&u4);
+ ulVal = u4;
+ PrintVal:
+ VWrite("%d", ulVal);
+ break;
+ case ELEMENT_TYPE_STRING:
+ CA.GetString(&pStr, &cbVal);
+ VWrite("\"%s\"", pStr);
+ break;
+ // The only class type that we accept is Type, which is stored as a string.
+ case ELEMENT_TYPE_CLASS:
+ // Eat the class type.
+ cb = CorSigUncompressData(ps, &ulData);
+ ps += cb;
+ // Get the name of the type.
+ CA.GetString(&pStr, &cbVal);
+ VWrite("typeof(%s)", pStr);
+ break;
+ case SERIALIZATION_TYPE_TYPE:
+ CA.GetString(&pStr, &cbVal);
+ VWrite("typeof(%s)", pStr);
+ break;
+ case ELEMENT_TYPE_I8:
+ case ELEMENT_TYPE_U8:
+ CA.GetU8(&u8);
+ uI64 = u8;
+ VWrite("%#lx", uI64);
+ break;
+ case ELEMENT_TYPE_R4:
+ dblVal = CA.GetR4();
+ VWrite("%f", dblVal);
+ break;
+ case ELEMENT_TYPE_R8:
+ dblVal = CA.GetR8();
+ VWrite("%f", dblVal);
+ break;
+ default:
+ // bail...
+ i = cParams;
+ Write(" <can not decode> ");
+ break;
+ }
+ }
+ WriteLine(")");
+ }
+
+ }
+ WriteLine("");
+} // void MDInfo::DisplayCustomAttributeInfo()
+
+// Print all custom values for the given token
+// This function is used to print the custom value information for all tokens.
+// which need slightly different formatting. preFix helps fix it up.
+//
+
+void MDInfo::DisplayCustomAttributes(mdToken inToken, const char *preFix)
+{
+ HCORENUM customAttributeEnum = NULL;
+ mdTypeRef customAttributes[ENUM_BUFFER_SIZE];
+ ULONG count, totalCount = 1;
+ HRESULT hr;
+
+ while(SUCCEEDED(hr = m_pImport->EnumCustomAttributes( &customAttributeEnum, inToken, 0,
+ customAttributes, NumItems(customAttributes), &count)) &&
+ count > 0)
+ {
+ for (ULONG i = 0; i < count; i++, totalCount++)
+ {
+ VWriteLine("%sCustomAttribute #%d (%08x)", preFix, totalCount, customAttributes[i]);
+ VWriteLine("%s-------------------------------------------------------", preFix);
+ DisplayCustomAttributeInfo(customAttributes[i], preFix);
+ }
+ }
+ m_pImport->CloseEnum( customAttributeEnum);
+} // void MDInfo::DisplayCustomAttributes()
+
+// Show the passed-in token's permissions
+//
+//
+
+void MDInfo::DisplayPermissions(mdToken tk, const char *preFix)
+{
+ HCORENUM permissionEnum = NULL;
+ mdPermission permissions[ENUM_BUFFER_SIZE];
+ ULONG count, totalCount = 1;
+ HRESULT hr;
+
+
+ while (SUCCEEDED(hr = m_pImport->EnumPermissionSets( &permissionEnum,
+ tk, 0, permissions, NumItems(permissions), &count)) &&
+ count > 0)
+ {
+ for (ULONG i = 0; i < count; i++, totalCount++)
+ {
+ VWriteLine("%s\tPermission #%d (%08x)", preFix, totalCount, permissions[i]);
+ VWriteLine("%s\t-------------------------------------------------------", preFix);
+ DisplayPermissionInfo(permissions[i], preFix);
+ WriteLine("");
+ }
+ }
+ m_pImport->CloseEnum( permissionEnum);
+} // void MDInfo::DisplayPermissions()
+
+// print properties of given rolecheck
+//
+//
+
+void MDInfo::DisplayPermissionInfo(mdPermission inPermission, const char *preFix)
+{
+ DWORD dwAction;
+ const BYTE *pvPermission;
+ ULONG cbPermission;
+ const char *flagDesc = NULL;
+ char newPreFix[STRING_BUFFER_LEN];
+ HRESULT hr;
+
+
+ hr = m_pImport->GetPermissionSetProps( inPermission, &dwAction,
+ (const void**)&pvPermission, &cbPermission);
+ if (FAILED(hr)) Error("GetPermissionSetProps failed.", hr);
+
+ switch(dwAction)
+ {
+ case dclActionNil: flagDesc = "ActionNil"; break;
+ case dclRequest: flagDesc = "Request"; break;
+ case dclDemand: flagDesc = "Demand"; break;
+ case dclAssert: flagDesc = "Assert"; break;
+ case dclDeny: flagDesc = "Deny"; break;
+ case dclPermitOnly: flagDesc = "PermitOnly"; break;
+ case dclLinktimeCheck: flagDesc = "LinktimeCheck"; break;
+ case dclInheritanceCheck: flagDesc = "InheritanceCheck"; break;
+ case dclRequestMinimum: flagDesc = "RequestMinimum"; break;
+ case dclRequestOptional: flagDesc = "RequestOptional"; break;
+ case dclRequestRefuse: flagDesc = "RequestRefuse"; break;
+ case dclPrejitGrant: flagDesc = "PrejitGrant"; break;
+ case dclPrejitDenied: flagDesc = "PrejitDenied"; break;
+ case dclNonCasDemand: flagDesc = "NonCasDemand"; break;
+ case dclNonCasLinkDemand: flagDesc = "NonCasLinkDemand"; break;
+ case dclNonCasInheritance: flagDesc = "NonCasInheritance"; break;
+
+ }
+ VWriteLine("%s\t\tAction : %s", preFix, flagDesc);
+ VWriteLine("%s\t\tBlobLen : %d", preFix, cbPermission);
+ if (cbPermission)
+ {
+ sprintf_s(newPreFix, STRING_BUFFER_LEN, "%s\tBlob", preFix);
+ DumpHex(newPreFix, pvPermission, cbPermission, false, 24);
+ }
+
+ sprintf_s (newPreFix, STRING_BUFFER_LEN, "\t\t%s", preFix);
+ DisplayCustomAttributes(inPermission, newPreFix);
+} // void MDInfo::DisplayPermissionInfo()
+
+
+// simply prints out the given GUID in standard form
+
+LPWSTR MDInfo::GUIDAsString(GUID inGuid, __out_ecount(bufLen) LPWSTR guidString, ULONG bufLen)
+{
+ StringFromGUID2(inGuid, guidString, bufLen);
+ return guidString;
+} // LPWSTR MDInfo::GUIDAsString()
+
+#ifdef FEATURE_COMINTEROP
+LPCWSTR MDInfo::VariantAsString(VARIANT *pVariant)
+{
+ HRESULT hr = S_OK;
+ if (V_VT(pVariant) == VT_UNKNOWN)
+ {
+ _ASSERTE(V_UNKNOWN(pVariant) == NULL);
+ return W("<NULL>");
+ }
+ else if (SUCCEEDED(hr = ::VariantChangeType(pVariant, pVariant, 0, VT_BSTR)))
+ return V_BSTR(pVariant);
+ else if (hr == DISP_E_BADVARTYPE && V_VT(pVariant) == VT_I8)
+ {
+ // allocate the bstr.
+ char szStr[32];
+ WCHAR wszStr[32];
+ // Set variant type to bstr.
+ V_VT(pVariant) = VT_BSTR;
+ // Create the ansi string.
+ sprintf_s(szStr, 32, "%I64d", V_CY(pVariant).int64);
+ // Convert to unicode.
+ WszMultiByteToWideChar(CP_ACP, 0, szStr, -1, wszStr, 32);
+ // convert to bstr and set variant value.
+ V_BSTR(pVariant) = ::SysAllocString(wszStr);
+ if (V_BSTR(pVariant) == NULL)
+ Error("SysAllocString() failed.", E_OUTOFMEMORY);
+ return V_BSTR(pVariant);
+ }
+ else
+ return W("ERROR");
+
+} // LPWSTR MDInfo::VariantAsString()
+#endif
+
+bool TrySigUncompress(PCCOR_SIGNATURE pData, // [IN] compressed data
+ ULONG *pDataOut, // [OUT] the expanded *pData
+ ULONG *cbCur)
+{
+ ULONG ulSize = CorSigUncompressData(pData, pDataOut);
+ if (ulSize == (ULONG)-1)
+ {
+ *cbCur = ulSize;
+ return false;
+ } else
+ {
+ *cbCur += ulSize;
+ return true;
+ }
+}
+
+void MDInfo::DisplayFieldMarshal(mdToken inToken)
+{
+ PCCOR_SIGNATURE pvNativeType; // [OUT] native type of this field
+ ULONG cbNativeType; // [OUT] the count of bytes of *ppvNativeType
+ HRESULT hr;
+
+
+ hr = m_pImport->GetFieldMarshal( inToken, &pvNativeType, &cbNativeType);
+ if (FAILED(hr) && hr != CLDB_E_RECORD_NOTFOUND) Error("GetFieldMarshal failed.", hr);
+ if (hr != CLDB_E_RECORD_NOTFOUND)
+ {
+ ULONG cbCur = 0;
+ ULONG ulData;
+ ULONG ulStrLoc;
+
+ char szNTDesc[STRING_BUFFER_LEN];
+
+ while (cbCur < cbNativeType)
+ {
+ ulStrLoc = 0;
+
+ ulData = NATIVE_TYPE_MAX;
+ if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur))
+ continue;
+ if (ulData >= sizeof(g_szNativeType)/sizeof(*g_szNativeType))
+ {
+ cbCur = (ULONG)-1;
+ continue;
+ }
+ ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "%s ", g_szNativeType[ulData]);
+ switch (ulData)
+ {
+ case NATIVE_TYPE_FIXEDSYSSTRING:
+ {
+ if (cbCur < cbNativeType)
+ {
+ if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur))
+ continue;
+ ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "{StringElementCount: %d} ",ulData);
+ }
+ }
+ break;
+ case NATIVE_TYPE_FIXEDARRAY:
+ {
+ if (cbCur < cbNativeType)
+ {
+ if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur))
+ continue;
+ ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "{ArrayElementCount: %d",ulData);
+
+ if (cbCur < cbNativeType)
+ {
+ if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur))
+ continue;
+ ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, ", ArrayElementType(NT): %d",ulData);
+ }
+
+ ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc,"}");
+ }
+ }
+ break;
+ case NATIVE_TYPE_ARRAY:
+ {
+ if (cbCur < cbNativeType)
+ {
+ BOOL bElemTypeSpecified;
+
+ if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur))
+ continue;
+ if (ulData != NATIVE_TYPE_MAX)
+ {
+ ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "{ArrayElementType(NT): %d", ulData);
+ bElemTypeSpecified = TRUE;
+ }
+ else
+ {
+ ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "{");
+ bElemTypeSpecified = FALSE;
+ }
+
+ if (cbCur < cbNativeType)
+ {
+ if (bElemTypeSpecified)
+ ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, ", ");
+
+ if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur))
+ continue;
+ ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "SizeParamIndex: %d",ulData);
+
+ if (cbCur < cbNativeType)
+ {
+ if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur))
+ continue;
+ ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, ", SizeParamMultiplier: %d",ulData);
+
+ if (cbCur < cbNativeType)
+ {
+ if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur))
+ continue;
+ ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, ", SizeConst: %d",ulData);
+ }
+ }
+ }
+
+ ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "}");
+ }
+ }
+ break;
+ case NATIVE_TYPE_SAFEARRAY:
+ {
+ if (cbCur < cbNativeType)
+ {
+ if (!TrySigUncompress(&pvNativeType[cbCur], &ulData, &cbCur))
+ continue;
+ ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "{SafeArraySubType(VT): %d, ",ulData);
+
+ // Extract the element type name if it is specified.
+ if (cbCur < cbNativeType)
+ {
+ LPUTF8 strTemp = NULL;
+ int strLen = 0;
+ int ByteCountLength = 0;
+
+ strLen = CPackedLen::GetLength(&pvNativeType[cbCur], &ByteCountLength);
+ cbCur += ByteCountLength;
+ strTemp = (LPUTF8)(new char[strLen + 1]);
+ if(strTemp)
+ {
+ memcpy(strTemp, (LPUTF8)&pvNativeType[cbCur], strLen);
+ strTemp[strLen] = 0;
+ ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "ElementTypeName: %s}", strTemp);
+ cbCur += strLen;
+ _ASSERTE(cbCur == cbNativeType);
+ delete [] strTemp;
+ }
+ }
+ else
+ {
+ ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "ElementTypeName: }");
+ }
+ }
+ }
+ break;
+ case NATIVE_TYPE_CUSTOMMARSHALER:
+ {
+ LPUTF8 strTemp = NULL;
+ int strLen = 0;
+ int ByteCountLength = 0;
+
+ // Extract the typelib GUID.
+ strLen = CPackedLen::GetLength(&pvNativeType[cbCur], &ByteCountLength);
+ cbCur += ByteCountLength;
+ strTemp = (LPUTF8)(new char[strLen + 1]);
+ if(strTemp)
+ {
+ memcpy(strTemp, (LPUTF8)&pvNativeType[cbCur], strLen);
+ strTemp[strLen] = 0;
+ ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "{Typelib: %s, ", strTemp);
+ cbCur += strLen;
+ _ASSERTE(cbCur < cbNativeType);
+ delete [] strTemp;
+ }
+ // Extract the name of the native type.
+ strLen = CPackedLen::GetLength(&pvNativeType[cbCur], &ByteCountLength);
+ cbCur += ByteCountLength;
+ strTemp = (LPUTF8)(new char[strLen + 1]);
+ if(strTemp)
+ {
+ memcpy(strTemp, (LPUTF8)&pvNativeType[cbCur], strLen);
+ strTemp[strLen] = 0;
+ ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "Native: %s, ", strTemp);
+ cbCur += strLen;
+ _ASSERTE(cbCur < cbNativeType);
+ delete [] strTemp;
+ }
+
+ // Extract the name of the custom marshaler.
+ strLen = CPackedLen::GetLength(&pvNativeType[cbCur], &ByteCountLength);
+ cbCur += ByteCountLength;
+ strTemp = (LPUTF8)(new char[strLen + 1]);
+ if(strTemp)
+ {
+ memcpy(strTemp, (LPUTF8)&pvNativeType[cbCur], strLen);
+ strTemp[strLen] = 0;
+ ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "Marshaler: %s, ", strTemp);
+ cbCur += strLen;
+ _ASSERTE(cbCur < cbNativeType);
+ delete [] strTemp;
+ }
+ // Extract the cookie string.
+ strLen = CPackedLen::GetLength(&pvNativeType[cbCur], &ByteCountLength);
+ cbCur += ByteCountLength;
+ if (strLen > 0)
+ {
+ strTemp = (LPUTF8)(new char[strLen + 1]);
+ if(strTemp)
+ {
+ memcpy(strTemp, (LPUTF8)&pvNativeType[cbCur], strLen);
+ strTemp[strLen] = 0;
+ ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "Cookie: ");
+
+ // Copy the cookie string and transform the embedded nulls into \0's.
+ for (int i = 0; i < strLen - 1; i++, cbCur++)
+ {
+ if (strTemp[i] == 0)
+ ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "\\0");
+ else
+ szNTDesc[ulStrLoc++] = strTemp[i];
+ }
+ szNTDesc[ulStrLoc++] = strTemp[strLen - 1];
+ cbCur++;
+ delete [] strTemp;
+ }
+ }
+ else
+ {
+ ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "Cookie: ");
+ }
+
+ // Finish the custom marshaler native type description.
+ ulStrLoc += sprintf_s(szNTDesc + ulStrLoc, STRING_BUFFER_LEN-ulStrLoc, "}");
+ _ASSERTE(cbCur <= cbNativeType);
+ }
+ break;
+ default:
+ {
+ // normal nativetype element: do nothing
+ }
+ }
+ VWriteLine("\t\t\t\t%s",szNTDesc);
+ if (ulData >= NATIVE_TYPE_MAX)
+ break;
+ }
+ if (cbCur == (ULONG)-1)
+ {
+ // There was something that we didn't grok in the signature.
+ // Just dump out the blob as hex
+ VWrite("\t\t\t\t{", szNTDesc);
+ while (cbNativeType--)
+ VWrite(" %2.2X", *pvNativeType++);
+ VWriteLine(" }");
+ }
+ }
+} // void MDInfo::DisplayFieldMarshal()
+
+void MDInfo::DisplayPinvokeInfo(mdToken inToken)
+{
+ HRESULT hr = NOERROR;
+ DWORD flags;
+ WCHAR rcImport[512];
+ mdModuleRef tkModuleRef;
+
+ char sFlags[STRING_BUFFER_LEN];
+
+ hr = m_pImport->GetPinvokeMap(inToken, &flags, rcImport,
+ NumItems(rcImport), 0, &tkModuleRef);
+ if (FAILED(hr))
+ {
+ if (hr != CLDB_E_RECORD_NOTFOUND)
+ VWriteLine("ERROR: GetPinvokeMap failed.", hr);
+ return;
+ }
+
+ WriteLine("\t\tPinvoke Map Data:");
+ VWriteLine("\t\tEntry point: %S", rcImport);
+ VWriteLine("\t\tModule ref: %08x", tkModuleRef);
+
+ sFlags[0] = 0;
+ ISFLAG(Pm, NoMangle);
+ ISFLAG(Pm, CharSetNotSpec);
+ ISFLAG(Pm, CharSetAnsi);
+ ISFLAG(Pm, CharSetUnicode);
+ ISFLAG(Pm, CharSetAuto);
+ ISFLAG(Pm, SupportsLastError);
+ ISFLAG(Pm, CallConvWinapi);
+ ISFLAG(Pm, CallConvCdecl);
+ ISFLAG(Pm, CallConvStdcall);
+ ISFLAG(Pm, CallConvThiscall);
+ ISFLAG(Pm, CallConvFastcall);
+
+ ISFLAG(Pm, BestFitEnabled);
+ ISFLAG(Pm, BestFitDisabled);
+ ISFLAG(Pm, BestFitUseAssem);
+ ISFLAG(Pm, ThrowOnUnmappableCharEnabled);
+ ISFLAG(Pm, ThrowOnUnmappableCharDisabled);
+ ISFLAG(Pm, ThrowOnUnmappableCharUseAssem);
+ if (!*sFlags)
+ strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]");
+
+ VWriteLine("\t\tMapping flags: %s (%08x)", sFlags, flags);
+} // void MDInfo::DisplayPinvokeInfo()
+
+
+/////////////////////////////////////////////////////////////////////////
+// void DisplaySignature(PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob);
+//
+// Display COM+ signature -- taken from cordump.cpp's DumpSignature
+/////////////////////////////////////////////////////////////////////////
+void MDInfo::DisplaySignature(PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, const char *preFix)
+{
+ ULONG cbCur = 0;
+ ULONG cb;
+ // 428793: Prefix complained correctly about unitialized data.
+ ULONG ulData = (ULONG) IMAGE_CEE_CS_CALLCONV_MAX;
+ ULONG ulArgs;
+ HRESULT hr = NOERROR;
+ ULONG ulSigBlobStart = ulSigBlob;
+
+ // initialize sigBuf
+ InitSigBuffer();
+
+ cb = CorSigUncompressData(pbSigBlob, &ulData);
+ VWriteLine("%s\t\tCallCnvntn: %s", preFix, (g_strCalling[ulData & IMAGE_CEE_CS_CALLCONV_MASK]));
+ if (cb>ulSigBlob)
+ goto ErrExit;
+ cbCur += cb;
+ ulSigBlob -= cb;
+
+ if (ulData & IMAGE_CEE_CS_CALLCONV_HASTHIS)
+ VWriteLine("%s\t\thasThis ", preFix);
+ if (ulData & IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS)
+ VWriteLine("%s\t\texplicit ", preFix);
+ if (ulData & IMAGE_CEE_CS_CALLCONV_GENERIC)
+ VWriteLine("%s\t\tgeneric ", preFix);
+
+ // initialize sigBuf
+ InitSigBuffer();
+ if ( isCallConv(ulData,IMAGE_CEE_CS_CALLCONV_FIELD) )
+ {
+
+ // display field type
+ if (FAILED(hr = GetOneElementType(&pbSigBlob[cbCur], ulSigBlob, &cb)))
+ goto ErrExit;
+ VWriteLine("%s\t\tField type: %s", preFix, (LPSTR)m_sigBuf.Ptr());
+ if (cb>ulSigBlob)
+ goto ErrExit;
+ cbCur += cb;
+ ulSigBlob -= cb;
+ }
+ else
+ {
+ if (ulData & IMAGE_CEE_CS_CALLCONV_GENERIC)
+ {
+ ULONG ulTyArgs;
+ cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulTyArgs);
+ if (cb>ulSigBlob)
+ goto ErrExit;
+ cbCur += cb;
+ ulSigBlob -= cb;
+ VWriteLine("%s\t\tType Arity:%d ", preFix, ulTyArgs);
+ }
+ cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulArgs);
+ if (cb>ulSigBlob)
+ goto ErrExit;
+ cbCur += cb;
+ ulSigBlob -= cb;
+
+ if (ulData != IMAGE_CEE_CS_CALLCONV_LOCAL_SIG && ulData != IMAGE_CEE_CS_CALLCONV_GENERICINST)
+ {
+ // display return type when it is not a local varsig
+ if (FAILED(hr = GetOneElementType(&pbSigBlob[cbCur], ulSigBlob, &cb)))
+ goto ErrExit;
+ VWriteLine("%s\t\tReturnType:%s", preFix, (LPSTR)m_sigBuf.Ptr());
+ if (cb>ulSigBlob)
+ goto ErrExit;
+ cbCur += cb;
+ ulSigBlob -= cb;
+ }
+
+ // display count of argument
+ // display arguments
+ if (ulSigBlob)
+ VWriteLine("%s\t\t%ld Arguments", preFix, ulArgs);
+ else
+ VWriteLine("%s\t\tNo arguments.", preFix);
+
+ ULONG i = 0;
+ while (i < ulArgs && ulSigBlob > 0)
+ {
+ ULONG ulDataTemp;
+
+ // Handle the sentinal for varargs because it isn't counted in the args.
+ CorSigUncompressData(&pbSigBlob[cbCur], &ulDataTemp);
+ ++i;
+
+ // initialize sigBuf
+ InitSigBuffer();
+
+ if (FAILED(hr = GetOneElementType(&pbSigBlob[cbCur], ulSigBlob, &cb)))
+ goto ErrExit;
+
+ VWriteLine("%s\t\t\tArgument #%ld: %s",preFix, i, (LPSTR)m_sigBuf.Ptr());
+
+ if (cb>ulSigBlob)
+ goto ErrExit;
+
+ cbCur += cb;
+ ulSigBlob -= cb;
+ }
+ }
+
+ // Nothing consumed but not yet counted.
+ cb = 0;
+
+ErrExit:
+ // We should have consumed all signature blob. If not, dump the sig in hex.
+ // Also dump in hex if so requested.
+ if (m_DumpFilter & dumpMoreHex || ulSigBlob != 0)
+ {
+ // Did we not consume enough, or try to consume too much?
+ if (cb > ulSigBlob)
+ WriteLine("\tERROR IN SIGNATURE: Signature should be larger.");
+ else
+ if (cb < ulSigBlob)
+ {
+ VWrite("\tERROR IN SIGNATURE: Not all of signature blob was consumed. %d byte(s) remain", ulSigBlob);
+ // If it is short, just append it to the end.
+ if (ulSigBlob < 4)
+ {
+ Write(": ");
+ for (; ulSigBlob; ++cbCur, --ulSigBlob)
+ VWrite("%02x ", pbSigBlob[cbCur]);
+ WriteLine("");
+ goto ErrExit2;
+ }
+ WriteLine("");
+ }
+
+ // Any appropriate error message has been issued. Dump sig in hex, as determined
+ // by error or command line switch.
+ cbCur = 0;
+ ulSigBlob = ulSigBlobStart;
+ char rcNewPrefix[80];
+ sprintf_s(rcNewPrefix, 80, "%s\t\tSignature ", preFix);
+ DumpHex(rcNewPrefix, pbSigBlob, ulSigBlob, false, 24);
+ }
+ErrExit2:
+ if (FAILED(hr))
+ Error("ERROR!! Bad signature blob value!");
+ return;
+} // void MDInfo::DisplaySignature()
+
+
+/////////////////////////////////////////////////////////////////////////
+// HRESULT GetOneElementType(mdScope tkScope, BYTE *pbSigBlob, ULONG ulSigBlob, ULONG *pcb)
+//
+// Adds description of element type to the end of buffer -- caller must ensure
+// buffer is large enough.
+/////////////////////////////////////////////////////////////////////////
+HRESULT MDInfo::GetOneElementType(PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, ULONG *pcb)
+{
+ HRESULT hr = S_OK; // A result.
+ ULONG cbCur = 0;
+ ULONG cb;
+ ULONG ulData = ELEMENT_TYPE_MAX;
+ ULONG ulTemp;
+ int iTemp = 0;
+ mdToken tk;
+
+ cb = CorSigUncompressData(pbSigBlob, &ulData);
+ cbCur += cb;
+
+ // Handle the modifiers.
+ if (ulData & ELEMENT_TYPE_MODIFIER)
+ {
+ if (ulData == ELEMENT_TYPE_SENTINEL)
+ IfFailGo(AddToSigBuffer("<ELEMENT_TYPE_SENTINEL>"));
+ else if (ulData == ELEMENT_TYPE_PINNED)
+ IfFailGo(AddToSigBuffer("PINNED"));
+ else
+ {
+ hr = E_FAIL;
+ goto ErrExit;
+ }
+ if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb)))
+ goto ErrExit;
+ cbCur += cb;
+ goto ErrExit;
+ }
+
+ // Handle the underlying element types.
+ if (ulData >= ELEMENT_TYPE_MAX)
+ {
+ hr = E_FAIL;
+ goto ErrExit;
+ }
+ while (ulData == ELEMENT_TYPE_PTR || ulData == ELEMENT_TYPE_BYREF)
+ {
+ IfFailGo(AddToSigBuffer(" "));
+ IfFailGo(AddToSigBuffer(g_szMapElementType[ulData]));
+ cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulData);
+ cbCur += cb;
+ }
+ IfFailGo(AddToSigBuffer(" "));
+ IfFailGo(AddToSigBuffer(g_szMapElementType[ulData]));
+ if (CorIsPrimitiveType((CorElementType)ulData) ||
+ ulData == ELEMENT_TYPE_TYPEDBYREF ||
+ ulData == ELEMENT_TYPE_OBJECT ||
+ ulData == ELEMENT_TYPE_I ||
+ ulData == ELEMENT_TYPE_U)
+ {
+ // If this is a primitive type, we are done
+ goto ErrExit;
+ }
+ if (ulData == ELEMENT_TYPE_VALUETYPE ||
+ ulData == ELEMENT_TYPE_CLASS ||
+ ulData == ELEMENT_TYPE_CMOD_REQD ||
+ ulData == ELEMENT_TYPE_CMOD_OPT)
+ {
+ cb = CorSigUncompressToken(&pbSigBlob[cbCur], &tk);
+ cbCur += cb;
+
+ // get the name of type ref. Don't care if truncated
+ if (TypeFromToken(tk) == mdtTypeDef || TypeFromToken(tk) == mdtTypeRef)
+ {
+ sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, " %ls",TypeDeforRefName(tk, m_szTempBuf, NumItems(m_szTempBuf)));
+ IfFailGo(AddToSigBuffer(m_tempFormatBuffer));
+ }
+ else
+ {
+ _ASSERTE(TypeFromToken(tk) == mdtTypeSpec);
+ sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, " %8x", tk);
+ IfFailGo(AddToSigBuffer(m_tempFormatBuffer));
+ }
+ if (ulData == ELEMENT_TYPE_CMOD_REQD ||
+ ulData == ELEMENT_TYPE_CMOD_OPT)
+ {
+ if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb)))
+ goto ErrExit;
+ cbCur += cb;
+ }
+
+ goto ErrExit;
+ }
+ if (ulData == ELEMENT_TYPE_SZARRAY)
+ {
+ // display the base type of SZARRAY
+ if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb)))
+ goto ErrExit;
+ cbCur += cb;
+ goto ErrExit;
+ }
+ // instantiated type
+ if (ulData == ELEMENT_TYPE_GENERICINST)
+ {
+ // display the type constructor
+ if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb)))
+ goto ErrExit;
+ cbCur += cb;
+ ULONG numArgs;
+ cb = CorSigUncompressData(&pbSigBlob[cbCur], &numArgs);
+ cbCur += cb;
+ IfFailGo(AddToSigBuffer("<"));
+
+ while (numArgs > 0)
+ {
+ if (cbCur > ulSigBlob)
+ goto ErrExit;
+ if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb)))
+ goto ErrExit;
+ cbCur += cb;
+ --numArgs;
+ if (numArgs > 0)
+ IfFailGo(AddToSigBuffer(","));
+ }
+ IfFailGo(AddToSigBuffer(">"));
+ goto ErrExit;
+ }
+ if (ulData == ELEMENT_TYPE_VAR)
+ {
+ ULONG index;
+ cb = CorSigUncompressData(&pbSigBlob[cbCur], &index);
+ cbCur += cb;
+ sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, "!%d", index);
+ IfFailGo(AddToSigBuffer(m_tempFormatBuffer));
+ goto ErrExit;
+ }
+ if (ulData == ELEMENT_TYPE_MVAR)
+ {
+ ULONG index;
+ cb = CorSigUncompressData(&pbSigBlob[cbCur], &index);
+ cbCur += cb;
+ sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, "!!%d", index);
+ IfFailGo(AddToSigBuffer(m_tempFormatBuffer));
+ goto ErrExit;
+ }
+ if (ulData == ELEMENT_TYPE_FNPTR)
+ {
+ cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulData);
+ cbCur += cb;
+ if (ulData & IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS)
+ IfFailGo(AddToSigBuffer(" explicit"));
+ if (ulData & IMAGE_CEE_CS_CALLCONV_HASTHIS)
+ IfFailGo(AddToSigBuffer(" hasThis"));
+
+ IfFailGo(AddToSigBuffer(" "));
+ IfFailGo(AddToSigBuffer(g_strCalling[ulData & IMAGE_CEE_CS_CALLCONV_MASK]));
+
+ // Get number of args
+ ULONG numArgs;
+ cb = CorSigUncompressData(&pbSigBlob[cbCur], &numArgs);
+ cbCur += cb;
+
+ // do return type
+ if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb)))
+ goto ErrExit;
+ cbCur += cb;
+
+ IfFailGo(AddToSigBuffer("("));
+ while (numArgs > 0)
+ {
+ if (cbCur > ulSigBlob)
+ goto ErrExit;
+ if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb)))
+ goto ErrExit;
+ cbCur += cb;
+ --numArgs;
+ if (numArgs > 0)
+ IfFailGo(AddToSigBuffer(","));
+ }
+ IfFailGo(AddToSigBuffer(" )"));
+ goto ErrExit;
+ }
+
+ if(ulData != ELEMENT_TYPE_ARRAY) return E_FAIL;
+
+ // display the base type of SDARRAY
+ if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb)))
+ goto ErrExit;
+ cbCur += cb;
+
+ // display the rank of MDARRAY
+ cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulData);
+ cbCur += cb;
+ sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, " %d", ulData);
+ IfFailGo(AddToSigBuffer(m_tempFormatBuffer));
+ if (ulData == 0)
+ // we are done if no rank specified
+ goto ErrExit;
+
+ // how many dimensions have size specified?
+ cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulData);
+ cbCur += cb;
+ sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, " %d", ulData);
+ IfFailGo(AddToSigBuffer(m_tempFormatBuffer));
+ while (ulData)
+ {
+ cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulTemp);
+ sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, " %d", ulTemp);
+ IfFailGo(AddToSigBuffer(m_tempFormatBuffer));
+ cbCur += cb;
+ ulData--;
+ }
+ // how many dimensions have lower bounds specified?
+ cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulData);
+ cbCur += cb;
+ sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, " %d", ulData);
+ IfFailGo(AddToSigBuffer(m_tempFormatBuffer));
+ while (ulData)
+ {
+
+ cb = CorSigUncompressSignedInt(&pbSigBlob[cbCur], &iTemp);
+ sprintf_s(m_tempFormatBuffer, STRING_BUFFER_LEN, " %d", iTemp);
+ IfFailGo(AddToSigBuffer(m_tempFormatBuffer));
+ cbCur += cb;
+ ulData--;
+ }
+
+ErrExit:
+ if (cbCur > ulSigBlob)
+ hr = E_FAIL;
+ *pcb = cbCur;
+ return hr;
+} // HRESULT MDInfo::GetOneElementType()
+
+// Display the fields of the N/Direct custom value structure.
+
+void MDInfo::DisplayCorNativeLink(COR_NATIVE_LINK *pCorNLnk, const char *preFix)
+{
+ // Print the LinkType.
+ const char *curField = "\tLink Type : ";
+ switch(pCorNLnk->m_linkType)
+ {
+ case nltNone:
+ VWriteLine("%s%s%s(%02x)", preFix, curField, "nltNone", pCorNLnk->m_linkType);
+ break;
+ case nltAnsi:
+ VWriteLine("%s%s%s(%02x)", preFix, curField, "nltAnsi", pCorNLnk->m_linkType);
+ break;
+ case nltUnicode:
+ VWriteLine("%s%s%s(%02x)", preFix, curField, "nltUnicode", pCorNLnk->m_linkType);
+ break;
+ case nltAuto:
+ VWriteLine("%s%s%s(%02x)", preFix, curField, "nltAuto", pCorNLnk->m_linkType);
+ break;
+ default:
+ _ASSERTE(!"Invalid Native Link Type!");
+ }
+
+ // Print the link flags
+ curField = "\tLink Flags : ";
+ switch(pCorNLnk->m_flags)
+ {
+ case nlfNone:
+ VWriteLine("%s%s%s(%02x)", preFix, curField, "nlfNone", pCorNLnk->m_flags);
+ break;
+ case nlfLastError:
+ VWriteLine("%s%s%s(%02x)", preFix, curField, "nlfLastError", pCorNLnk->m_flags);
+ break;
+ default:
+ _ASSERTE(!"Invalid Native Link Flags!");
+ }
+
+ // Print the entry point.
+ WCHAR memRefName[STRING_BUFFER_LEN];
+ HRESULT hr;
+ hr = m_pImport->GetMemberRefProps( pCorNLnk->m_entryPoint, NULL, memRefName,
+ STRING_BUFFER_LEN, NULL, NULL, NULL);
+ if (FAILED(hr)) Error("GetMemberRefProps failed.", hr);
+ VWriteLine("%s\tEntry Point : %ls (0x%08x)", preFix, memRefName, pCorNLnk->m_entryPoint);
+} // void MDInfo::DisplayCorNativeLink()
+
+// Fills given varaint with value given in pValue and of type in bCPlusTypeFlag
+//
+// Taken from MetaInternal.cpp
+
+HRESULT _FillVariant(
+ BYTE bCPlusTypeFlag,
+ const void *pValue,
+ ULONG cbValue,
+ VARIANT *pvar)
+{
+ HRESULT hr = NOERROR;
+ switch (bCPlusTypeFlag)
+ {
+ case ELEMENT_TYPE_BOOLEAN:
+ V_VT(pvar) = VT_BOOL;
+ V_BOOL(pvar) = *((BYTE*)pValue); //*((UNALIGNED VARIANT_BOOL *)pValue);
+ break;
+ case ELEMENT_TYPE_I1:
+ V_VT(pvar) = VT_I1;
+ V_I1(pvar) = *((CHAR*)pValue);
+ break;
+ case ELEMENT_TYPE_U1:
+ V_VT(pvar) = VT_UI1;
+ V_UI1(pvar) = *((BYTE*)pValue);
+ break;
+ case ELEMENT_TYPE_I2:
+ V_VT(pvar) = VT_I2;
+ V_I2(pvar) = GET_UNALIGNED_VAL16(pValue);
+ break;
+ case ELEMENT_TYPE_U2:
+ case ELEMENT_TYPE_CHAR:
+ V_VT(pvar) = VT_UI2;
+ V_UI2(pvar) = GET_UNALIGNED_VAL16(pValue);
+ break;
+ case ELEMENT_TYPE_I4:
+ V_VT(pvar) = VT_I4;
+ V_I4(pvar) = GET_UNALIGNED_VAL32(pValue);
+ break;
+ case ELEMENT_TYPE_U4:
+ V_VT(pvar) = VT_UI4;
+ V_UI4(pvar) = GET_UNALIGNED_VAL32(pValue);
+ break;
+ case ELEMENT_TYPE_R4:
+ {
+ V_VT(pvar) = VT_R4;
+ __int32 Value = GET_UNALIGNED_VAL32(pValue);
+ V_R4(pvar) = (float &)Value;
+ }
+ break;
+ case ELEMENT_TYPE_R8:
+ {
+ V_VT(pvar) = VT_R8;
+ __int64 Value = GET_UNALIGNED_VAL64(pValue);
+ V_R8(pvar) = (double &) Value;
+ }
+
+ break;
+ case ELEMENT_TYPE_STRING:
+ {
+ V_VT(pvar) = VT_BSTR;
+ WCHAR *TempString;;
+#if BIGENDIAN
+ TempString = (WCHAR *)alloca(cbValue);
+ memcpy(TempString, pValue, cbValue);
+ SwapStringLength(TempString, cbValue/sizeof(WCHAR));
+#else
+ TempString = (WCHAR *)pValue;
+#endif
+ // allocated bstr here
+ V_BSTR(pvar) = ::SysAllocStringLen((LPWSTR)TempString, cbValue/sizeof(WCHAR));
+ if (V_BSTR(pvar) == NULL)
+ hr = E_OUTOFMEMORY;
+ }
+ break;
+ case ELEMENT_TYPE_CLASS:
+ V_VT(pvar) = VT_UNKNOWN;
+ V_UNKNOWN(pvar) = NULL;
+ // _ASSERTE( GET_UNALIGNED_VAL32(pValue) == 0);
+ break;
+ case ELEMENT_TYPE_I8:
+ V_VT(pvar) = VT_I8;
+ V_CY(pvar).int64 = GET_UNALIGNED_VAL64(pValue);
+ break;
+ case ELEMENT_TYPE_U8:
+ V_VT(pvar) = VT_UI8;
+ V_CY(pvar).int64 = GET_UNALIGNED_VAL64(pValue);
+ break;
+ case ELEMENT_TYPE_VOID:
+ V_VT(pvar) = VT_EMPTY;
+ break;
+ default:
+ _ASSERTE(!"bad constant value type!");
+ }
+
+ return hr;
+} // HRESULT _FillVariant()
+
+void MDInfo::DisplayAssembly()
+{
+ if (m_pAssemblyImport)
+ {
+ DisplayAssemblyInfo();
+ DisplayAssemblyRefs();
+ DisplayFiles();
+ DisplayExportedTypes();
+ DisplayManifestResources();
+ }
+} // void MDInfo::DisplayAssembly()
+
+void MDInfo::DisplayAssemblyInfo()
+{
+ HRESULT hr;
+ mdAssembly mda;
+ const BYTE *pbPublicKey;
+ ULONG cbPublicKey;
+ ULONG ulHashAlgId;
+ WCHAR szName[STRING_BUFFER_LEN];
+ ASSEMBLYMETADATA MetaData;
+ DWORD dwFlags;
+
+ hr = m_pAssemblyImport->GetAssemblyFromScope(&mda);
+ if (hr == CLDB_E_RECORD_NOTFOUND)
+ return;
+ else if (FAILED(hr)) Error("GetAssemblyFromScope() failed.", hr);
+
+ // Get the required sizes for the arrays of locales, processors etc.
+ ZeroMemory(&MetaData, sizeof(ASSEMBLYMETADATA));
+ hr = m_pAssemblyImport->GetAssemblyProps(mda,
+ NULL, NULL, // Public Key.
+ NULL, // Hash Algorithm.
+ NULL, 0, NULL, // Name.
+ &MetaData,
+ NULL); // Flags.
+ if (FAILED(hr)) Error("GetAssemblyProps() failed.", hr);
+
+ // Allocate space for the arrays in the ASSEMBLYMETADATA structure.
+ if (MetaData.cbLocale)
+ MetaData.szLocale = new WCHAR[MetaData.cbLocale];
+ if (MetaData.ulProcessor)
+ MetaData.rProcessor = new DWORD[MetaData.ulProcessor];
+ if (MetaData.ulOS)
+ MetaData.rOS = new OSINFO[MetaData.ulOS];
+
+ hr = m_pAssemblyImport->GetAssemblyProps(mda,
+ (const void **)&pbPublicKey, &cbPublicKey,
+ &ulHashAlgId,
+ szName, STRING_BUFFER_LEN, NULL,
+ &MetaData,
+ &dwFlags);
+ if (FAILED(hr)) Error("GetAssemblyProps() failed.", hr);
+ WriteLine("Assembly");
+ WriteLine("-------------------------------------------------------");
+ VWriteLine("\tToken: 0x%08x", mda);
+ VWriteLine("\tName : %ls", szName);
+ DumpHex("\tPublic Key ", pbPublicKey, cbPublicKey, false, 24);
+ VWriteLine("\tHash Algorithm : 0x%08x", ulHashAlgId);
+ DisplayASSEMBLYMETADATA(&MetaData);
+ if(MetaData.szLocale) delete [] MetaData.szLocale;
+ if(MetaData.rProcessor) delete [] MetaData.rProcessor;
+ if(MetaData.rOS) delete [] MetaData.rOS;
+
+ char sFlags[STRING_BUFFER_LEN];
+ DWORD flags = dwFlags;
+
+ sFlags[0] = 0;
+ ISFLAG(Af, PublicKey);
+ ISFLAG(Af, Retargetable);
+ ISFLAG(AfContentType_, WindowsRuntime);
+
+ if (!*sFlags)
+ strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]");
+
+ VWriteLine("\tFlags : %s (%08x)", sFlags, dwFlags);
+ DisplayCustomAttributes(mda, "\t");
+ DisplayPermissions(mda, "\t");
+ WriteLine("");
+} // void MDInfo::DisplayAssemblyInfo()
+
+void MDInfo::DisplayAssemblyRefs()
+{
+ HCORENUM assemblyRefEnum = NULL;
+ mdAssemblyRef AssemblyRefs[ENUM_BUFFER_SIZE];
+ ULONG count;
+ ULONG totalCount = 1;
+ HRESULT hr;
+
+ while (SUCCEEDED(hr = m_pAssemblyImport->EnumAssemblyRefs( &assemblyRefEnum,
+ AssemblyRefs, NumItems(AssemblyRefs), &count)) &&
+ count > 0)
+ {
+ for (ULONG i = 0; i < count; i++, totalCount++)
+ {
+ VWriteLine("AssemblyRef #%d (%08x)", totalCount, AssemblyRefs[i]);
+ WriteLine("-------------------------------------------------------");
+ DisplayAssemblyRefInfo(AssemblyRefs[i]);
+ WriteLine("");
+ }
+ }
+ m_pAssemblyImport->CloseEnum(assemblyRefEnum);
+} // void MDInfo::DisplayAssemblyRefs()
+
+void MDInfo::DisplayAssemblyRefInfo(mdAssemblyRef inAssemblyRef)
+{
+ HRESULT hr;
+ const BYTE *pbPublicKeyOrToken;
+ ULONG cbPublicKeyOrToken;
+ WCHAR szName[STRING_BUFFER_LEN];
+ ASSEMBLYMETADATA MetaData;
+ const BYTE *pbHashValue;
+ ULONG cbHashValue;
+ DWORD dwFlags;
+
+ VWriteLine("\tToken: 0x%08x", inAssemblyRef);
+
+ // Get sizes for the arrays in the ASSEMBLYMETADATA structure.
+ ZeroMemory(&MetaData, sizeof(ASSEMBLYMETADATA));
+ hr = m_pAssemblyImport->GetAssemblyRefProps(inAssemblyRef,
+ NULL, NULL, // Public Key or Token.
+ NULL, 0, NULL, // Name.
+ &MetaData,
+ NULL, NULL, // HashValue.
+ NULL); // Flags.
+ if (FAILED(hr)) Error("GetAssemblyRefProps() failed.", hr);
+
+ // Allocate space for the arrays in the ASSEMBLYMETADATA structure.
+ if (MetaData.cbLocale)
+ MetaData.szLocale = new WCHAR[MetaData.cbLocale];
+ if (MetaData.ulProcessor)
+ MetaData.rProcessor = new DWORD[MetaData.ulProcessor];
+ if (MetaData.ulOS)
+ MetaData.rOS = new OSINFO[MetaData.ulOS];
+
+ hr = m_pAssemblyImport->GetAssemblyRefProps(inAssemblyRef,
+ (const void **)&pbPublicKeyOrToken, &cbPublicKeyOrToken,
+ szName, STRING_BUFFER_LEN, NULL,
+ &MetaData,
+ (const void **)&pbHashValue, &cbHashValue,
+ &dwFlags);
+ if (FAILED(hr)) Error("GetAssemblyRefProps() failed.", hr);
+
+ DumpHex("\tPublic Key or Token", pbPublicKeyOrToken, cbPublicKeyOrToken, false, 24);
+ VWriteLine("\tName: %ls", szName);
+ DisplayASSEMBLYMETADATA(&MetaData);
+ if(MetaData.szLocale) delete [] MetaData.szLocale;
+ if(MetaData.rProcessor) delete [] MetaData.rProcessor;
+ if(MetaData.rOS) delete [] MetaData.rOS;
+ DumpHex("\tHashValue Blob", pbHashValue, cbHashValue, false, 24);
+
+ char sFlags[STRING_BUFFER_LEN];
+ DWORD flags = dwFlags;
+
+ sFlags[0] = 0;
+ ISFLAG(Af, PublicKey);
+ ISFLAG(Af, Retargetable);
+ ISFLAG(AfContentType_, WindowsRuntime);
+#if 0
+ ISFLAG(Af, LegacyLibrary);
+ ISFLAG(Af, LegacyPlatform);
+ ISFLAG(Af, Library);
+ ISFLAG(Af, Platform);
+#endif
+ if (!*sFlags)
+ strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]");
+
+ VWriteLine("\tFlags: %s (%08x)", sFlags, dwFlags);
+ DisplayCustomAttributes(inAssemblyRef, "\t");
+ WriteLine("");
+} // void MDInfo::DisplayAssemblyRefInfo()
+
+void MDInfo::DisplayFiles()
+{
+ HCORENUM fileEnum = NULL;
+ mdFile Files[ENUM_BUFFER_SIZE];
+ ULONG count;
+ ULONG totalCount = 1;
+ HRESULT hr;
+
+ while (SUCCEEDED(hr = m_pAssemblyImport->EnumFiles( &fileEnum,
+ Files, NumItems(Files), &count)) &&
+ count > 0)
+ {
+ for (ULONG i = 0; i < count; i++, totalCount++)
+ {
+ VWriteLine("File #%d (%08x)", totalCount, Files[i]);
+ WriteLine("-------------------------------------------------------");
+ DisplayFileInfo(Files[i]);
+ WriteLine("");
+ }
+ }
+ m_pAssemblyImport->CloseEnum(fileEnum);
+} // void MDInfo::DisplayFiles()
+
+void MDInfo::DisplayFileInfo(mdFile inFile)
+{
+ HRESULT hr;
+ WCHAR szName[STRING_BUFFER_LEN];
+ const BYTE *pbHashValue;
+ ULONG cbHashValue;
+ DWORD dwFlags;
+
+ VWriteLine("\tToken: 0x%08x", inFile);
+
+ hr = m_pAssemblyImport->GetFileProps(inFile,
+ szName, STRING_BUFFER_LEN, NULL,
+ (const void **)&pbHashValue, &cbHashValue,
+ &dwFlags);
+ if (FAILED(hr)) Error("GetFileProps() failed.", hr);
+ VWriteLine("\tName : %ls", szName);
+ DumpHex("\tHashValue Blob ", pbHashValue, cbHashValue, false, 24);
+
+ char sFlags[STRING_BUFFER_LEN];
+ DWORD flags = dwFlags;
+
+ sFlags[0] = 0;
+ ISFLAG(Ff, ContainsMetaData);
+ ISFLAG(Ff, ContainsNoMetaData);
+ if (!*sFlags)
+ strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]");
+
+ VWriteLine("\tFlags : %s (%08x)", sFlags, dwFlags);
+ DisplayCustomAttributes(inFile, "\t");
+ WriteLine("");
+
+} // MDInfo::DisplayFileInfo()
+
+void MDInfo::DisplayExportedTypes()
+{
+ HCORENUM comTypeEnum = NULL;
+ mdExportedType ExportedTypes[ENUM_BUFFER_SIZE];
+ ULONG count;
+ ULONG totalCount = 1;
+ HRESULT hr;
+
+ while (SUCCEEDED(hr = m_pAssemblyImport->EnumExportedTypes( &comTypeEnum,
+ ExportedTypes, NumItems(ExportedTypes), &count)) &&
+ count > 0)
+ {
+ for (ULONG i = 0; i < count; i++, totalCount++)
+ {
+ VWriteLine("ExportedType #%d (%08x)", totalCount, ExportedTypes[i]);
+ WriteLine("-------------------------------------------------------");
+ DisplayExportedTypeInfo(ExportedTypes[i]);
+ WriteLine("");
+ }
+ }
+ m_pAssemblyImport->CloseEnum(comTypeEnum);
+} // void MDInfo::DisplayExportedTypes()
+
+void MDInfo::DisplayExportedTypeInfo(mdExportedType inExportedType)
+{
+ HRESULT hr;
+ WCHAR szName[STRING_BUFFER_LEN];
+ mdToken tkImplementation;
+ mdTypeDef tkTypeDef;
+ DWORD dwFlags;
+ char sFlags[STRING_BUFFER_LEN];
+
+ VWriteLine("\tToken: 0x%08x", inExportedType);
+
+ hr = m_pAssemblyImport->GetExportedTypeProps(inExportedType,
+ szName, STRING_BUFFER_LEN, NULL,
+ &tkImplementation,
+ &tkTypeDef,
+ &dwFlags);
+ if (FAILED(hr)) Error("GetExportedTypeProps() failed.", hr);
+ VWriteLine("\tName: %ls", szName);
+ VWriteLine("\tImplementation token: 0x%08x", tkImplementation);
+ VWriteLine("\tTypeDef token: 0x%08x", tkTypeDef);
+ VWriteLine("\tFlags : %s (%08x)",ClassFlags(dwFlags, sFlags), dwFlags);
+ DisplayCustomAttributes(inExportedType, "\t");
+ WriteLine("");
+} // void MDInfo::DisplayExportedTypeInfo()
+
+void MDInfo::DisplayManifestResources()
+{
+ HCORENUM manifestResourceEnum = NULL;
+ mdManifestResource ManifestResources[ENUM_BUFFER_SIZE];
+ ULONG count;
+ ULONG totalCount = 1;
+ HRESULT hr;
+
+ while (SUCCEEDED(hr = m_pAssemblyImport->EnumManifestResources( &manifestResourceEnum,
+ ManifestResources, NumItems(ManifestResources), &count)) &&
+ count > 0)
+ {
+ for (ULONG i = 0; i < count; i++, totalCount++)
+ {
+ VWriteLine("ManifestResource #%d (%08x)", totalCount, ManifestResources[i]);
+ WriteLine("-------------------------------------------------------");
+ DisplayManifestResourceInfo(ManifestResources[i]);
+ WriteLine("");
+ }
+ }
+ m_pAssemblyImport->CloseEnum(manifestResourceEnum);
+} // void MDInfo::DisplayManifestResources()
+
+void MDInfo::DisplayManifestResourceInfo(mdManifestResource inManifestResource)
+{
+ HRESULT hr;
+ WCHAR szName[STRING_BUFFER_LEN];
+ mdToken tkImplementation;
+ DWORD dwOffset;
+ DWORD dwFlags;
+
+ VWriteLine("\tToken: 0x%08x", inManifestResource);
+
+ hr = m_pAssemblyImport->GetManifestResourceProps(inManifestResource,
+ szName, STRING_BUFFER_LEN, NULL,
+ &tkImplementation,
+ &dwOffset,
+ &dwFlags);
+ if (FAILED(hr)) Error("GetManifestResourceProps() failed.", hr);
+ VWriteLine("Name: %ls", szName);
+ VWriteLine("Implementation token: 0x%08x", tkImplementation);
+ VWriteLine("Offset: 0x%08x", dwOffset);
+
+ char sFlags[STRING_BUFFER_LEN];
+ DWORD flags = dwFlags;
+
+ sFlags[0] = 0;
+ ISFLAG(Mr, Public);
+ ISFLAG(Mr, Private);
+ if (!*sFlags)
+ strcpy_s(sFlags, STRING_BUFFER_LEN, "[none]");
+
+ VWriteLine("\tFlags: %s (%08x)", sFlags, dwFlags);
+ DisplayCustomAttributes(inManifestResource, "\t");
+ WriteLine("");
+} // void MDInfo::DisplayManifestResourceInfo()
+
+void MDInfo::DisplayASSEMBLYMETADATA(ASSEMBLYMETADATA *pMetaData)
+{
+ ULONG i;
+
+ VWriteLine("\tVersion: %d.%d.%d.%d", pMetaData->usMajorVersion, pMetaData->usMinorVersion, pMetaData->usBuildNumber, pMetaData->usRevisionNumber);
+ VWriteLine("\tMajor Version: 0x%08x", pMetaData->usMajorVersion);
+ VWriteLine("\tMinor Version: 0x%08x", pMetaData->usMinorVersion);
+ VWriteLine("\tBuild Number: 0x%08x", pMetaData->usBuildNumber);
+ VWriteLine("\tRevision Number: 0x%08x", pMetaData->usRevisionNumber);
+ VWriteLine("\tLocale: %ls", pMetaData->cbLocale ? pMetaData->szLocale : W("<null>"));
+ for (i = 0; i < pMetaData->ulProcessor; i++)
+ VWriteLine("\tProcessor #%ld: 0x%08x", i+1, pMetaData->rProcessor[i]);
+ for (i = 0; i < pMetaData->ulOS; i++)
+ {
+ VWriteLine("\tOS #%ld:", i+1);
+ VWriteLine("\t\tOS Platform ID: 0x%08x", pMetaData->rOS[i].dwOSPlatformId);
+ VWriteLine("\t\tOS Major Version: 0x%08x", pMetaData->rOS[i].dwOSMajorVersion);
+ VWriteLine("\t\tOS Minor Version: 0x%08x", pMetaData->rOS[i].dwOSMinorVersion);
+ }
+} // void MDInfo::DisplayASSEMBLYMETADATA()
+
+void MDInfo::DisplayUserStrings()
+{
+ HCORENUM stringEnum = NULL; // string enumerator.
+ mdString Strings[ENUM_BUFFER_SIZE]; // String tokens from enumerator.
+ CQuickArray<WCHAR> rUserString; // Buffer to receive string.
+ WCHAR *szUserString; // Working pointer into buffer.
+ ULONG chUserString; // Size of user string.
+ CQuickArray<char> rcBuf; // Buffer to hold the BLOB version of the string.
+ char *szBuf; // Working pointer into buffer.
+ ULONG chBuf; // Saved size of the user string.
+ ULONG count; // Items returned from enumerator.
+ ULONG totalCount = 1; // Running count of strings.
+ bool bUnprint = false; // Is an unprintable character found?
+ HRESULT hr; // A result.
+ while (SUCCEEDED(hr = m_pImport->EnumUserStrings( &stringEnum,
+ Strings, NumItems(Strings), &count)) &&
+ count > 0)
+ {
+ if (totalCount == 1)
+ { // If only one, it is the NULL string, so don't print it.
+ WriteLine("User Strings");
+ WriteLine("-------------------------------------------------------");
+ }
+ for (ULONG i = 0; i < count; i++, totalCount++)
+ {
+ do { // Try to get the string into the existing buffer.
+ hr = m_pImport->GetUserString( Strings[i], rUserString.Ptr(),(ULONG32)rUserString.MaxSize(), &chUserString);
+ if (hr == CLDB_S_TRUNCATION)
+ { // Buffer wasn't big enough, try to enlarge it.
+ if (FAILED(rUserString.ReSizeNoThrow(chUserString)))
+ Error("malloc failed.", E_OUTOFMEMORY);
+ continue;
+ }
+ } while (hr == CLDB_S_TRUNCATION);
+ if (FAILED(hr)) Error("GetUserString failed.", hr);
+
+ szUserString = rUserString.Ptr();
+ chBuf = chUserString;
+
+ VWrite("%08x : (%2d) L\"", Strings[i], chUserString);
+ for (ULONG j=0; j<chUserString; j++)
+ {
+ switch (*szUserString)
+ {
+ case 0:
+ Write("\\0"); break;
+ case L'\r':
+ Write("\\r"); break;
+ case L'\n':
+ Write("\\n"); break;
+ case L'\t':
+ Write("\\t"); break;
+ default:
+ if (iswprint(*szUserString))
+ VWrite("%lc", *szUserString);
+ else
+ {
+ bUnprint = true;
+ Write(".");
+ }
+ break;
+ }
+ ++szUserString;
+ if((j>0)&&((j&0x7F)==0)) WriteLine("");
+ }
+ WriteLine("\"");
+
+ // Print the user string as a blob if an unprintable character is found.
+ if (bUnprint)
+ {
+ bUnprint = false;
+ szUserString = rUserString.Ptr();
+ if (FAILED(hr = rcBuf.ReSizeNoThrow(81))) //(chBuf * 5 + 1);
+ Error("ReSize failed.", hr);
+ szBuf = rcBuf.Ptr();
+ ULONG j,k;
+ WriteLine("\t\tUser string has unprintables, hex format below:");
+ for (j = 0,k=0; j < chBuf; j++)
+ {
+ sprintf_s (&szBuf[k*5], 81, "%04x ", szUserString[j]);
+ k++;
+ if((k==16)||(j == (chBuf-1)))
+ {
+ szBuf[k*5] = '\0';
+ VWriteLine("\t\t%s", szBuf);
+ k=0;
+ }
+ }
+ }
+ }
+ }
+ if (stringEnum)
+ m_pImport->CloseEnum(stringEnum);
+} // void MDInfo::DisplayUserStrings()
+
+void MDInfo::DisplayUnsatInfo()
+{
+ HRESULT hr = S_OK;
+
+ HCORENUM henum = 0;
+ mdToken tk;
+ ULONG cMethods;
+
+ Write("\nUnresolved Externals\n");
+ Write("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
+
+ while ( (hr = m_pImport->EnumUnresolvedMethods(
+ &henum,
+ &tk,
+ 1,
+ &cMethods)) == S_OK && cMethods )
+ {
+ if ( TypeFromToken(tk) == mdtMethodDef )
+ {
+ // a method definition without implementation
+ DisplayMethodInfo( tk );
+ }
+ else if ( TypeFromToken(tk) == mdtMemberRef )
+ {
+ // an unresolved MemberRef to a global function
+ DisplayMemberRefInfo( tk, "" );
+ }
+ else
+ {
+ _ASSERTE(!"Unknown token kind!");
+ }
+ }
+ m_pImport->CloseEnum(henum);
+} // void MDInfo::DisplayUnsatInfo()
+
+//*******************************************************************************
+// This code is used for debugging purposes only. This will just print out the
+// entire database.
+//*******************************************************************************
+const char *MDInfo::DumpRawNameOfType(ULONG iType)
+{
+ if (iType <= iRidMax)
+ {
+ const char *pNameTable;
+ m_pTables->GetTableInfo(iType, 0,0,0,0, &pNameTable);
+ return pNameTable;
+ }
+ else
+ // Is the field a coded token?
+ if (iType <= iCodedTokenMax)
+ {
+ int iCdTkn = iType - iCodedToken;
+ const char *pNameCdTkn;
+ m_pTables->GetCodedTokenInfo(iCdTkn, 0,0, &pNameCdTkn);
+ return pNameCdTkn;
+ }
+
+ // Fixed type.
+ switch (iType)
+ {
+ case iBYTE:
+ return "BYTE";
+ case iSHORT:
+ return "short";
+ case iUSHORT:
+ return "USHORT";
+ case iLONG:
+ return "long";
+ case iULONG:
+ return "ULONG";
+ case iSTRING:
+ return "string";
+ case iGUID:
+ return "GUID";
+ case iBLOB:
+ return "blob";
+ }
+ // default:
+ static char buf[30];
+ sprintf_s(buf, 30, "unknown type 0x%02x", iType);
+ return buf;
+} // const char *MDInfo::DumpRawNameOfType()
+
+void MDInfo::DumpRawCol(ULONG ixTbl, ULONG ixCol, ULONG rid, bool bStats)
+{
+ ULONG ulType; // Type of a column.
+ ULONG ulVal; // Value of a column.
+ LPCUTF8 pString; // Pointer to a string.
+ const void *pBlob; // Pointer to a blob.
+ ULONG cb; // Size of something.
+
+ m_pTables->GetColumn(ixTbl, ixCol, rid, &ulVal);
+ m_pTables->GetColumnInfo(ixTbl, ixCol, 0, 0, &ulType, 0);
+
+ if (ulType <= iRidMax)
+ {
+ const char *pNameTable;
+ m_pTables->GetTableInfo(ulType, 0,0,0,0, &pNameTable);
+ VWrite("%s[%x]", pNameTable, ulVal);
+ }
+ else
+ // Is the field a coded token?
+ if (ulType <= iCodedTokenMax)
+ {
+ int iCdTkn = ulType - iCodedToken;
+ const char *pNameCdTkn;
+ m_pTables->GetCodedTokenInfo(iCdTkn, 0,0, &pNameCdTkn);
+ VWrite("%s[%08x]", pNameCdTkn, ulVal);
+ }
+ else
+ {
+ // Fixed type.
+ switch (ulType)
+ {
+ case iBYTE:
+ VWrite("%02x", ulVal);
+ break;
+ case iSHORT:
+ case iUSHORT:
+ VWrite("%04x", ulVal);
+ break;
+ case iLONG:
+ case iULONG:
+ VWrite("%08x", ulVal);
+ break;
+ case iSTRING:
+ if (ulVal && (m_DumpFilter & dumpNames))
+ {
+ m_pTables->GetString(ulVal, &pString);
+ VWrite("(%x)\"%s\"", ulVal, pString);
+ }
+ else
+ VWrite("string#%x", ulVal);
+ if (bStats && ulVal)
+ {
+ m_pTables->GetString(ulVal, &pString);
+ cb = (ULONG) strlen(pString) + 1;
+ VWrite("(%d)", cb);
+ }
+ break;
+ case iGUID:
+ VWrite("guid#%x", ulVal);
+ if (bStats && ulVal)
+ {
+ VWrite("(16)");
+ }
+ break;
+ case iBLOB:
+ VWrite("blob#%x", ulVal);
+ if (bStats && ulVal)
+ {
+ m_pTables->GetBlob(ulVal, &cb, &pBlob);
+ cb += 1;
+ if (cb > 128)
+ cb += 1;
+ if (cb > 16535)
+ cb += 1;
+ VWrite("(%d)", cb);
+ }
+ break;
+ default:
+ VWrite("unknown type 0x%04x", ulVal);
+ break;
+ }
+ }
+} // void MDInfo::DumpRawCol()
+
+ULONG MDInfo::DumpRawColStats(ULONG ixTbl, ULONG ixCol, ULONG cRows)
+{
+ ULONG rslt = 0;
+ ULONG ulType; // Type of a column.
+ ULONG ulVal; // Value of a column.
+ LPCUTF8 pString; // Pointer to a string.
+ const void *pBlob; // Pointer to a blob.
+ ULONG cb; // Size of something.
+
+ m_pTables->GetColumnInfo(ixTbl, ixCol, 0, 0, &ulType, 0);
+
+ if (IsHeapType(ulType))
+ {
+ for (ULONG rid=1; rid<=cRows; ++rid)
+ {
+ m_pTables->GetColumn(ixTbl, ixCol, rid, &ulVal);
+ // Fixed type.
+ switch (ulType)
+ {
+ case iSTRING:
+ if (ulVal)
+ {
+ m_pTables->GetString(ulVal, &pString);
+ cb = (ULONG) strlen(pString);
+ rslt += cb + 1;
+ }
+ break;
+ case iGUID:
+ if (ulVal)
+ rslt += 16;
+ break;
+ case iBLOB:
+ if (ulVal)
+ {
+ m_pTables->GetBlob(ulVal, &cb, &pBlob);
+ rslt += cb + 1;
+ if (cb > 128)
+ rslt += 1;
+ if (cb > 16535)
+ rslt += 1;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return rslt;
+} // ULONG MDInfo::DumpRawColStats()
+
+int MDInfo::DumpHex(
+ const char *szPrefix, // String prefix for first line.
+ const void *pvData, // The data to print.
+ ULONG cbData, // Bytes of data to print.
+ int bText, // If true, also dump text.
+ ULONG nLine) // Bytes per line to print.
+{
+ const BYTE *pbData = static_cast<const BYTE*>(pvData);
+ ULONG i; // Loop control.
+ ULONG nPrint; // Number to print in an iteration.
+ ULONG nSpace; // Spacing calculations.
+ ULONG nPrefix; // Size of the prefix.
+ ULONG nLines=0; // Number of lines printed.
+ const char *pPrefix; // For counting spaces in the prefix.
+
+ // Round down to 8 characters.
+ nLine = nLine & ~0x7;
+
+ for (nPrefix=0, pPrefix=szPrefix; *pPrefix; ++pPrefix)
+ {
+ if (*pPrefix == '\t')
+ nPrefix = (nPrefix + 8) & ~7;
+ else
+ ++nPrefix;
+ }
+ //nPrefix = strlen(szPrefix);
+ do
+ { // Write the line prefix.
+ if (szPrefix)
+ VWrite("%s:", szPrefix);
+ else
+ VWrite("%*s:", nPrefix, "");
+ szPrefix = 0;
+ ++nLines;
+
+ // Calculate spacing.
+ nPrint = min(cbData, nLine);
+ nSpace = nLine - nPrint;
+
+ // dump in hex.
+ for(i=0; i<nPrint; i++)
+ {
+ if ((i&7) == 0)
+ Write(" ");
+ VWrite("%02x ", pbData[i]);
+ }
+ if (bText)
+ {
+ // Space out to the text spot.
+ if (nSpace)
+ VWrite("%*s", nSpace*3+nSpace/8, "");
+ // Dump in text.
+ Write(">");
+ for(i=0; i<nPrint; i++)
+ VWrite("%c", (isprint(pbData[i])) ? pbData[i] : ' ');
+ // Space out the text, and finish the line.
+ VWrite("%*s<", nSpace, "");
+ }
+ VWriteLine("");
+
+ // Next data to print.
+ cbData -= nPrint;
+ pbData += nPrint;
+ }
+ while (cbData > 0);
+
+ return nLines;
+} // int MDInfo::DumpHex()
+
+void MDInfo::DumpRawHeaps()
+{
+ HRESULT hr; // A result.
+ ULONG ulSize; // Bytes in a heap.
+ const BYTE *pData; // Pointer to a blob.
+ ULONG cbData; // Size of a blob.
+ ULONG oData; // Offset of current blob.
+ char rcPrefix[30]; // To format line prefix.
+
+ m_pTables->GetBlobHeapSize(&ulSize);
+ VWriteLine("");
+ VWriteLine("Blob Heap: %d(%#x) bytes", ulSize,ulSize);
+ oData = 0;
+ do
+ {
+ m_pTables->GetBlob(oData, &cbData, (const void**)&pData);
+ sprintf_s(rcPrefix, 30, "%5x,%-2x", oData, cbData);
+ DumpHex(rcPrefix, pData, cbData);
+ hr = m_pTables->GetNextBlob(oData, &oData);
+ }
+ while (hr == S_OK);
+
+ m_pTables->GetStringHeapSize(&ulSize);
+ VWriteLine("");
+ VWriteLine("String Heap: %d(%#x) bytes", ulSize,ulSize);
+ oData = 0;
+ const char *pString;
+ do
+ {
+ m_pTables->GetString(oData, &pString);
+ if (m_DumpFilter & dumpMoreHex)
+ {
+ sprintf_s(rcPrefix, 30, "%08x", oData);
+ DumpHex(rcPrefix, pString, (ULONG)strlen(pString)+1);
+ }
+ else
+ if (*pString != 0)
+ VWrite("%08x: %s\n", oData, pString);
+ hr = m_pTables->GetNextString(oData, &oData);
+ }
+ while (hr == S_OK);
+ VWriteLine("");
+
+ DisplayUserStrings();
+
+} // void MDInfo::DumpRawHeaps()
+
+
+void MDInfo::DumpRaw(int iDump, bool bunused)
+{
+ ULONG cTables; // Tables in the database.
+ ULONG cCols; // Columns in a table.
+ ULONG cRows; // Rows in a table.
+ ULONG cbRow; // Bytes in a row of a table.
+ ULONG iKey; // Key column of a table.
+ const char *pNameTable; // Name of a table.
+ ULONG oCol; // Offset of a column.
+ ULONG cbCol; // Size of a column.
+ ULONG ulType; // Type of a column.
+ const char *pNameColumn; // Name of a column.
+ ULONG ulSize;
+
+ // Heaps is easy -- there is a specific bit for that.
+ bool bStats = (m_DumpFilter & dumpStats) != 0;
+ // Rows are harder. Was there something else that limited data?
+ BOOL bRows = (m_DumpFilter & (dumpSchema | dumpHeader)) == 0;
+ BOOL bSchema = bRows || (m_DumpFilter & dumpSchema);
+ // (m_DumpFilter & (dumpSchema | dumpHeader | dumpCSV | dumpRaw | dumpStats | dumpRawHeaps))
+
+ if (m_pTables2)
+ {
+ // Get the raw metadata header.
+ const BYTE *pbData = NULL;
+ const BYTE *pbStream = NULL; // One of the stream.s
+ const BYTE *pbMd = NULL; // The metadata stream.
+ ULONG cbData = 0;
+ ULONG cbStream = 0; // One of the streams.
+ ULONG cbMd = 0; // The metadata stream.
+ const char *pName;
+ HRESULT hr = S_OK;
+ ULONG ix;
+
+ m_pTables2->GetMetaDataStorage((const void**)&pbData, &cbData);
+
+ // Per the ECMA spec, the section data looks like this:
+ struct MDSTORAGESIGNATURE
+ {
+ ULONG lSignature; // "Magic" signature.
+ USHORT iMajorVer; // Major file version.
+ USHORT iMinorVer; // Minor file version.
+ ULONG iExtraData; // Offset to next structure of information
+ ULONG iVersionString; // Length of version string
+ BYTE pVersion[0]; // Version string
+ };
+ struct MDSTORAGEHEADER
+ {
+ BYTE fFlags; // STGHDR_xxx flags.
+ BYTE pad;
+ USHORT iStreams; // How many streams are there.
+ };
+ const MDSTORAGESIGNATURE *pStorage = (const MDSTORAGESIGNATURE *) pbData;
+ const MDSTORAGEHEADER *pSHeader = (const MDSTORAGEHEADER *)(pbData + sizeof(MDSTORAGESIGNATURE) + pStorage->iVersionString);
+
+ VWriteLine("Metadata section: 0x%08x, version: %d.%d, extra: %d, version len: %d, version: %s", pStorage->lSignature, pStorage->iMajorVer, pStorage->iMinorVer, pStorage->iExtraData, pStorage->iVersionString, pStorage->pVersion);
+ VWriteLine(" flags: 0x%02x, streams: %d", pSHeader->fFlags, pSHeader->iStreams);
+ if (m_DumpFilter & dumpMoreHex)
+ {
+ const BYTE *pbEnd = pbData;
+ ULONG cb = sizeof(MDSTORAGESIGNATURE) + pStorage->iVersionString + sizeof(MDSTORAGEHEADER);
+ hr = m_pTables2->GetMetaDataStreamInfo(0, &pName, (const void**)&pbEnd, &cbStream);
+ if (hr == S_OK)
+ cb = (ULONG)(pbEnd - pbData);
+ DumpHex(" ", pbData, cb);
+ }
+
+ for (ix=0; hr == S_OK; ++ix)
+ {
+ hr = m_pTables2->GetMetaDataStreamInfo(ix, &pName, (const void**)&pbStream, &cbStream);
+ if (hr != S_OK)
+ break;
+ if (strcmp(pName, "#~") == 0 || strcmp(pName, "#-") == 0)
+ {
+ pbMd = pbStream;
+ cbMd = cbStream;
+ }
+
+ VWriteLine("Stream %d: name: %s, size %d", ix, pName, cbStream);
+ // hex for individual stream headers in metadata section dump. hex for
+ // the streams themselves distributed throughout the dump.
+ }
+
+ if (pbMd)
+ {
+ // Per ECMA, the metadata header looks like this:
+ struct MD
+ {
+ ULONG m_ulReserved; // Reserved, must be zero.
+ BYTE m_major; // Version numbers.
+ BYTE m_minor;
+ BYTE m_heaps; // Bits for heap sizes.
+ BYTE m_rid; // log-base-2 of largest rid.
+ unsigned __int64 m_maskvalid; // Bit mask of present table counts.
+ unsigned __int64 m_sorted; // Bit mask of sorted tables. };
+ };
+
+ const MD *pMd;
+ pMd = (const MD *)pbMd;
+
+ VWriteLine("Metadata header: %d.%d, heaps: 0x%02x, rid: 0x%02x, valid: 0x%016I64x, sorted: 0x%016I64x",
+ pMd->m_major, pMd->m_minor, pMd->m_heaps, pMd->m_rid,
+ (ULONGLONG)GET_UNALIGNED_VAL64(&(pMd->m_maskvalid)),
+ (ULONGLONG)GET_UNALIGNED_VAL64(&(pMd->m_sorted)));
+
+ if (m_DumpFilter & dumpMoreHex)
+ {
+ DumpHex(" ", pbMd, sizeof(MD));
+ }
+ }
+ VWriteLine("");
+ }
+
+ m_pTables->GetNumTables(&cTables);
+
+ m_pTables->GetStringHeapSize(&ulSize);
+ VWrite("Strings: %d(%#x)", ulSize, ulSize);
+ m_pTables->GetBlobHeapSize(&ulSize);
+ VWrite(", Blobs: %d(%#x)", ulSize, ulSize);
+ m_pTables->GetGuidHeapSize(&ulSize);
+ VWrite(", Guids: %d(%#x)", ulSize, ulSize);
+ m_pTables->GetUserStringHeapSize(&ulSize);
+ VWriteLine(", User strings: %d(%#x)", ulSize, ulSize);
+
+ for (ULONG ixTbl = 0; ixTbl < cTables; ++ixTbl)
+ {
+ m_pTables->GetTableInfo(ixTbl, &cbRow, &cRows, &cCols, &iKey, &pNameTable);
+
+ if (bRows) // when dumping rows, print a break between row data and schema
+ VWriteLine("=================================================");
+ VWriteLine("%2d(%#x): %-20s cRecs:%5d(%#x), cbRec:%3d(%#x), cbTable:%6d(%#x)",
+ ixTbl, ixTbl, pNameTable, cRows, cRows, cbRow, cbRow, cbRow * cRows, cbRow * cRows);
+
+ if (!bSchema && !bRows)
+ continue;
+
+ // Dump column definitions for the table.
+ ULONG ixCol;
+ for (ixCol=0; ixCol<cCols; ++ixCol)
+ {
+ m_pTables->GetColumnInfo(ixTbl, ixCol, &oCol, &cbCol, &ulType, &pNameColumn);
+
+ VWrite(" col %2x:%c %-12s oCol:%2x, cbCol:%x, %-7s",
+ ixCol, ((ixCol==iKey)?'*':' '), pNameColumn, oCol, cbCol, DumpRawNameOfType(ulType));
+
+ if (bStats)
+ {
+ ulSize = DumpRawColStats(ixTbl, ixCol, cRows);
+ if (ulSize)
+ VWrite("(%d)", ulSize);
+ }
+ VWriteLine("");
+ }
+
+ if (!bRows)
+ continue;
+
+ // Dump the rows.
+ for (ULONG rid = 1; rid <= cRows; ++rid)
+ {
+ if (rid == 1)
+ VWriteLine("-------------------------------------------------");
+ VWrite(" %3x == ", rid);
+ for (ixCol=0; ixCol < cCols; ++ixCol)
+ {
+ if (ixCol) VWrite(", ");
+ VWrite("%d:", ixCol);
+ DumpRawCol(ixTbl, ixCol, rid, bStats);
+ }
+ VWriteLine("");
+ }
+ }
+} // void MDInfo::DumpRaw()
+
+void MDInfo::DumpRawCSV()
+{
+ ULONG cTables; // Tables in the database.
+ ULONG cCols; // Columns in a table.
+ ULONG cRows; // Rows in a table.
+ ULONG cbRow; // Bytes in a row of a table.
+ const char *pNameTable; // Name of a table.
+ ULONG ulSize;
+
+ m_pTables->GetNumTables(&cTables);
+
+ VWriteLine("Name,Size,cRecs,cbRec");
+
+ m_pTables->GetStringHeapSize(&ulSize);
+ VWriteLine("Strings,%d", ulSize);
+
+ m_pTables->GetBlobHeapSize(&ulSize);
+ VWriteLine("Blobs,%d", ulSize);
+
+ m_pTables->GetGuidHeapSize(&ulSize);
+ VWriteLine("Guids,%d", ulSize);
+
+ for (ULONG ixTbl = 0; ixTbl < cTables; ++ixTbl)
+ {
+ m_pTables->GetTableInfo(ixTbl, &cbRow, &cRows, &cCols, NULL, &pNameTable);
+ VWriteLine("%s,%d,%d,%d", pNameTable, cbRow*cRows, cRows, cbRow);
+ }
+
+} // void MDInfo::DumpRawCSV()
+
diff --git a/src/tools/metainfo/mdinfo.h b/src/tools/metainfo/mdinfo.h
new file mode 100644
index 0000000000..06c0a76b63
--- /dev/null
+++ b/src/tools/metainfo/mdinfo.h
@@ -0,0 +1,207 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef _mdinfo_h
+#define _mdinfo_h
+
+#include "winwrap.h"
+#include "cor.h"
+#include "corhlprpriv.h"
+
+#ifdef FEATURE_PAL
+#include <oleauto.h>
+#endif
+
+#define STRING_BUFFER_LEN 4096
+
+typedef void (*strPassBackFn)(const char *str);
+
+class MDInfo {
+public:
+ enum DUMP_FILTER
+ {
+ dumpDefault = 0x00000000, // Dump everything but debugger data.
+ dumpSchema = 0x00000002, // Dump the metadata schema.
+ dumpRaw = 0x00000004, // Dump the metadata in raw table format.
+ dumpHeader = 0x00000008, // Dump just the metadata header info.
+ dumpCSV = 0x00000010, // Dump the metadata header info in CSV format.
+ dumpUnsat = 0x00000020, // Dump unresolved methods or memberref
+ dumpAssem = 0x00000040,
+ dumpStats = 0x00000080, // Dump more statistics about tables.
+ dumpMoreHex = 0x00000100, // Dump more things in hex.
+ dumpValidate = 0x00000200, // Validate MetaData.
+ dumpRawHeaps = 0x00000400, // Also dump the heaps in the raw dump.
+ dumpNoLogo = 0x00000800, // Don't display the logo or MVID
+ dumpNames = 0x00001000, // In a hex dump, display the names, as well as string #'s.
+ };
+
+
+public:
+ MDInfo(IMetaDataImport2* pImport, IMetaDataAssemblyImport* pAssemblyImport, LPCWSTR szScope, strPassBackFn inPBFn, ULONG DumpFilter);
+ MDInfo(IMetaDataDispenserEx *pDispenser, LPCWSTR szScope, strPassBackFn inPBFn, ULONG DumpFilter=dumpDefault);
+ MDInfo(IMetaDataDispenserEx *pDispenser, PBYTE pManifest, DWORD dwSize, strPassBackFn inPBFn, ULONG DumpFilter=dumpDefault);
+ ~MDInfo();
+
+ void DisplayMD(void);
+
+#ifdef FEATURE_COMINTEROP
+ LPCWSTR VariantAsString(VARIANT *pVariant);
+#endif
+
+ void DisplayVersionInfo(void);
+
+ void DisplayScopeInfo(void);
+
+ void DisplayGlobalFunctions(void);
+ void DisplayGlobalFields(void);
+ void DisplayFieldRVA(mdFieldDef field);
+ void DisplayGlobalMemberRefs(void);
+
+ void DisplayTypeDefs(void);
+ void DisplayTypeDefInfo(mdTypeDef inTypeDef);
+ void DisplayTypeDefProps(mdTypeDef inTypeDef);
+
+ void DisplayModuleRefs(void);
+ void DisplayModuleRefInfo(mdModuleRef inModuleRef);
+
+ void DisplaySignatures(void);
+ void DisplaySignatureInfo(mdSignature inSignature);
+
+ LPCWSTR TokenName(mdToken inToken, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen);
+
+ LPCWSTR TypeDeforRefName(mdToken inToken, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen);
+ LPCWSTR TypeDefName(mdTypeDef inTypeDef, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen);
+ LPCWSTR TypeRefName(mdTypeRef tr, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen);
+
+ LPCWSTR MemberDeforRefName(mdToken inToken, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen);
+ LPCWSTR MemberRefName(mdToken inMemRef, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen);
+ LPCWSTR MemberName(mdToken inMember, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen);
+
+ LPCWSTR MethodName(mdMethodDef inToken, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen);
+ LPCWSTR FieldName(mdFieldDef inToken, __out_ecount(bufLen) LPWSTR buffer, ULONG bufLen);
+
+ char *ClassFlags(DWORD flags, __out_ecount(STRING_BUFFER_LEN) char *sFlags);
+
+ void DisplayTypeRefs(void);
+ void DisplayTypeRefInfo(mdTypeRef tr);
+ void DisplayTypeSpecs(void);
+ void DisplayTypeSpecInfo(mdTypeSpec ts, const char *preFix);
+ void DisplayMethodSpecs(void);
+ void DisplayMethodSpecInfo(mdMethodSpec ms, const char *preFix);
+
+ void DisplayCorNativeLink(COR_NATIVE_LINK *pCorNLnk, const char *preFix);
+ void DisplayCustomAttributeInfo(mdCustomAttribute inValue, const char *preFix);
+ void DisplayCustomAttributes(mdToken inToken, const char *preFix);
+
+ void DisplayInterfaceImpls(mdTypeDef inTypeDef);
+ void DisplayInterfaceImplInfo(mdInterfaceImpl inImpl);
+
+ LPWSTR GUIDAsString(GUID inGuid, __out_ecount(bufLen) LPWSTR guidString, ULONG bufLen);
+
+ const char *TokenTypeName(mdToken inToken);
+
+ void DisplayMemberInfo(mdToken inMember);
+ void DisplayMethodInfo(mdMethodDef method, DWORD *pflags = 0);
+ void DisplayFieldInfo(mdFieldDef field, DWORD *pflags = 0);
+
+ void DisplayMethods(mdTypeDef inTypeDef);
+ void DisplayFields(mdTypeDef inTypeDef, COR_FIELD_OFFSET *rFieldOffset, ULONG cFieldOffset);
+
+ void DisplaySignature(PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, const char *preFix);
+ HRESULT GetOneElementType(PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, ULONG *pcb);
+
+ void DisplayMemberRefs(mdToken tkParent, const char *preFix);
+ void DisplayMemberRefInfo(mdMemberRef inMemRef, const char *preFix);
+
+ void DisplayMethodImpls(mdTypeDef inTypeDef);
+
+ void DisplayParams(mdMethodDef inMthDef);
+ void DisplayParamInfo(mdParamDef inParam);
+
+ void DisplayGenericParams(mdToken tk, const char *prefix);
+ void DisplayGenericParamInfo(mdGenericParam tkparam, const char *prefix);
+
+ void DisplayPropertyInfo(mdProperty inProp);
+ void DisplayProperties(mdTypeDef inTypeDef);
+
+ void DisplayEventInfo(mdEvent inEvent);
+ void DisplayEvents(mdTypeDef inTypeDef);
+
+ void DisplayPermissions(mdToken tk, const char *preFix);
+ void DisplayPermissionInfo(mdPermission inPermission, const char *preFix);
+
+ void DisplayFieldMarshal(mdToken inToken);
+
+ void DisplayPinvokeInfo(mdToken inToken);
+
+ void DisplayAssembly();
+
+ void DisplayAssemblyInfo();
+
+ void DisplayAssemblyRefs();
+ void DisplayAssemblyRefInfo(mdAssemblyRef inAssemblyRef);
+
+ void DisplayFiles();
+ void DisplayFileInfo(mdFile inFile);
+
+ void DisplayExportedTypes();
+ void DisplayExportedTypeInfo(mdExportedType inExportedType);
+
+ void DisplayManifestResources();
+ void DisplayManifestResourceInfo(mdManifestResource inManifestResource);
+
+ void DisplayASSEMBLYMETADATA(ASSEMBLYMETADATA *pMetaData);
+
+ void DisplayUserStrings();
+
+ void DisplayUnsatInfo();
+
+ void DisplayRaw();
+ void DumpRawHeaps();
+ void DumpRaw(int iDump=1, bool bStats=false);
+ void DumpRawCSV();
+ void DumpRawCol(ULONG ixTbl, ULONG ixCol, ULONG rid, bool bStats);
+ ULONG DumpRawColStats(ULONG ixTbl, ULONG ixCol, ULONG cRows);
+ const char *DumpRawNameOfType(ULONG ulType);
+ void SetVEHandlerReporter(__int64 VEHandlerReporterPtr) { m_VEHandlerReporterPtr = VEHandlerReporterPtr; };
+
+ static void Error(const char *szError, HRESULT hr = S_OK);
+private:
+ void Init(strPassBackFn inPBFn, DUMP_FILTER DumpFilter); // Common initialization code.
+
+ int DumpHex(const char *szPrefix, const void *pvData, ULONG cbData, int bText=true, ULONG nLine=16);
+
+ int Write(__in_z __in const char *str);
+ int WriteLine(__in_z __in const char *str);
+
+ int VWrite(__in_z __in const char *str, ...);
+ int VWriteLine(__in_z __in const char *str, ...);
+ int VWriteMarker(__in_z __in const char *str, va_list marker);
+
+ void InitSigBuffer();
+ HRESULT AddToSigBuffer(__in_z __in const char *string);
+
+ IMetaDataImport2 *m_pRegImport;
+ IMetaDataImport2 *m_pImport;
+ IMetaDataAssemblyImport *m_pAssemblyImport;
+ strPassBackFn m_pbFn;
+ __int64 m_VEHandlerReporterPtr;
+ IMetaDataTables *m_pTables;
+ IMetaDataTables2 *m_pTables2;
+
+ CQuickBytes m_output;
+ DUMP_FILTER m_DumpFilter;
+
+ // temporary buffer for TypeDef or TypeRef name. Consume immediately
+ // because other functions may overwrite it.
+ WCHAR m_szTempBuf[STRING_BUFFER_LEN];
+
+ // temporary buffer for formatted string. Consume immediately before any function calls.
+ char m_tempFormatBuffer[STRING_BUFFER_LEN];
+
+ // Signature buffer.
+ CQuickBytes m_sigBuf;
+};
+
+#endif
diff --git a/src/tools/metainfo/mdobj.cpp b/src/tools/metainfo/mdobj.cpp
new file mode 100644
index 0000000000..192281f9b9
--- /dev/null
+++ b/src/tools/metainfo/mdobj.cpp
@@ -0,0 +1,298 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include <stdio.h>
+#include <ctype.h>
+#include <crtdbg.h>
+#include "mdinfo.h"
+
+#ifndef STRING_BUFFER_LEN
+#define STRING_BUFFER_LEN 4096
+#endif
+
+#define OBJ_EXT ".obj"
+#define OBJ_EXT_W W(".obj")
+#define OBJ_EXT_LEN 4
+#define LIB_EXT ".lib"
+#define LIB_EXT_W W(".lib")
+#define LIB_EXT_LEN 4
+
+extern IMetaDataDispenserEx *g_pDisp;
+extern DWORD g_ValModuleType;
+
+// This function is copied from peparse.c file. Making this static, so we won't end up with
+// duplicate definitions causing confusion.
+static const char g_szCORMETA[] = ".cormeta";
+static HRESULT FindObjMetaData(PVOID pImage, PVOID *ppMetaData, long *pcbMetaData)
+{
+ IMAGE_FILE_HEADER *pImageHdr; // Header for the .obj file.
+ IMAGE_SECTION_HEADER *pSectionHdr; // Section header.
+ WORD i; // Loop control.
+
+ // Get a pointer to the header and the first section.
+ pImageHdr = (IMAGE_FILE_HEADER *) pImage;
+ pSectionHdr = (IMAGE_SECTION_HEADER *)(pImageHdr + 1);
+
+ // Avoid confusion.
+ *ppMetaData = NULL;
+ *pcbMetaData = 0;
+
+ // Walk each section looking for .cormeta.
+ for (i=0; i<VAL16(pImageHdr->NumberOfSections); i++, pSectionHdr++)
+ {
+ // Simple comparison to section name.
+ if (strcmp((const char *) pSectionHdr->Name, g_szCORMETA) == 0)
+ {
+ *pcbMetaData = VAL32(pSectionHdr->SizeOfRawData);
+ *ppMetaData = (void *) ((UINT_PTR)pImage + VAL32(pSectionHdr->PointerToRawData));
+ break;
+ }
+ }
+
+ // Check for errors.
+ if (*ppMetaData == NULL || *pcbMetaData == 0)
+ return (E_FAIL);
+ return (S_OK);
+}
+
+
+// This function returns the address to the MapView of file and file size.
+void GetMapViewOfFile(__in wchar_t *szFile, PBYTE *ppbMap, DWORD *pdwFileSize)
+{
+ HANDLE hMapFile;
+ DWORD dwHighSize;
+
+ HANDLE hFile = WszCreateFile(szFile,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
+ NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ MDInfo::Error("CreateFileA failed!");
+
+ *pdwFileSize = GetFileSize(hFile, &dwHighSize);
+
+ if ((*pdwFileSize == 0xFFFFFFFF) && (GetLastError() != NO_ERROR))
+ {
+ CloseHandle(hFile);
+ MDInfo::Error("GetFileSize failed!");
+ }
+ _ASSERTE(dwHighSize == 0);
+
+ hMapFile = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
+ CloseHandle(hFile);
+ if (!hMapFile)
+ MDInfo::Error("CreateFileMappingA failed!");
+
+ *ppbMap = (PBYTE) MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
+ CloseHandle(hMapFile);
+
+ if (!*ppbMap)
+ MDInfo::Error("MapViewOfFile failed!");
+} // void GetMapViewOfFile()
+
+// This function skips a member given the pointer to the member header
+// and returns a pointer to the next header.
+PBYTE SkipMember(PBYTE pbMapAddress)
+{
+ PIMAGE_ARCHIVE_MEMBER_HEADER pMemHdr;
+ ULONG ulMemSize;
+ int j;
+
+ pMemHdr = (PIMAGE_ARCHIVE_MEMBER_HEADER)pbMapAddress;
+
+ // Get size of the member.
+ ulMemSize = 0;
+ for (j = 0; j < 10; j++)
+ {
+ if (pMemHdr->Size[j] < '0' || pMemHdr->Size[j] > '9')
+ break;
+ else
+ ulMemSize = ulMemSize * 10 + pMemHdr->Size[j] - '0';
+ }
+
+ // Skip past the header.
+ pbMapAddress += IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR + ulMemSize;
+ // Find the next even address if the current one is not even.
+ if ((ULONG_PTR)pbMapAddress % 2)
+ pbMapAddress++;
+
+ return pbMapAddress;
+} // void SkipMember()
+
+// This function returns the name of the given Obj. If the name fits in the header,
+// szBuf will be filled in and returned from the function. Else an offset into the long
+// names section will be returned.
+char *GetNameOfObj(PBYTE pbLongNames, PIMAGE_ARCHIVE_MEMBER_HEADER pMemHdr, char szBuf[17])
+{
+ if (pMemHdr->Name[0] == '/')
+ {
+ ULONG ulOffset = 0;
+
+ // Long Names section must exist if the .obj file name starts with '/'.
+ _ASSERTE(pbLongNames &&
+ "Corrupt archive file - .obj file name in the header starts with "
+ "'/' but no long names section present in the archive file.");
+
+ // Calculate the offset into the long names section.
+ for (int j = 1; j < 16; j++)
+ {
+ if (pMemHdr->Name[j] < '0' || pMemHdr->Name[j] > '9')
+ break;
+ else
+ ulOffset = ulOffset * 10 + pMemHdr->Name[j] - '0';
+ }
+ return (char *)(pbLongNames + ulOffset);
+ }
+ else
+ {
+ int j;
+ for (j = 0; j < 16; j++)
+ if ((szBuf[j] = pMemHdr->Name[j]) == '/')
+ break;
+ szBuf[j] = '\0';
+ return szBuf;
+ }
+} // char *GetNameOfObj()
+
+// DisplayArchive() function
+//
+// Opens the .LIB file, and displays the metadata in the specified object files.
+
+void DisplayArchive(__in_z __in wchar_t* szFile, ULONG DumpFilter, __in_z __in_opt wchar_t* szObjName, strPassBackFn pDisplayString)
+{
+ PBYTE pbMapAddress;
+ PBYTE pbStartAddress;
+ PBYTE pbLongNameAddress;
+ PIMAGE_ARCHIVE_MEMBER_HEADER pMemHdr;
+ DWORD dwFileSize;
+ PVOID pvMetaData;
+ char *szName;
+ wchar_t wzName[1024];
+ char szBuf[17];
+ long cbMetaData;
+ int i;
+ HRESULT hr;
+ char szString[1024];
+
+ GetMapViewOfFile(szFile, &pbMapAddress, &dwFileSize);
+ pbStartAddress = pbMapAddress;
+
+ // Verify and skip archive signature.
+ if (dwFileSize < IMAGE_ARCHIVE_START_SIZE ||
+ strncmp((char *)pbMapAddress, IMAGE_ARCHIVE_START, IMAGE_ARCHIVE_START_SIZE))
+ {
+ MDInfo::Error("Bad file format - archive signature mis-match!");
+ }
+ pbMapAddress += IMAGE_ARCHIVE_START_SIZE;
+
+ // Skip linker member 1, linker member 2.
+ for (i = 0; i < 2; i++)
+ pbMapAddress = SkipMember(pbMapAddress);
+
+ // Save address of the long name member and skip it if there exists one.
+ pMemHdr = (PIMAGE_ARCHIVE_MEMBER_HEADER)pbMapAddress;
+ if (pMemHdr->Name[0] == '/' && pMemHdr->Name[1] == '/')
+ {
+ pbLongNameAddress = pbMapAddress + IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR;
+ pbMapAddress = SkipMember(pbMapAddress);
+ }
+ else
+ pbLongNameAddress = 0;
+
+ pDisplayString ("\n");
+ // Get the MetaData for each object file and display it.
+ while (DWORD(pbMapAddress - pbStartAddress) < dwFileSize)
+ {
+ if((szName = GetNameOfObj(pbLongNameAddress, (PIMAGE_ARCHIVE_MEMBER_HEADER)pbMapAddress, szBuf))!=NULL)
+ {
+ if (Wsz_mbstowcs(wzName, szName, 1024) == -1)
+ MDInfo::Error("Conversion from Multi-Byte to Wide-Char failed.");
+
+ // Display metadata only for object files.
+ // If szObjName is specified, display metadata only for that one object file.
+ if (!_stricmp(&szName[strlen(szName) - OBJ_EXT_LEN], OBJ_EXT) &&
+ (!szObjName || !_wcsicmp(szObjName, wzName)))
+ {
+ // Try to find the MetaData section in the current object file.
+ hr = FindObjMetaData(pbMapAddress+IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR, &pvMetaData, &cbMetaData);
+ if (SUCCEEDED(hr))
+ {
+ sprintf_s (szString,1024,"MetaData for object file %s:\n", szName);
+ pDisplayString(szString);
+ MDInfo archiveInfo(g_pDisp,
+ (PBYTE)pvMetaData,
+ cbMetaData,
+ pDisplayString,
+ DumpFilter);
+ archiveInfo.DisplayMD();
+ }
+ else
+ {
+ sprintf_s(szString,1024,"MetaData not found for object file %s!\n\n", szName);
+ pDisplayString(szString);
+ }
+ }
+ }
+
+ // Skip past the object file.
+ pbMapAddress = SkipMember(pbMapAddress);
+ }
+
+ UnmapViewOfFile(pbStartAddress);
+} // void DisplayArchive()
+
+// DisplayFile() function
+//
+// Opens the meta data content of a .EXE, .CLB, .CLASS, .TLB, .DLL or .LIB file, and
+// calls RawDisplay()
+
+void DisplayFile(__in_z __in wchar_t* szFile, BOOL isFile, ULONG DumpFilter, __in_z __in_opt wchar_t* szObjName, strPassBackFn pDisplayString)
+{
+ // Open the emit scope
+
+ // We need to make sure this file isn't too long. Checking _MAX_PATH is probably safe, but since we have a much
+ // larger buffer, we might as well use it all.
+ if (wcslen(szFile) > 1000)
+ return;
+
+
+ WCHAR szScope[1024];
+ char szString[1024];
+
+ if (isFile)
+ {
+ wcscpy_s(szScope, 1024, W("file:"));
+ wcscat_s(szScope, 1024, szFile);
+ }
+ else
+ wcscpy_s(szScope, 1024, szFile);
+
+ // print bar that separates different files
+ pDisplayString("////////////////////////////////////////////////////////////////\n");
+ wchar_t rcFname[_MAX_FNAME], rcExt[_MAX_EXT];
+
+ _wsplitpath_s(szFile, NULL, 0, NULL, 0, rcFname, _MAX_FNAME, rcExt, _MAX_EXT);
+ sprintf_s(szString,1024,"\nFile %S%S: \n",rcFname, rcExt);
+ pDisplayString(szString);
+
+ if (DumpFilter & MDInfo::dumpValidate)
+ {
+ if (!_wcsicmp(rcExt, OBJ_EXT_W) || !_wcsicmp(rcExt, LIB_EXT_W))
+ g_ValModuleType = ValidatorModuleTypeObj;
+ else
+ g_ValModuleType = ValidatorModuleTypePE;
+ }
+
+ if (!_wcsicmp(rcExt, LIB_EXT_W))
+ DisplayArchive(szFile, DumpFilter, szObjName, pDisplayString);
+ else
+ {
+ MDInfo metaDataInfo(g_pDisp, szScope, pDisplayString, DumpFilter);
+ metaDataInfo.DisplayMD();
+ }
+} // void DisplayFile()
+
diff --git a/src/tools/metainfo/metainfo.cpp b/src/tools/metainfo/metainfo.cpp
new file mode 100644
index 0000000000..4e1f1cedc4
--- /dev/null
+++ b/src/tools/metainfo/metainfo.cpp
@@ -0,0 +1,190 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include <stdio.h>
+#include <ctype.h>
+#include <crtdbg.h>
+#include <utilcode.h>
+#include "mdinfo.h"
+#include <ndpversion.h>
+
+// Provide custom LoadLibrary implementation.
+#define LEGACY_ACTIVATION_SHIM_LOAD_LIBRARY WszLoadLibrary
+#define LEGACY_ACTIVATION_SHIM_DEFINE_CoInitializeEE
+#include "LegacyActivationShim.h"
+
+#ifdef FEATURE_PAL
+#include <palstartupw.h>
+#endif
+
+// Global variables
+bool g_bSchema = false;
+bool g_bRaw = false;
+bool g_bDebug = false;
+bool g_bHeader = false;
+
+// Validator module type.
+DWORD g_ValModuleType = ValidatorModuleTypeInvalid;
+
+IMetaDataImport2 *g_pImport = NULL;
+IMetaDataDispenserEx *g_pDisp = NULL;
+
+void DisplayFile(__in_z __in wchar_t* szFile, BOOL isFile, ULONG DumpFilter, __in_z __in_opt wchar_t* szObjFile, strPassBackFn pDisplayString);
+void DisplayArchive(__in_z __in wchar_t* szFile, ULONG DumpFilter, __in_z __in_opt wchar_t* szObjName, strPassBackFn pDisplayString);
+
+void PrintLogo()
+{
+ printf("Microsoft (R) .Net Frameworks Runtime Meta Data Dump Utility Version %s\n", VER_FILEVERSION_STR);
+ printf("%S", VER_LEGALCOPYRIGHT_LOGO_STR_L);
+ printf("\n");
+}// PrintLogo
+
+void Usage()
+{
+ printf("\n");
+ printf("metainfo [-? | -header | -schema | -raw | -validate] [-nologo] [-obj <obj file name>] [<filname> | <file pattern>]\n");
+ printf(" -? Displays this text.\n");
+ printf(" -hex Prints more things in hex as well as words.\n");
+ printf(" -header Prints MetaData header information and sizes.\n");
+ printf(" -csv Prints the header sizes in Comma Separated format.\n");
+ printf(" -unsat Prints unresolved externals.\n");
+ printf(" -assem Prints only the Assembly information.\n");
+ printf(" -schema Prints the MetaData schema information.\n");
+ printf(" -raw Prints the raw MetaData tables.\n");
+ printf(" -heaps Prints the raw heaps (only if -raw).\n");
+ printf(" -names Prints string columns (only if -raw).\n");
+ printf(" -validate Validate the consistency of the metadata.\n");
+ printf(" -nologo Do not display the logo and MVID.\n");
+ printf(" -obj <objFileName>\n");
+ printf(" Prints the MetaData for the specified obj file in the given \n");
+ printf(" archive(.lib) - e.g metainfo libc.lib -obj wMSILWinCRTStartup.obj\n");
+
+ MDInfo::Error("");
+}
+
+void DisplayString(__in_z __in const char *str)
+{
+ printf("%s", str);
+}
+
+extern "C" int _cdecl wmain(int argc, __in_ecount(argc) WCHAR **argv)
+{
+ wchar_t *pArg = NULL;
+ wchar_t *szObjName = NULL;
+ ULONG DumpFilter = MDInfo::dumpDefault;
+ HRESULT hr = 0;
+ BOOL fWantHelp=FALSE;
+
+ // Validate incoming arguments
+ for (int i=1; i<argc; i++)
+ {
+ const wchar_t *szArg = argv[i];
+ if (*szArg == L'-' || *szArg == L'/')
+ {
+ if (_wcsicmp(szArg + 1, L"?") == 0)
+ fWantHelp=TRUE;
+
+ else if (_wcsicmp(szArg + 1, L"nologo") == 0)
+ DumpFilter |= MDInfo::dumpNoLogo;
+
+ else if (_wcsicmp(szArg + 1, L"Hex") == 0)
+ DumpFilter |= MDInfo::dumpMoreHex;
+
+ else if (_wcsicmp(szArg + 1, L"header") == 0)
+ DumpFilter |= MDInfo::dumpHeader;
+
+ else if (_wcsicmp(szArg + 1, L"csv") == 0)
+ DumpFilter |= MDInfo::dumpCSV;
+
+ else if (_wcsicmp(szArg + 1, L"raw") == 0)
+ DumpFilter |= MDInfo::dumpRaw;
+
+ else if (_wcsicmp(szArg + 1, L"heaps") == 0)
+ DumpFilter |= MDInfo::dumpRawHeaps;
+
+ else if (_wcsicmp(szArg + 1, L"names") == 0)
+ DumpFilter |= MDInfo::dumpNames;
+
+ else if (_wcsicmp(szArg + 1, L"schema") == 0)
+ DumpFilter |= MDInfo::dumpSchema;
+
+ else if (_wcsicmp(szArg + 1, L"unsat") == 0)
+ DumpFilter |= MDInfo::dumpUnsat;
+
+ else if (_wcsicmp(szArg + 1, L"stats") == 0)
+ DumpFilter |= MDInfo::dumpStats;
+
+ else if (_wcsicmp(szArg + 1, L"assem") == 0)
+ DumpFilter |= MDInfo::dumpAssem;
+
+ else if (_wcsicmp(szArg + 1, L"validate") == 0)
+ DumpFilter |= MDInfo::dumpValidate;
+
+ else if (_wcsicmp(szArg + 1, L"obj") == 0)
+ {
+ if (++i == argc)
+ Usage();
+ else
+ szObjName = argv[i];
+ }
+ }
+ else
+ pArg = argv[i];
+ }
+
+ // Print banner.
+ if (!(DumpFilter & MDInfo::dumpNoLogo))
+ PrintLogo();
+
+
+ if (!pArg || fWantHelp)
+ Usage();
+
+
+#ifndef FEATURE_PAL
+ // Init and run.
+ CoInitialize(0);
+#endif
+
+ LegacyActivationShim::CoInitializeCor(0);
+
+ hr = LegacyActivationShim::ClrCoCreateInstance(
+ CLSID_CorMetaDataDispenser, NULL, CLSCTX_INPROC_SERVER,
+ IID_IMetaDataDispenserEx, (void **) &g_pDisp);
+ if(FAILED(hr)) MDInfo::Error("Unable to CoCreate Meta-data Dispenser", hr);
+
+ // Loop through all files in the file pattern passed
+ WIN32_FIND_DATA fdFiles;
+ HANDLE hFind;
+ wchar_t szSpec[_MAX_PATH];
+ wchar_t szDrive[_MAX_DRIVE];
+ wchar_t szDir[_MAX_DIR];
+
+ hFind = WszFindFirstFile(pArg, &fdFiles);
+
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ DisplayFile(pArg, false, DumpFilter, szObjName, DisplayString);
+ }
+ else
+ {
+ // Convert relative paths to full paths.
+ LPWSTR szFname;
+ WszGetFullPathName(pArg, _MAX_PATH, szSpec, &szFname);
+ SplitPath(szSpec, szDrive, _MAX_DRIVE, szDir, _MAX_DIR, NULL, 0, NULL, 0);
+ do
+ {
+ MakePath(szSpec, szDrive, szDir, fdFiles.cFileName, NULL);
+ // display the meta data of the file
+ DisplayFile(szSpec, true, DumpFilter, szObjName, DisplayString);
+ } while (WszFindNextFile(hFind, &fdFiles)) ;
+ FindClose(hFind);
+ }
+ g_pDisp->Release();
+ LegacyActivationShim::CoUninitializeCor();
+#ifndef FEATURE_PAL
+ CoUninitialize();
+#endif
+ return 0;
+}
diff --git a/src/tools/metainfo/metainfo.nativeproj b/src/tools/metainfo/metainfo.nativeproj
new file mode 100644
index 0000000000..7591a40d63
--- /dev/null
+++ b/src/tools/metainfo/metainfo.nativeproj
@@ -0,0 +1,42 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood">
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+ <!--Leaf project Properties-->
+ <PropertyGroup>
+ <OutputName>metainfo</OutputName>
+ <FileToMarkForSigning>$(BinariesDirectory)\metainfo.exe</FileToMarkForSigning>
+ <TargetType>PROGRAM</TargetType>
+ <LinkSubsystem>console</LinkSubsystem>
+ <EntryPoint>wmain</EntryPoint>
+ <ClAdditionalOptions>$(ClAdditionalOptions) -DUNICODE -D_UNICODE</ClAdditionalOptions>
+ <LinkGenerateManifest>true</LinkGenerateManifest>
+ <LinkAdditionalOptions>$(LinkAdditionalOptions) /MANIFEST</LinkAdditionalOptions>
+ </PropertyGroup>
+ <!--Leaf Project Items-->
+ <ItemGroup>
+ <LinkPreCrtLibs Include="$(ClrLibPath)\utilcodenohost.lib">
+ <ProjectReference>$(ClrSrcDirectory)utilcode\dyncrtnohost\dyncrtnohost.nativeproj</ProjectReference>
+ </LinkPreCrtLibs>
+ <LinkPreCrtLibs Include="$(ClrLibPath)\MDHotData.lib" />
+
+ <TargetLib Include="$(ClrLibPath)\corguids.lib" />
+ <TargetLib Include="$(SdkLibPath)\mscoree.lib" />
+ <TargetLib Include="$(SdkLibPath)\ole32.lib" />
+ <TargetLib Include="$(SdkLibPath)\user32.lib" />
+ <TargetLib Include="$(SdkLibPath)\uuid.lib" />
+ <TargetLib Include="$(SdkLibPath)\oleaut32.lib" />
+ <ProjectReference Include="$(ClrSrcDirectory)md\hotdata\full\mdhotdata.nativeproj">
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <RCResourceFile Include="native.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <CppCompile Include="mdinfo.cpp" />
+ <CppCompile Include="mdobj.cpp" />
+ <CppCompile Include="metainfo.cpp" />
+ </ItemGroup>
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" />
+</Project>
diff --git a/src/tools/util/.gitmirror b/src/tools/util/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/tools/util/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/tools/util/consoleargs.cpp b/src/tools/util/consoleargs.cpp
new file mode 100644
index 0000000000..3baacd1635
--- /dev/null
+++ b/src/tools/util/consoleargs.cpp
@@ -0,0 +1,958 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include <stdio.h>
+#include "consoleargs.h"
+#include <strsafe.h>
+
+typedef unsigned char byte;
+
+size_t SafeStrCopy( _In_ LPCWSTR wszSrc, _In_ size_t cchSrc, _Out_ LPWSTR wszDest, _In_ size_t cchDest)
+{
+ if (cchSrc == (size_t)-1)
+ cchSrc = wcslen(wszSrc);
+
+ if (cchSrc >= cchDest) {
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ return 0;
+ }
+
+ if (FAILED(StringCchCopyNW( wszDest, cchDest, wszSrc, cchSrc))) {
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ return 0;
+ }
+ return cchSrc;
+}
+
+size_t SafeStrLower( _In_ LPCWSTR wszSrc, _In_ size_t cchSrc, _Out_ LPWSTR wszDest, _In_ size_t cchDest)
+{
+ if (cchSrc == (size_t)-1)
+ cchSrc = wcslen(wszSrc);
+
+ if (cchSrc >= cchDest) {
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ return 0;
+ }
+
+ SafeStrCopy(wszSrc, cchSrc, wszDest, cchDest);
+ _wcslwr_s((WCHAR*)wszDest, cchDest);
+ return wcslen(wszDest);
+}
+
+inline int HexValue (WCHAR c)
+{
+ return (c >= '0' && c <= '9') ? c - '0' : (c & 0xdf) - 'A' + 10;
+}
+
+#ifndef PLATFORM_UNIX
+// Get canonical file path from a user specified path. wszSrcfileName can include relative paths, etc.
+// Much of this function was taken from csc.exe.
+DWORD GetCanonFilePath(_In_z_ LPCWSTR wszSrcFileName, _Out_z_cap_(cchDestFileName) LPWSTR wszDestFileName, _In_ DWORD cchDestFileName, _In_ bool fPreserveSrcCasing)
+{
+ DWORD full_len;
+ WCHAR * full_path = new WCHAR[cchDestFileName]; // an intermediate buffer
+ WCHAR * temp_path = new WCHAR[cchDestFileName]; // Used if FindFile fails
+ WCHAR * full_cur;
+ WCHAR * out_cur;
+ WCHAR * out_end;
+ bool hasDrive = false;
+
+ memset(full_path, 0, cchDestFileName * sizeof(WCHAR));
+ out_cur = wszDestFileName;
+ out_end = out_cur + cchDestFileName;
+ if (wszSrcFileName != wszDestFileName)
+ *out_cur = L'\0';
+ full_cur = full_path;
+
+ // Replace '\\' with single backslashes in paths, because W_GetFullPathName fails to do this on win9x.
+ size_t i = 0;
+ size_t j = 0;
+ size_t length = wcslen(wszSrcFileName);
+ while (j<length)
+ {
+ // UNC paths start with '\\' so skip the first character if it is a backslash.
+ if (j!= 0 && wszSrcFileName[j] == '\\' && wszSrcFileName[j+1] == '\\')
+ j++;
+ else
+ temp_path[i++] = wszSrcFileName[j++];
+ if (i >= cchDestFileName) {
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ goto FAIL;
+ }
+ }
+ temp_path[i] = L'\0';
+
+ full_len = GetFullPathNameW(temp_path, cchDestFileName, full_path, NULL);
+ if (wszSrcFileName == wszDestFileName)
+ wszDestFileName[cchDestFileName-1] = L'\0';
+ if (full_len == 0) {
+ goto FAIL;
+ } else if (full_len >= cchDestFileName) {
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ goto FAIL;
+ }
+
+ // Allow only 1 ':' for drives and no long paths with "\\?\"
+ if (((full_path[0] >= L'a' && full_path[0] <= L'z') ||
+ (full_path[0] >= L'A' && full_path[0] <= L'Z')) &&
+ full_path[1] == L':')
+ hasDrive = true;
+
+ // We don't allow colons (except after the drive letter)
+ // long paths beginning with "\\?\"
+ // devices beginning with "\\.\"
+ // or wildcards
+ // or characters 0-31
+ if (wcschr( full_path + (hasDrive ? 2 : 0), W(':')) != NULL ||
+ wcsncmp( full_path, W("\\\\?\\"), 4) == 0 ||
+ wcsncmp( full_path, W("\\\\.\\"), 4) == 0 ||
+ wcspbrk(full_path, W("?*\x1\x2\x3\x4\x5\x6\x7\x8\x9")
+ W("\xA\xB\xC\xD\xE\xF\x10\x11\x12\x13\x14\x15")
+ W("\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\0")) != NULL) {
+ SetLastError(ERROR_INVALID_NAME);
+ goto FAIL;
+ }
+
+
+ if (hasDrive) {
+ size_t len = SafeStrLower( full_path, 3, out_cur, out_end - out_cur);
+ if (len == 0)
+ goto FAIL;
+
+ full_cur += 3;
+ out_cur += len;
+
+ } else if (full_path[0] == L'\\' && full_path[1] == L'\\') {
+ // Must be a UNC pathname, so lower-case the server and share
+ // since there's no known way to get the 'correct casing'
+ WCHAR * slash = wcschr(full_path + 2, L'\\');
+ // slash should now point to the backslash between the server and share
+ if (slash == NULL || slash == full_path + 2) {
+ SetLastError(ERROR_INVALID_NAME);
+ goto FAIL;
+ }
+
+ slash = wcschr(slash + 1, L'\\');
+ if (slash == NULL) {
+ slash = full_path + wcslen(full_path);
+ } else if (slash[-1] == L'\\') {
+ // An empty share-name?
+ SetLastError(ERROR_INVALID_NAME);
+ goto FAIL;
+ } else
+ slash++;
+ // slash should now point to char after the slash after the share name
+ // or the end of the sharename if there's no trailing slash
+
+ size_t len = SafeStrLower( full_path, slash - full_path, out_cur, out_end - out_cur);
+ if (len == 0)
+ goto FAIL;
+
+ full_cur = slash;
+ out_cur += len;
+
+ } else {
+ // Not a drive-leter path or a UNC path, so assume it's invalid
+ SetLastError(ERROR_INVALID_NAME);
+ goto FAIL;
+ }
+
+ // We either have a lower-cased drive letter or a UNC name
+ // with it's trailing slash
+ // out_cur points to the trailing NULL
+ // full_cur points to the character after the slash
+
+ // Now iterate over each element of the path and attempt to canonicalize it
+ // It's possible for this loop to never run
+ // (for strings like "C:\" or "\\unc\share" or "\\unc\share2\")
+ while (*full_cur) {
+ WIN32_FIND_DATAW find_data;
+ bool hasSlash = true;
+ WCHAR * slash = wcschr(full_cur, '\\');
+ if (slash == NULL) {
+ // This means we're on the last element of the path
+ // so work with everything left in the string
+ hasSlash = false;
+ slash = full_cur + wcslen(full_cur);
+ }
+
+ // Check to make sure we have enough room for the next part of the path
+ if (out_cur + (slash - full_cur) >= out_end) {
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ goto FAIL;
+ }
+
+ // Copy over the next path part into the output buffer
+ // so we can run FindFile to get the correct casing/long filename
+ memcpy(out_cur, full_cur, (BYTE*)slash - (BYTE*)full_cur);
+ out_cur[slash - full_cur] = L'\0';
+ HANDLE hFind = FindFirstFileW(wszDestFileName, &find_data);
+ if (hFind == INVALID_HANDLE_VALUE) {
+ size_t temp_len;
+
+ // We coundn't find the file, the general causes are the file doesn't exist
+ // or we don't have access to it. Either way we still try to get a canonical filename
+ // but preserve the passed in casing for the filename
+
+ if (!hasSlash && fPreserveSrcCasing) {
+ // This is the last component in the filename, we should preserve the user's input text
+ // even if we can't find it
+ out_cur += slash - full_cur;
+ full_cur = slash;
+ break;
+ }
+
+ // This will succeed even if we don't have access to the file
+ // (And on NT4 if the filename is already in 8.3 form)
+ temp_len = GetShortPathNameW(wszDestFileName, temp_path, cchDestFileName);
+ if (temp_len == 0) {
+ // GetShortPathName failed, we have no other way of figuring out the
+ // The filename, so just lowercase it so it hashes in a case-insensitive manner
+
+ if (!hasSlash) {
+ // If it doesn't have a slash, then it must be the last part of the filename,
+ // so don't lowercase it, preserve whatever casing the user gave
+ temp_len = SafeStrCopy( full_cur, slash - full_cur, out_cur, out_end - out_cur);
+ } else {
+ temp_len = SafeStrLower( full_cur, slash - full_cur, out_cur, out_end - out_cur);
+ }
+ if (temp_len == 0)
+ goto FAIL;
+
+ full_cur = slash;
+ out_cur += temp_len;
+
+ } else if (temp_len >= cchDestFileName) {
+ // The short filename is longer than the whole thing?
+ // This shouldn't ever happen, right?
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ goto FAIL;
+ } else {
+ // GetShortPathName succeeded with a path that is less than BUFFER_LEN
+ // find the last slash and copy it. (We don't want to copy previous
+ // path components that we've already 'resolved')
+ // However, GetShortPathName doesn't always correct the casing
+ // so as a safe-guard, lower-case it (unless it's the last filename)
+ WCHAR * temp_slash = wcsrchr(temp_path, L'\\');
+
+ temp_slash++;
+ size_t len = 0;
+ if (!hasSlash) {
+ len = SafeStrCopy( temp_slash, -1, out_cur, out_end - out_cur);
+ } else {
+ len = SafeStrLower( temp_slash, -1, out_cur, out_end - out_cur);
+ }
+ if (len == 0)
+ goto FAIL;
+
+ full_cur = slash;
+ out_cur += len;
+
+ }
+ } else {
+ // Copy over the properly cased long filename
+ FindClose(hFind);
+ size_t name_len = wcslen(find_data.cFileName);
+ if (out_cur + name_len + (hasSlash ? 1 : 0) >= out_end) {
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ goto FAIL;
+ }
+
+ // out_cur already has the filename with the input casing, so we can just leave it alone
+ // if this is not a directory name and the caller asked to perserve the casing
+ if (hasSlash || !fPreserveSrcCasing) {
+ memcpy(out_cur, find_data.cFileName, name_len * sizeof(WCHAR));
+ }
+ else if (name_len != (slash - full_cur) || _wcsnicmp(find_data.cFileName, full_cur, name_len) != 0) {
+ // The user asked us to preserve the casing of the filename
+ // and the filename is different by more than just casing so report
+ // an error indicating we can't create the file
+ SetLastError(ERROR_FILE_EXISTS);
+ goto FAIL;
+ }
+
+ out_cur += name_len;
+ full_cur = slash;
+ }
+
+ if (hasSlash) {
+ if (out_cur + 1 >= out_end) {
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ goto FAIL;
+ }
+ full_cur++;
+ *out_cur++ = L'\\';
+ }
+ *out_cur = '\0';
+ }
+
+ return (DWORD)(out_cur - wszDestFileName);
+
+FAIL:
+ if (full_path)
+ {
+ delete [] full_path;
+ }
+ if (temp_path)
+ {
+ delete [] temp_path;
+ }
+ return 0;
+}
+#endif // !PLATFORM_UNIX
+
+bool FreeString(LPCWSTR szText)
+{
+ if (szText)
+ delete [] (const_cast<LPWSTR>(szText));
+ return true;
+}
+
+bool IsWhitespace(WCHAR c)
+{
+ return c == L' ' || c == L'\t' || c == L'\n' || c == L'\r';
+}
+
+void ConsoleArgs::CleanUpArgs()
+{
+ while (m_listArgs)
+ {
+ WStrList * next = m_listArgs->next;
+ if (m_listArgs->arg)
+ delete [] m_listArgs->arg;
+ delete m_listArgs;
+ m_listArgs = next;
+ }
+
+ if (m_rgArgs)
+ delete[] m_rgArgs;
+
+ m_rgArgs = NULL;
+
+ if(m_lastErrorMessage)
+ {
+ delete[] m_lastErrorMessage;
+ }
+}
+
+bool ConsoleArgs::GetFullFileName(LPCWSTR szSource, __out_ecount(cchFilenameBuffer) LPWSTR filenameBuffer, DWORD cchFilenameBuffer, bool fOutputFilename)
+{
+#ifdef PLATFORM_UNIX
+ WCHAR tempBuffer[MAX_LONGPATH];
+ memset(filenameBuffer, 0, cchFilenameBuffer * sizeof(WCHAR));
+ if (!PathCanonicalizeW(tempBuffer, szSource) ||
+ StringCchCopyW(filenameBuffer, cchFilenameBuffer, tempBuffer) != S_OK)
+#else
+ if (0 == GetCanonFilePath( szSource, filenameBuffer, cchFilenameBuffer, fOutputFilename))
+#endif
+ {
+ if (filenameBuffer[0] == L'\0')
+ {
+ // This could easily fail because of an overflow, but that's OK
+ // we only want what will fit in the output buffer so we can print
+ // a good error message
+ StringCchCopyW(filenameBuffer, cchFilenameBuffer - 4, szSource);
+ // Don't cat on the ..., only stick it in the last 4 characters
+ // to indicate truncation (if the string is short than this it just won't print)
+ StringCchCopyW(filenameBuffer + cchFilenameBuffer - 4, 4, W("..."));
+ }
+ return false;
+ }
+ return true;
+}
+
+//
+// Clear previous error message if any and set the new one by copying into m_lastErrorMessage.
+// We are responsible for freeing the memory destruction.
+//
+void ConsoleArgs::SetErrorMessage(__in LPCWSTR pwzMessage)
+{
+ if (m_lastErrorMessage != nullptr)
+ {
+ delete[] m_lastErrorMessage;
+ }
+ m_errorOccurred = true;
+ m_lastErrorMessage = new WCHAR[wcslen(pwzMessage) + 1];
+ if (m_lastErrorMessage == nullptr)
+ {
+ //
+ // Out of memory allocating error string
+ //
+ m_lastErrorMessage = kOutOfMemory;
+ return;
+ }
+
+ wcscpy_s((LPWSTR)m_lastErrorMessage, wcslen(pwzMessage) + 1, pwzMessage);
+}
+
+//
+// Create a simple leaf tree node with the given text
+//
+b_tree * ConsoleArgs::MakeLeaf(LPCWSTR text)
+{
+ b_tree * t = NULL;
+ size_t name_len = wcslen(text) + 1;
+ LPWSTR szCopy = new WCHAR[name_len];
+
+ if (!szCopy)
+ {
+ return NULL;
+ }
+
+ HRESULT hr;
+ hr = StringCchCopyW (szCopy, name_len, text);
+
+ t = new b_tree(szCopy);
+ if (!t)
+ {
+ delete [] szCopy;
+ return NULL;
+ }
+ return t;
+}
+
+//
+// Free the memory allocated by the tree (recursive)
+//
+void ConsoleArgs::CleanupTree(b_tree *root)
+{
+ if (root == NULL)
+ return ;
+ root->InOrderWalk(FreeString);
+ delete root;
+}
+
+//
+// Search the binary tree and add the given string
+// return true if it was added or false if it already
+// exists
+//
+HRESULT ConsoleArgs::TreeAdd(b_tree **root, LPCWSTR add
+ )
+{
+ // Special case - init the tree if it
+ // doesn't already exist
+ if (*root == NULL)
+ {
+ *root = MakeLeaf(add
+ );
+ return *root == NULL ? E_OUTOFMEMORY : S_OK;
+ }
+
+ size_t name_len = wcslen(add
+ ) + 1;
+ LPWSTR szCopy = new WCHAR[name_len];
+
+ if (!szCopy)
+ {
+ return NULL;
+ }
+
+ HRESULT hr = StringCchCopyW (szCopy, name_len, add
+ );
+ // otherwise, just let the template do the work
+ hr = (*root)->Add(szCopy, _wcsicmp);
+
+ if (hr != S_OK) // S_FALSE means it already existed
+ delete [] szCopy;
+
+ return hr;
+}
+
+//
+// Parse the text into a list of argument
+// return the total count
+// and set 'args' to point to the last list element's 'next'
+// This function assumes the text is NULL terminated
+//
+void ConsoleArgs::TextToArgs(LPCWSTR szText, WStrList ** listReplace)
+{
+ WStrList **argLast;
+ const WCHAR *pCur;
+ size_t iSlash;
+ int iCount;
+
+ argLast = listReplace;
+ pCur = szText;
+ iCount = 0;
+
+ // Guaranteed that all tokens are no bigger than the entire file.
+ LPWSTR szTemp = new WCHAR[wcslen(szText) + 1];
+ if (!szTemp)
+ {
+ return ;
+ }
+ while (*pCur != '\0')
+ {
+ WCHAR *pPut, *pFirst, *pLast;
+ WCHAR chIllegal;
+
+LEADINGWHITE:
+ while (IsWhitespace( *pCur) && *pCur != '\0')
+ pCur++;
+
+ if (*pCur == '\0')
+ break;
+ else if (*pCur == L'#')
+ {
+ while ( *pCur != '\0' && *pCur != '\n')
+ pCur++; // Skip to end of line
+ goto LEADINGWHITE;
+ }
+
+ // The treatment of quote marks is a bit different than the standard
+ // treatment. We only remove quote marks at the very beginning and end of the
+ // string. We still consider interior quotemarks for space ignoring purposes.
+ // All the below are considered a single argument:
+ // "foo bar" -> foo bar
+ // "foo bar";"baz" -> "foo bar";"baz"
+ // fo"o ba"r -> fo"o ba"r
+ //
+ // Additionally, in order to allow multi-line arguments we allow a ^ at the
+ // end of a line to specify "invisible space". A character sequence matching
+ // "\^(\r\n|\r|\n)[ \t]*" will be completely ignored (whether inside a quoted
+ // string or not). The below transformations occur (and represent a single
+ // argument):
+ // "foo ^
+ // bar" -> foo bar
+ // foo;^
+ // bar -> foo;bar
+ // Notes:
+ // 1. Comments are not recognized in a multi-line argument
+ // 2. A caret escapes only one new-line followed by an arbitrary number of
+ // tabs or blanks.
+ // The following will be parsed as the names suggest, into several different
+ // arguments:
+ // /option1 ^
+ // val1_1;^
+ // val1_2;^
+ // val1_3;^
+ //
+ // /option2
+ // /opt^
+ // ion3 -> /option1 val1_1;val1_2;val1_3; /option2 /option3
+ int cQuotes = 0;
+ pPut = pFirst = szTemp;
+ chIllegal = 0;
+ while ((!IsWhitespace( *pCur) || !!(cQuotes & 1)) && *pCur != '\0')
+ {
+ switch (*pCur)
+ {
+ // All this weird slash stuff follows the standard argument processing routines
+ case L'\\':
+ iSlash = 0;
+ // Copy and advance while counting slashes
+ while (*pCur == L'\\')
+ {
+ *pPut++ = *pCur++;
+ iSlash++;
+ }
+
+ // Slashes not followed by a quote character don't matter now
+ if (*pCur != L'\"')
+ break;
+
+ // If there's an odd count of slashes, it's escaping the quote
+ // Otherwise the quote is a quote
+ if ((iSlash & 1) == 0)
+ {
+ ++cQuotes;
+ }
+ *pPut++ = *pCur++;
+ break;
+
+ case L'\"':
+ ++cQuotes;
+ *pPut++ = *pCur++;
+ break;
+
+ case L'^':
+ // ignore this sequence: \^[\r\n|\r|\n]( \t)*
+ if (pCur[1] == L'\r' || pCur[1] == L'\n')
+ {
+ if (pCur[1] == L'\r' && pCur[2] == L'\n')
+ pCur += 3;
+ else
+ pCur += 2;
+
+ while (*pCur == L' ' || *pCur == L'\t')
+ ++pCur;
+ }
+ else
+ {
+ *pPut++ = *pCur++; // Copy the caret and advance
+ }
+ break;
+
+ case L'\x01':
+ case L'\x02':
+ case L'\x03':
+ case L'\x04':
+ case L'\x05':
+ case L'\x06':
+ case L'\x07':
+ case L'\x08':
+ case L'\x09':
+ case L'\x0A':
+ case L'\x0B':
+ case L'\x0C':
+ case L'\x0D':
+ case L'\x0E':
+ case L'\x0F':
+ case L'\x10':
+ case L'\x11':
+ case L'\x12':
+ case L'\x13':
+ case L'\x14':
+ case L'\x15':
+ case L'\x16':
+ case L'\x17':
+ case L'\x18':
+ case L'\x19':
+ case L'\x1A':
+ case L'\x1B':
+ case L'\x1C':
+ case L'\x1D':
+ case L'\x1E':
+ case L'\x1F':
+ case L'|':
+ // Save the first legal character and skip over them
+ if (chIllegal == 0)
+ chIllegal = *pCur;
+ pCur++;
+ break;
+
+ default:
+ *pPut++ = *pCur++; // Copy the char and advance
+ break;
+ }
+ }
+
+ pLast = pPut;
+ *pPut++ = '\0';
+
+ // If the string is surrounded by quotes, with no interior quotes, remove them.
+ if (cQuotes == 2 && *pFirst == L'\"' && *(pLast - 1) == L'\"')
+ {
+ ++pFirst;
+ --pLast;
+ *pLast = L'\0';
+ }
+
+ if (chIllegal != 0)
+ {
+ SetErrorMessage(W("Illegal option character."));
+ break;
+ }
+
+ size_t cchLen = pLast - pFirst + 1;
+ WCHAR * szArgCopy = new WCHAR[cchLen];
+ if (!szArgCopy || FAILED(StringCchCopyW(szArgCopy, cchLen, pFirst)))
+ {
+ SetErrorMessage(W("Out of memory."));
+ break;
+ }
+ WStrList * listArgNew = new WStrList( szArgCopy, (*argLast));
+ if (!listArgNew)
+ {
+ SetErrorMessage(W("Out of memory."));
+ break;
+ }
+
+ *argLast = listArgNew;
+ argLast = &listArgNew->next;
+ }
+
+ delete[] szTemp;
+
+}
+
+//
+// Pass in the command line args, argc and argv
+//
+// We expand any response files that may be contained in the args and return a new
+// set of args, pargc2 and pppargv2 that contain the full flat command line.
+//
+bool ConsoleArgs::ExpandResponseFiles(__in int argc, __deref_in_ecount(argc) const LPCWSTR * argv, int * pargc2, __deref_out_ecount(*pargc2) LPWSTR ** pppargv2)
+{
+ *pargc2 = 0;
+ *pppargv2 = NULL;
+ WStrList **argLast = &m_listArgs;
+ while (argc > 0)
+ {
+ // Make a copy of the original var args so we can just delete[] everything
+ // once parsing is done: original args and new args from response files
+ // mixed in amongst the originals.
+ LPWSTR copyArg = new WCHAR[wcslen(argv[0]) + 1];
+ if (!copyArg)
+ {
+ SetErrorMessage(W("Out of memory."));
+ return false;
+ }
+ wcscpy_s(copyArg, wcslen(argv[0]) + 1, argv[0]);
+
+ WStrList * listArgNew = new WStrList(copyArg, (*argLast));
+ if (!listArgNew)
+ {
+ SetErrorMessage(W("Out of memory."));
+ return false;
+ }
+
+ *argLast = listArgNew;
+ argLast = &listArgNew->next;
+
+ argc--;
+ argv++;
+ }
+
+ // Process Response Files
+ ProcessResponseArgs();
+ if (m_errorOccurred)
+ return false;
+
+ // Now convert to an argc/argv form for remaining processing.
+ int newArgc = 0;
+ for (WStrList * listCurArg = m_listArgs; listCurArg != NULL; listCurArg = listCurArg->next)
+ {
+ if (listCurArg->arg)
+ ++newArgc;
+ }
+
+ m_rgArgs = new LPWSTR[newArgc];
+ if (!m_rgArgs)
+ {
+ SetErrorMessage(W("Out of memory."));
+ return false;
+ }
+ int i = 0;
+ for (WStrList * listCurArg = m_listArgs; listCurArg != NULL; listCurArg = listCurArg->next)
+ {
+ if (listCurArg->arg)
+ {
+ LPWSTR newString = new WCHAR[wcslen(listCurArg->arg) + 1];
+ wcscpy_s(newString, wcslen(listCurArg->arg) + 1, listCurArg->arg);
+ m_rgArgs[i++] = newString;
+ }
+ }
+
+ *pargc2 = newArgc;
+ *pppargv2 = m_rgArgs;
+ return !m_errorOccurred;
+}
+
+//
+// Read file to end, converting to unicode
+// ppwzTextBuffer is allocated. Caller is responsible for freeing
+//
+bool ConsoleArgs::ReadTextFile(LPCWSTR pwzFilename, __deref_out LPWSTR *ppwzTextBuffer)
+{
+ bool success = false;
+ char *bufA = nullptr;
+ WCHAR *bufW = nullptr;
+
+ HANDLE hFile = CreateFile(pwzFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ SetErrorMessage(W("Cannot open response file."));
+ goto ErrExit;
+ }
+
+ {
+ DWORD size = GetFileSize(hFile, NULL);
+ bufA = new char[size];
+
+ if (!bufA)
+ {
+ SetErrorMessage(W("Out of memory"));
+ goto ErrExit;
+ }
+ DWORD numRead = 0;
+ if (!ReadFile(hFile, bufA, size, &numRead, NULL) || numRead != size)
+ {
+ SetErrorMessage(W("Failure reading response file."));
+ goto ErrExit;
+ }
+
+ char *postByteOrderMarks = bufA;
+
+ //
+ // If there are Byte Order Marks, skip them make sure they are ones that don't
+ // require us to handle the wrong endianness
+ //
+
+ byte byte0 = (byte)bufA[0];
+ byte byte1 = (byte)bufA[1];
+ byte byte2 = (byte)bufA[2];
+ byte byte3 = (byte)bufA[3];
+
+ bool alreadyUtf16 = false;
+
+ if (byte0 == 0xEF && byte1 == 0xBB && byte2 == 0xBF)
+ {
+ postByteOrderMarks += 3;
+ size -= 3;
+ }
+ else if (byte0 == 0xFF && byte1 == 0xFE)
+ {
+ postByteOrderMarks += 2;
+ size -= 2;
+ alreadyUtf16 = true;
+ }
+ else if (byte0 == 0xFE && byte1 == 0xFF)
+ {
+ SetErrorMessage(W("Invalid response file format. Use little endian encoding with Unicode"));
+ goto ErrExit;
+ }
+ else if ((byte0 == 0xFF && byte1 == 0xFE && byte2 == 0x00 && byte3 == 0x00) ||
+ (byte0 == 0x00 && byte1 == 0x00 && byte2 == 0xFE && byte3 == 0xFF))
+ {
+ SetErrorMessage(W("Invalid response file format. Use ANSI, UTF-8, or UTF-16"));
+ goto ErrExit;
+ }
+
+ if (alreadyUtf16)
+ {
+ //
+ // File is already formatted as UTF-16; just copy the bytes into the output buffer
+ //
+ int requiredSize = size + 2; // space for 2 nullptr bytes
+
+ // Sanity check - requiredSize better be an even number since we're dealing with UTF-16
+ if (requiredSize % 2 != 0)
+ {
+ SetErrorMessage(W("Response file corrupt. Expected UTF-16 encoding but we had an odd number of bytes"));
+ goto ErrExit;
+ }
+
+ requiredSize /= 2;
+
+ bufW = new WCHAR[requiredSize];
+ if (!bufW)
+ {
+ SetErrorMessage(W("Out of memory"));
+ goto ErrExit;
+ }
+
+ memcpy(bufW, postByteOrderMarks, size);
+ bufW[requiredSize - 1] = L'\0';
+ }
+ else
+ {
+ //
+ // File is formated as ANSI or UTF-8 and needs converting to UTF-16
+ //
+ int requiredSize = MultiByteToWideChar(CP_UTF8, 0, postByteOrderMarks, size, nullptr, 0);
+ bufW = new WCHAR[requiredSize + 1];
+ if (!bufW)
+ {
+ SetErrorMessage(W("Out of memory"));
+ goto ErrExit;
+ }
+
+ if (!MultiByteToWideChar(CP_UTF8, 0, postByteOrderMarks, size, bufW, requiredSize))
+ {
+ SetErrorMessage(W("Failure reading response file."));
+ goto ErrExit;
+ }
+
+ bufW[requiredSize] = L'\0';
+ }
+
+ *ppwzTextBuffer = bufW;
+
+ success = true;
+ }
+
+ErrExit:
+ if (bufA)
+ {
+ delete[] bufA;
+ }
+ CloseHandle(hFile);
+ return success;
+}
+
+/*
+ * Process Response files on the command line
+ */
+void ConsoleArgs::ProcessResponseArgs()
+{
+ HRESULT hr;
+ b_tree *response_files = NULL;
+
+ WCHAR szFilename[MAX_LONGPATH];
+
+ for (WStrList * listCurArg = m_listArgs;
+ listCurArg != NULL && !m_errorOccurred;
+ listCurArg = listCurArg->next)
+ {
+ WCHAR * szArg = listCurArg->arg;
+
+ // Skip everything except Response files
+ if (szArg == NULL || szArg[0] != '@')
+ continue;
+
+ if (wcslen(szArg) == 1)
+ {
+ SetErrorMessage(W("No response file specified"));
+ goto CONTINUE;
+ }
+
+ // Check for duplicates
+ if (!GetFullFileName(&szArg[1], szFilename, MAX_LONGPATH, false))
+ continue;
+
+
+ hr = TreeAdd(&response_files, szFilename);
+ if (hr == E_OUTOFMEMORY)
+ {
+ SetErrorMessage(W("Out of memory."));
+ goto CONTINUE;
+ }
+ else if (hr == S_FALSE)
+ {
+ SetErrorMessage(W("Duplicate response file."));
+ goto CONTINUE;
+ }
+
+ {
+ LPWSTR pwzFileBuffer;
+ pwzFileBuffer = nullptr;
+ if (!ReadTextFile(szFilename, &pwzFileBuffer))
+ {
+ goto CONTINUE;
+ }
+
+ LPWSTR szActualText = nullptr;
+#ifdef PLATFORM_UNIX
+ szActualText = pwzFileBuffer;
+#else
+ DWORD dwNumChars = ExpandEnvironmentStrings(pwzFileBuffer, NULL, 0);
+ LPWSTR szExpandedBuffer = new WCHAR[dwNumChars];
+ if (szExpandedBuffer != nullptr)
+ {
+ DWORD dwRetVal = ExpandEnvironmentStrings(pwzFileBuffer, szExpandedBuffer, dwNumChars);
+
+ if (dwRetVal != 0)
+ {
+ szActualText = szExpandedBuffer;
+ }
+ else
+ {
+ // Expand failed
+
+ }
+ }
+#endif
+
+ TextToArgs(szActualText, &listCurArg->next);
+ }
+
+CONTINUE: // remove the response file argument, and continue to the next.
+ listCurArg->arg = NULL;
+ }
+
+ CleanupTree(response_files);
+}
+
diff --git a/src/tools/util/consoleargs.h b/src/tools/util/consoleargs.h
new file mode 100644
index 0000000000..06b6e75384
--- /dev/null
+++ b/src/tools/util/consoleargs.h
@@ -0,0 +1,72 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef __CONSOLEARGS_H__
+#define __CONSOLEARGS_H__
+
+#include "list.h"
+#include "tree.h"
+#include <strsafe.h>
+
+#include "palclr.h"
+
+typedef tree<LPCWSTR> b_tree;
+typedef list<WCHAR*> WStrList;
+
+const LPCWSTR kOutOfMemory = W("Out of memory");
+
+class ConsoleArgs
+{
+public:
+ // Place the fully-qualified filename in the given output buffer
+ bool GetFullFileName(LPCWSTR szSource, __out_ecount(cbFilenameBuffer) LPWSTR filenameBuffer, DWORD cbFilenameBuffer, bool fOutputFilename);
+
+ ConsoleArgs() :
+ m_rgArgs(NULL),
+ m_listArgs(NULL),
+ m_errorOccurred(false),
+ m_lastErrorMessage(nullptr)
+ {
+ };
+
+ ~ConsoleArgs()
+ {
+ CleanUpArgs();
+ };
+
+ // returns false if there are errors
+ bool ExpandResponseFiles(__in int argc, __deref_in_ecount(argc) const LPCWSTR * argv, int * pargc2, __deref_out_ecount(*pargc2) LPWSTR ** pppargv2);
+
+ // Frees all memory used by the arg list and the argv/argc array
+ void CleanUpArgs();
+
+ LPCWSTR ErrorMessage()
+ {
+ if (m_errorOccurred)
+ {
+ return m_lastErrorMessage;
+ }
+ else
+ {
+ return nullptr;
+ }
+ }
+
+private:
+ void SetErrorMessage(__in LPCWSTR pwzMessage);
+ b_tree * MakeLeaf( LPCWSTR szText);
+ void CleanupTree( b_tree * root);
+ HRESULT TreeAdd( b_tree ** root, LPCWSTR szAdd);
+ void TextToArgs( LPCWSTR szText, WStrList ** listReplace);
+ bool ReadTextFile(LPCWSTR pwzFilename, __deref_out LPWSTR *ppwzTextBuffer);
+ void ProcessResponseArgs();
+
+ LPWSTR * m_rgArgs;
+ WStrList * m_listArgs;
+
+ bool m_errorOccurred;
+ LPCWSTR m_lastErrorMessage;
+};
+
+#endif // __CONSOLEARGS_H__
diff --git a/src/tools/util/file_can.h b/src/tools/util/file_can.h
new file mode 100644
index 0000000000..71031eb9d7
--- /dev/null
+++ b/src/tools/util/file_can.h
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef __FILE_CAN_H__
+#define __FILE_CAN_H__
+
+class CFileChecksum;
+
+enum FileType
+{
+ ftUnknown = 0,
+ ftUnicode,
+ ftSwappedUnicode,
+ ftUTF8,
+ ftASCII,
+ ftBinary
+};
+
+HANDLE OpenFileEx( LPCWSTR filename, DWORD *fileLen, LPCWSTR relPath = NULL, bool bWrite = false);
+HRESULT ReadTextFile (PCWSTR pszFileName, UINT uiCodePage, WCAllocBuffer & textBuffer, FileType *fileType);
+#if !defined(FEATURE_PAL) && !defined(CSEE)
+// If you call ReadTextFile a lot you should create one HCRYPTPROV and pass it in to every call, otherwise
+// ReadTextFile indirectly creates and destroys a new HCRYPTPROV for every call, which is slow and unnecessary.
+// You can use CryptProvider to manage an HCRYPTPROV for you.
+HRESULT ReadTextFile (PCWSTR pszFileName, UINT uiCodePage, WCAllocBuffer & textBuffer, FileType *fileType, CFileChecksum *pChecksum, HCRYPTPROV hCryptProv = NULL);
+#endif
+
+// Src and Dest may be the same buffer
+// Returns 0 for error (check via GetLastError()) or count of characters
+// (not including NULL) copied to Dest.
+// if fPreserveSrcCasing is set, ignores on-disk casing of filename (but still gets on-disk casing of directories)
+// if fPreserveSrcCasing is set and and existing file matches with different short/longness it will fail
+// and set the error code to ERROR_FILE_EXISTS
+DWORD GetCanonFilePath(LPCWSTR wszSrcFileName, WCBuffer outBuffer, bool fPreserveSrcCasing);
+
+// GetCanonFilePath uses a cache to eliminate redundant calls to FindFirstFile. This cache
+// is global and is thus long lived. The IDE would like to minimize memory impact, so
+// ClearGetCanonFilePathCache is provided here for them to clear the cache when appropriate.
+void ClearGetCanonFilePathCache();
+
+// Remove quote marks from a string.
+// Translation is done in-place
+LPWSTR RemoveQuotes(WCBuffer textBuffer);
+
+// Remove quote marks from a string.
+// Replace various characters with other illegal characters if unquoted.
+// Translation is done in-place.
+LPWSTR RemoveQuotesAndReplaceComma(WCBuffer textBuffer); // "," -> "|"
+LPWSTR RemoveQuotesAndReplacePathDelim(WCBuffer textBuffer); // ",;" -> "|"
+LPWSTR RemoveQuotesAndReplaceAlias(WCBuffer textBuffer); // ",;" -> "|" and "=" -> "\x1"
+
+// Safe version of ToLowerCase
+// Gaurantees null termination even if buffer size is too small
+inline PWSTR WINAPI SafeToLowerCase (PCWSTR pSrc, WCBuffer textBuffer)
+{
+ PWSTR returnValue = ToLowerCase(pSrc, textBuffer.GetData(), textBuffer.Count());
+ if (textBuffer.Count() > 0)
+ {
+ textBuffer.SetAt(textBuffer.Count() - 1, 0);
+ }
+ return returnValue;
+}
+
+// Joins a relative or absolute filename to the given path and stores the new
+// filename in lpBuffer
+bool MakePath( /*[in]*/LPCWSTR lpPath, /*[in]*/LPCWSTR lpFileName, WCBuffer pathBuffer);
+
+#endif // __FILE_CAN_H__
diff --git a/src/tools/util/list.h b/src/tools/util/list.h
new file mode 100644
index 0000000000..1748ed9cd3
--- /dev/null
+++ b/src/tools/util/list.h
@@ -0,0 +1,25 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef __GENERIC_LIST_H__
+#define __GENERIC_LIST_H__
+
+// Simple parameterized linked list
+// with some good ctors
+template <typename _T>
+struct list
+{
+ _T arg;
+ list<_T> *next;
+
+ list(_T t, list<_T> *n)
+ {
+ arg = t, next = n;
+ }
+ list() : arg(), next(NULL)
+ {
+ }
+};
+
+#endif // __GENERIC_LIST_H__
diff --git a/src/tools/util/tree.h b/src/tools/util/tree.h
new file mode 100644
index 0000000000..164f4c6975
--- /dev/null
+++ b/src/tools/util/tree.h
@@ -0,0 +1,242 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef __GENERIC_TREE_H__
+#define __GENERIC_TREE_H__
+
+#include <windows.h>
+
+// Partially balanced binary tree
+// it does individual rotations on insertion, but does nto allow deletion.
+// thus the worst case depth is not (n), but (n/2)
+// Generic paramter is the element type
+// Find and Add require a method that compares 2 elements
+template <typename _E>
+struct tree
+{
+ _E name;
+ tree<_E> *lChild;
+ tree<_E> *rChild;
+ size_t lDepth;
+ size_t rDepth;
+
+ tree(_E e)
+ {
+ name = e;
+ lChild = rChild = NULL;
+ lDepth = rDepth = 0;
+ }
+ ~tree()
+ {
+ Cleanup();
+ }
+
+ bool InOrderWalk( bool (WalkFunc)(_E))
+ {
+ if (lChild != NULL && !lChild->InOrderWalk(WalkFunc))
+ return false;
+ if (!WalkFunc(name))
+ return false;
+ if (rChild != NULL)
+ return rChild->InOrderWalk(WalkFunc);
+ return true;
+ }
+
+ /*
+ * return the depths of the tree from here down (minimum of 1)
+ */
+ size_t MaxDepth()
+ {
+ return lDepth > rDepth ? lDepth + 1 : rDepth + 1;
+ }
+
+ /*
+ * Search the binary tree for the given string
+ * return a pointer to it was added or NULL if it
+ * doesn't exist
+ */
+ _E * Find(_E SearchVal, int (__cdecl CompFunc)(_E, _E))
+ {
+ int cmp = CompFunc(name, SearchVal);
+ if (cmp < 0)
+ {
+ if (lChild == NULL)
+ return NULL;
+ else
+ return lChild->Find(SearchVal, CompFunc);
+ }
+ else if (cmp > 0)
+ {
+ if (rChild == NULL)
+ return NULL;
+ else
+ return rChild->Find(SearchVal, CompFunc);
+ }
+ else
+ return &name;
+ }
+
+ /*
+ * Search the binary tree and add the given string
+ * return S_OK if it was added or S_FALSE if it already
+ * exists (or E_OUTOFMEMORY)
+ */
+ HRESULT Add(_E add
+ , int (__cdecl CompFunc)(_E, _E))
+ {
+ int cmp = CompFunc(name, add
+ );
+REDO:
+ if (cmp == 0)
+ return S_FALSE;
+
+ if (cmp < 0)
+ {
+ if (lChild == NULL)
+ {
+ lDepth = 1;
+ lChild = new tree<_E>(add
+ );
+ if (lChild == NULL)
+ return E_OUTOFMEMORY;
+ return S_OK;
+ }
+ else if (rDepth < lDepth)
+ {
+ tree<_E> *temp = new tree<_E>(name);
+ if (temp == NULL)
+ return E_OUTOFMEMORY;
+ temp->rChild = rChild;
+ temp->rDepth = rDepth;
+ if (lChild != NULL &&
+ (cmp = CompFunc(lChild->name, add
+ )) > 0)
+ {
+ // push right
+ temp->lChild = NULL;
+ temp->lDepth = 0;
+ name = add
+ ;
+ rChild = temp;
+ rDepth++;
+ return S_OK;
+ }
+ else if (cmp == 0)
+ {
+ temp->rChild = NULL;
+ delete temp;
+ return S_FALSE;
+ }
+ else
+ {
+ // Rotate right
+ temp->lChild = lChild->rChild;
+ temp->lDepth = lChild->rDepth;
+ name = lChild->name;
+ lDepth = lChild->lDepth;
+ rDepth = temp->MaxDepth();
+ rChild = temp;
+ temp = lChild->lChild;
+ lChild->lChild = lChild->rChild = NULL;
+ delete lChild;
+ lChild = temp;
+ goto REDO;
+ }
+ }
+ else
+ {
+ HRESULT hr = lChild->Add(add
+ , CompFunc);
+ lDepth = lChild->MaxDepth();
+ return hr;
+ }
+ }
+ else
+ {
+ if (rChild == NULL)
+ {
+ rDepth = 1;
+ rChild = new tree<_E>(add
+ );
+ if (rChild == NULL)
+ return E_OUTOFMEMORY;
+ return S_OK;
+ }
+ else if (lDepth < rDepth)
+ {
+ tree<_E> *temp = new tree<_E>(name);
+ if (temp == NULL)
+ return E_OUTOFMEMORY;
+ temp->lChild = lChild;
+ temp->lDepth = lDepth;
+ if (rChild != NULL &&
+ (cmp = CompFunc(rChild->name, add
+ )) < 0)
+ {
+ // push left
+ temp->rChild = NULL;
+ temp->rDepth = 0;
+ name = add
+ ;
+ lChild = temp;
+ lDepth++;
+ return S_OK;
+ }
+ else if (cmp == 0)
+ {
+ temp->lChild = NULL;
+ delete temp;
+ return S_FALSE;
+ }
+ else
+ {
+ // Rotate left
+ temp->rChild = rChild->lChild;
+ temp->rDepth = rChild->lDepth;
+ name = rChild->name;
+ rDepth = rChild->rDepth;
+ lDepth = temp->MaxDepth();
+ lChild = temp;
+ temp = rChild->rChild;
+ rChild->rChild = rChild->lChild = NULL;
+ delete rChild;
+ rChild = temp;
+ goto REDO;
+ }
+ }
+ else
+ {
+ HRESULT hr = rChild->Add(add
+ , CompFunc);
+ rDepth = rChild->MaxDepth();
+ return hr;
+ }
+ }
+ }
+
+ /*
+ * Free the memory allocated by the tree (recursive)
+ */
+ void Cleanup()
+ {
+ if (this == NULL)
+ return ;
+ if (lChild != NULL)
+ {
+ lChild->Cleanup();
+ delete lChild;
+ lChild = NULL;
+ }
+ if (rChild != NULL)
+ {
+ rChild->Cleanup();
+ delete rChild;
+ rChild = NULL;
+
+ }
+ }
+
+};
+
+#endif // __GENERIC_TREE_H__