Thanks to the advice of @HansPassant, I was able to get a list of string literals in the assembly. Which is very close to what I originally wanted.
You need to use assembly read metadata and list custom strings. This can be done using these three IMetaDataImport methods:
[ComImport, Guid("7DAC8207-D3AE-4C75-9B67-92801A497D44")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IMetaDataImport { void CloseEnum(IntPtr hEnum); uint GetUserString(uint stk, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] char[] szString, uint cchString, out uint pchString); uint EnumUserStrings(ref IntPtr phEnum, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]uint[] rStrings, uint cmax, out uint pcStrings);
To get an instance of IMetaDataImport , you need to get IMetaDataDispenser :
[ComImport, Guid("809C652E-7396-11D2-9771-00A0C9B4D50C")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [CoClass(typeof(CorMetaDataDispenser))] interface IMetaDataDispenser { uint OpenScope([MarshalAs(UnmanagedType.LPWStr)]string szScope, uint dwOpenFlags, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppIUnk);
Here's how to do it:
var dispenser = new IMetaDataDispenser(); var metaDataImportGuid = new Guid("7DAC8207-D3AE-4C75-9B67-92801A497D44"); object scope; var hr = dispenser.OpenScope(location, 0, ref metaDataImportGuid, out scope); metaDataImport = (IMetaDataImport)scope;
where location is the path to the build file.
After that, the call to EnumUserStrings() and GetUserString() is disconnected.
Here 's a blog post with more details and a demo project on GitHub .