Friday, October 8, 2010

Regenerating a decompiled database

With all of the work done to decompile the database it was time to take the big leap: reversing the procedure. Most of this wasn’t particularly difficult.
Forms, Reports, Macros, Modules, and Queries are all output with the little-to-no-documentation api call Application.SaveAsText. This hidden method outputs the object in question as a single text file. So reloading these objects was a piece of cake: simply use the also-little-to-no-documentation api call Application.LoadFromText. Tables were just about as easy I used the Application.ExportXML method to export just the schema for the tables. For some tables, I also manually exported the data in them. The reverse was a simple call to Application.ImportXML.
The difficulties came with the things I was saving the Project.xml meta-data file. These had to be manually recreated. This was fairly straight forward for things like the project properties, relationships, and linked tables. The two spots where it wasn’t were the startup options and object descriptions.

Startup options and other Jet properties

These properties were much more difficult to output. For one thing, they only get output if we are talking about an mdb file, not and adp file. Second, we have to be sure to *only* export those properties that can be modified. For instance, for an mdb file, the startup options are stored in the Jet properties. These are configurable through the Tools->Startup… menu. However, there are also several properties such as Name, ReplicaID, and Version that are read-only. So for this, I made a list of properties that should not change and I only export/import them if Application.CurrentDb() returns something other than null.

Object Descriptions

Access has a really cool feature that you can apply a description to all of the objects through the database window. This is really useful for putting quick overview documentation so that you can see what an object is used for at a glance. Trouble is, the only thing that exports its description with its definition is the queries, and those only if you use the SaveAsText method. So I had to output them manually.
The second issue is that where these descriptions are saved is dependent on the type of database. In an adp file, they stored as an AccessObject.Properties(“Description”) object in the appropriate AllObject collection on the CurrentProject. For an mdb file, however, they are stored on the Document.Properties(“Description”) for the DAO.Document in the Jet database. Just as bad, if the objects description is not set, this property is not empty, it doesn’t exist.
My solution to this was a little convoluted and hackish. There is a lot of procedural code (read a lot of if-then statements) that decide where to get the descriptions from, which descriptions to get, and if a description is even present. This code seriously needs to be refactored.

Conclusion

So other than some refactoring, I am happy with the new solution that allows me to compile and decompile a database. Right? Well, not really. See here’s the thing. I set out to right a build system that would integrate with COM nicely without the presence of PowerShell. Trouble is, at this point, I have about 155 lines of code dedicated toward task management, the primary burden of the build system. And then I have 590 lines of code dedicated to automating Access as an addin. I have four times as much code dedicated to being a *compiler* than I do being a *build system*. That does not make me happy. But short of building an actual compiler for access, and then modifying the addin to simply call in to the compiler… I am not sure what I’m going to do yet.

No comments: