How to install Inmagic DB/Textworks on Vista

by Peter Tyrrell Friday, June 15, 2007 5:05 PM

Right-click on the db/textworks installer. Choose "run as administrator". You may be prompted to proceed and/or enter administrative credentials, depending on your Vista setup. The installer will start installing and should work fine.

If you do not run as administrator, you will get an error like this:

Error 1925. You do not have sufficient privileges to complete this installation for all users of the machine. Log on as administrator & retry installation.

You may be confused by this message if you are logged in as an administrator. Welcome to Vista's User Account Control (UAC).

With UAC, you may have logged in as an admin, but you are not running as one. Instead you are prompted to elevate your permissions whenever you attempt an administrator-level operation. It so happens that Inmagic has not updated db/textworks to handle this scenario and give you fair warning. The error message it gives upon failure is at least completely accurate in its diagnosis, but leaves it up to you to manually elevate your permissions.

Here are some other Inmagic-on-Vista related posts on the Andornot Developer Blog:

No time for Textworks date fields

by Peter Tyrrell Friday, June 01, 2007 12:33 PM

Ha ha! That was a pun, that was. "No time for Textworks date fields." Phew... that is the kind of half-inflated rubber-mattress-smelling type of humour I am capable of, here on this highly informative forum.

So I discovered the other day, quite by accident, that Inmagic textbase Date fields are exactly that and no more. By which I mean: Date fields are not DateTime fields.

Perhaps on the surface this seems a trivial distinction. Let me assure you, my dear confidant, it is not.

You can enter time information in a non-strict Date field, or one that has trailing text enabled, but the time you enter is just a string. It is not understood as a chronological statement. You might as well type "blah blah blah" instead of "09:00:00 AM" for all the good it does you, because you can't search for, or sort by, time. You and I know that 1:00:00 PM comes after 12:00:00 PM, but Inmagic doesn't.

Here's an example where I told the report to sort by a date field. Note that it is NOT sorting chronologically, but rather, numerically.


I'm so surprised that there is no way to handle chronological data. In the languages, programming environments, and database systems I work with, it's just assumed that Date fields, classes, and variables are date-plus-time: DateTime objects. The assumption is such that you can call a DateTime object a Date, in fact, and everyone already knows you really mean DateTime but aren't pretentious enough to have to say it. (The javascript Date object is an example off the top of my head.)

A DateTime object can of course show a date without time, but that's just a matter of formatting. The information about time is still in there. And, even if you instantiate a DateTime object with a date string and don't include the time, the time defaults to 00:00:00.

Anyway, I'm not sure what to do about this.

Watch out for file encoding when importing into Inmagic Textworks

by Peter Tyrrell Thursday, May 31, 2007 2:21 PM

When importing a text file into a Textworks database, make sure it is ANSI/ASCII encoded, not UTF-8 or otherwise.

You can't tell just by looking at the text how the file has been encoded, but a good text editor will tell you, and allow you to save as another encoding format.

Note that Textworks is not going to warn you about encoding incompatibilities specifically. It's just going to drastically misinterpret characters. Lucky for me this happened before import got underway, as the misinterpretation involved a field name match.

As a nota bene, the above shows how misleading it is to refer to any delimited text file as an "ASCII delimited file," as I've heard them referred to before. Unless of course you happen to mean literally ASCII-encoded as opposed to UTF.

How to serialize an object to Inmagic Textworks userStore with JSON

by Peter Tyrrell Thursday, May 17, 2007 11:28 PM

The Inmagic DB/Textworks and CS/Textworks script object model includes a Store object which you can use to store strings. It's a simple dictionary object of key/value pairs where the key is a unique identifier for the corresponding value. There are two versions of the Store object: userStore and sessionStore. The first persists key/value pairs to the local machine, while sessionStore only sticks around so long as Textworks is open.

It's a lot like writing cookies. If you need to keep some values around to reuse that would otherwise disappear when the form unloads, you need to use the Store object.


var myString = "foo";

Application.userStore.value("keyName") = myString;



var myString = "";

myString = Application.userStore.value("keyName");

Unfortunately it only stores a string, like a cookie. If you like to work with objects, it doesn't seem right to store individual object properties as separate key/value pairs. Especially if you decide to change the object profile down the road, because you will have to rewrite code. It would be great to simply store an object's state and pick it back up again whenever.

Serialize the object

Serialization is the act of saving an object into a binary or text format. Aha! Text format - that's a string. We can save our object to a string, and persist it to the Store object. Then later we can get that string and deserialize back into an object.

What's the best way to store the string so we can easily turn it back into an object? We could roll our own format, but it's best to stick with something already known and tested and out there. So let's use JSON. JSON stands for JavaScript Object Notation and it's a text-based human-readable format for representing data structures, commonly for transmission over an HTTP connection. Basically it's AJAX without the X (Object Notation instead of XML).

JSON Example

In the following example, we define a Person object, instantiate it, set its properties, serialize it, store it, retrieve it, and deserialize back into an object.

function Person()






// instantiate a Person

var person = new Person();

person.Name = "Joe Blow";

person.BirthDate = new Date("July 1, 1975 08:30:00");


// serialize the Person object

var strPerson = person.toJSONString();


strPerson =

{"name":"Joe Blow","BirthDate":"1975-07-01T08:30:00"}



// store the serialized Person

Application.userStore.value("mykey") = strPerson;


// retrieve the serialized Person

var s = Application.userStore.value("mykey");


// deserialize from string back into object

var o = s.parseJSON();

Pretty simple!

JSON Source Code

The prototype functions toJSONString() and parseJSON() are provided by an open source JSON parser and stringifier at which can be compressed to less than 2000 characters and placed in the form script.

toJSONString() serializes strings, dates, arrays, booleans, numbers, nested versions of these... pretty much anything. parseJSON() is a more secure rewrite of javascript eval which limits itself to valid JSON notation only.

A Short Aside About Eval

If you're not already aware of how powerful eval is, consider that you can pass in a string and have it interpreted as code. You can say:

eval("var a = 1");

and thereafter have a variable, a, which equals 1. This is incredibly handy, but also a security concern, so you would never eval anything you didn't have complete trust in. You can directly eval a JSON string and magically get your object back, but parseJSON() is safer.

Handling Inmagic Textworks javascript errors

by Peter Tyrrell Tuesday, May 15, 2007 2:40 PM

The scripting environment within Inmagic DB/Textworks (or CS/Textworks) is extremely primitive. Controls you want to interact with have to be declared in an environment separate from the form designer and it's hard to write code longer than 100 lines because there's no tab character or ctrl-a select all, let alone syntax highlighting or intellisense. It's very easy to lose your way if your script does anything beyond "hello world."

The most difficult thing to deal with is that any javascript error encountered does not actually throw an error. Things just progress... until they don't. No error thrown, no feedback, no nothing. It makes debugging a nightmare. What I have done until recently is insert a million-and-one trace statements that write to a trace box over on the side of the form, which at least tells me how far progress went and gives me a clue as to the general area things went wrong.

But I've recently realized I *can* throw (and handle) an error, if I wrap logical blocks of code in try/catch/finally statements. Can't believe it took me so long to cotton on to this. Now I can get detailed info about unanticipated exceptions as well as the anticipated ones. It makes my life better until I can boot up Visual Studio and bask once again in its warm developer-friendly glow.

Play "spot da error":

Yeah, "rs" is an undeclared variable. That's what happens when you refactor manually. Without try/catch this little problem becomes extremely elusive.

UPDATE: The picture has syntax highlighting because I do all scripting in UltraEdit. (Also features code folding, a jump-to-function list, etc.)

Month List