Before we begin i want to say couple words about the projects. These projects were not tested well enough therefore it can cause problems. The loader doesn't support most of the features of PE files therefore some executables may not work.
So...
This overview consists three projects:
- Compiler - it is the biggest project of all. It creates an installation based on the loader, user files, commands and manifest;
- Loader - it is the simple loader that performs commands, unpacks files and runs an executable from memory;
- Patcher - it is the small utility that removes the runtime import from an executable file.
I call an exe that contains the commands, files and executable file the installation. The main idea is to put the information about an installation to the resources of the loader. When the loader is being loaded it reads the information and performs the commands from resources. I decided to use an special storage to save the files and exe, and other storage for commands.
The first storage stores all the files that will be unpacked, and the main executable that will be launched. The second storage stores the commands that will be passed to the ShellExecuteEx function after unpacking process will have been completed. The loader supports the following wildcards (for path):
- <app> - application installed path;
- <win> - system windows directory;
- <sys> - System32 directory;
- <drv> - system drive;
- <tmp> - temporary directory;
- <dtp> - user desktop.
Compiler.
This is the application that forms the installation information and puts it to the loader resource. All the information is stored in a project. You can save and load a project from file. The clsProject class in VB project represents the compiler-project. This compiler has 3 sections: storage, execute, manifest.
The 'storage' section allows to add the files that will be copied when the application is being launched. Each item in the list has flags: 'replace if exists', 'main executable', 'ignore error'. If you select 'replace if exists' flag a file will be copied even if one exists. The 'main executable' flag can be set only for the single executable file. It means that this file will be launched when all the operations have been performed. The 'ignore error' flag makes ignore any errors respectively. The order in the list corresponds the order of extracting the files except the main executable. The main executable is not extracted and is launched after all the operations. The storage section is represented as clsStorage class in the VB project. This class implements the standard collection of the clsStorageItem objects and adds some additional methods.The MainExecutable property determines the index of main executable file in the storage. When this parameter equal -1 executable file is not presented. The clsStoragaItem class represent the single item in the storage list. It has some properties that determine the behavior of item. This section is helpful if you want to copy files to disk before execution of the application.
The next section is the 'execute'. This section allows execute any commands. This commands just pass to ShellExecuteEx function. Thus you can register libraries or do something else. Each item in the execution list has two properties: the executable path and parameters. Both the path and the parameters is passed to ShellExecuteEx function. It is worth noting that all the operations is performed synchronously in the order that set in the list. It also has the 'ignore error' flag that prevents appearance any messages if an error occurs. The execute section is represented as two classes: clsExecute and clsExecuteItem. These classes are similar to the storage classes.
The last section is 'manifest'. It is just the manifest text file that you can add to the final executable. You should check the checkbox 'include manifest' in the 'manifest' tab if you wan to add manifest. It can be helpful for Free-Reg COM components or for visual styles.
All the classes refer to the project object (clsProject) that manages them. Each class that refers to project can be saved or loaded to the PropertyBag object. When a project is being saved it alternately saves each entity to the property bag, same during loading. It looks like a IPersistStream interface behavior. All the links to the storage items in the project is stored with relative paths (like a VB6 .vbp file) hence you can move project folder without issues. In order to translate from/to relative/absolute path i used PathRelativePathTo and PathCanonicalize functions.
So... This was basic information about compiler project. Now i want to talk about compilation procedure. As i said all the information about extracting/executing/launching is stored to the loader resources. At first we should define the format of the data. This information is represented in the following structures:
Code:
' // Storage list item
Private Type BinStorageListItem
ofstFileName As Long ' // Offset of file name
ofstDestPath As Long ' // Offset of file path
dwSizeOfFile As Long ' // Size of file
ofstBeginOfData As Long ' // Offset of beginning data
dwFlags As FileFlags ' // Flags
End Type
' // Execute list item
Private Type BinExecListItem
ofstFileName As Long ' // Offset of file name
ofstParameters As Long ' // Offset of parameters
dwFlags As ExeFlags ' // Flags
End Type
' // Storage descriptor
Private Type BinStorageList
dwSizeOfStructure As Long ' // Size of structure
iExecutableIndex As Long ' // Index of main executable
dwSizeOfItem As Long ' // Size of BinaryStorageItem structure
dwNumberOfItems As Long ' // Number of files in storage
End Type
' // Execute list descriptor
Private Type BinExecList
dwSizeOfStructure As Long ' // Size of structure
dwSizeOfItem As Long ' // Size of BinaryExecuteItem structure
dwNumberOfItems As Long ' // Number of items
End Type
' // Base information about project
Private Type BinProject
dwSizeOfStructure As Long ' // Size of structure
storageDescriptor As BinStorageList ' // Storage descriptor
execListDescriptor As BinExecList ' // Command descriptor
dwStringsTableLen As Long ' // Size of strings table
dwFileTableLen As Long ' // Size of data table
End Type