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;