PELib
PELib is the main interface class in the DotNetPELib library.   Most of the functions available from the library are accessible through this class; because it also inherits from Allocator, in practice most constructors for other classes are also accessed using PELib as the interface.

PELib is usually constructed directly; there is no corresponding constructor within the Allocator class.  AssemblyName is the name of the assembly, and CoreFlags usually has ILONLY set and may have BITS32 set as well.   This constructor also creates the main AssemblyDef entity, where the generated program will be defined.

        enum CorFlags {
            ilonly = 1,
            bits32 = 2
        };

        PELib(std::string AssemblyName, int CoreFlags);

Retrieve the main assembly.   Useful for setting things like version information, or strong name key files.

        AssemblyDef *WorkingAssembly() const { return assemblyRefs_.front(); }

Add a reference to an external assembly.    You can put external references in it if you want.   This is a legacy function; as of version 2.0 of the library it is generally more useful just to load the external reference from disk than to create one from scratch.

        void AddExternalAssembly(std::string assemblyName, Byte *publicKeyToken = nullptr);

Entry point to load an external assembly.   Searches GACs in this order:
1) v4.0 cache, MSIL
2) v4.0 cache, 32-bit
3) pre-v4.0 cache, MSIL
4) pre-v4.0 cache, 32-bit

Currently there is no ability to set a search path however if the assembly is path-qualified it will look for it in an explicit place.   The assembly should not have .dll in the name.   If the version is left at the default the latest version will be chosen; otherwise the DotNetPELib will look for an exact match to the version.  

The actual assembly version and the short version of the strong name key( if any) will be embedded with any reference to the loaded assembly.

        int LoadAssembly(std::string assemblyName, int major = 0, int minor = 0, int build = 0, int revision = 0);

Load the references from an unmanaged DLL.   Occil uses this to figure out what should be a PInvoke.   Note that you still need to provide MethodSignatures for any reference you use.   occil uses the windows header files for this.

        int LoadUnmanaged(std::string dllName);

Load a per-module object file into the working assembly. Will also create entries in other assemblies and pinvokes as needed.

        int LoadObject(std::string Name);

Look up a name in the unmanaged dictionary; return its DLL or an empty string if it doesn't exist

        std::string PELib::FindUnmanagedName(std::string name);

Find an assembly by name

        AssemblyDef *FindAssembly(std::string assemblyName) const;

Add a reference to generate a PInvoke import.   Note these ARE added directly to the PELib object, since they aren't associated with any particular assembly.

        void AddPInvokeReference(MethodSignature *methodsig, std::string dllname, bool iscdecl);

Get the core flags value.

        int GetCorFlags() const { return corFlags_; }


Write the working assembly to an output file, making it a console or GUI file.   Possibilities are a .IL file, an EXE file, a DLL, or a per-module object file. Note: if writing an object file you need to optimize methods when you read it back in, rather than before you write it out.

       enum OutputMode {
           ilasm,
           peexe,
           pedll,
           object
       };

       bool DumpOutputFile(std::string fileName, OutputMode mode, bool Gui);


Add a namespace search path.   similar to the 'using' directive in C#.

        bool AddUsing(std::string path);


Find something that exists uniquely, return type indicates what was found.   Usually one would consult the .NET documentation to know what to search for.

This function will not find a method, if the method is overloaded.   That would result in multiple matches.

        enum eFindType {
            s_notFound=0,
            s_ambiguous=1,
            s_namespace,
            s_class,
            s_enum,
            s_field,
            s_property,
            s_method
        };

        eFindType Find(std::string path, void **result, AssemblyDef *assembly = nullptr);


Find a method, with an explicit overload signature.

        eFindType Find(std::string path, Method **result, std::vector<Type *> args, AssemblyDef *assembly = nullptr);

Traverse the declaration tree.   Functions in the Callback instance will be called as namespaces and classes are entered and exited, and to signify fields, methods, and properties.   Generally, returning false from one of these functions stops the current phase of traversal and returning true keeps the traversal going. This could be used to check validity of definitions (e.g. for extern/public matching), or to go through the the entire list of definitions to optimize methods.

        void Traverse(Callback &callback) const;