Home page Home page Home page Home page
Pixel Header R1 C1 Pixel
Pixel Header R2 C1 Pixel
Pixel Header R3 C1 Pixel
By apk | Wednesday, 7 March 2018 16:13 | 0 Comments
As we all know, computers are actually pretty dumb.  They can't count past 1.  On the other hand, they're very loyal.  They do exactly what they're told to do.  When you're debugging code, that's great.  Enter in the same set of data, step through the debugger, and it's guaranteed to always work the same way ever time.  Except for when it doesn't.  We've all experienced the frustration of finding something wrong during testing, but no matter what you do, when you step through the debugger, it doesn't happen.

Sure, we usually chalk this up to something with the message queue or interaction with another program that's being interfered with because the debugger now has focus.  But, sometimes, we know we're just fooling ourselves, and we start to wonder if maybe this machine has a mind of it's own.

Recently, we here at Sprezz Towers found ourselves with a machine where the only obvious conclusion was that the system had become sentient.  Before welcoming our new silicon overlords, we decided to give things a second look.  And a third.  Probably a fourth as well.

The problem was reasonably simple.  While attempting to calculate a shipping rate, we were receiving an on-screen message that the shipping rate could not be found.  We expected that because we were testing how the system responded to missing shipping rates.  This had been working for years before the modification we were testing.  And by years, I mean decades.  We don't know when the code was originally written because there's no date in the header, but there's a comment dated June 1993.  Yes, 25 years ago. The most recent comment regarding a change is from 2001.  The code has been recompiled since in the move from ARev to OI, but it's effectively unchanged for 17 years.

The change itself was relatively simple.  We added a set of date ranges to indicate when the shipping rate profile was active. For the overly technical readers, basically, we added three MV fields, HIST_START_DATE, HIST_END_DATE, HIST_ACTIVE.  The system is full of this type of code.  There's a routine that's been in use for 10 years:

validRange = checkDateRange( checkDate, startDates, endDates, activeFlags )

which just returns TRUE$ or FALSE$ indicating if the passed checkDate is inside a valid date range.  This isn't rocket science nor brain surgery.  And it was working fine.  The system displayed the invalid rate message when the date was invalid, and didn't display the message when the date was valid.  That wasn't the problem.  With one specific test case, the system was displaying a failure message we weren't expecting.  The error was related to the customer's configuration, and not the changed code.  It was a valid error, and the correct error was displaying on screen.  However, the wrong error text was being placed into the error log.

Setting a debug break point just before the shipping rate code, we stepped through the code and verified that all the error flags are being set correctly.  And they are.  Everything is working as expected.  Including logging the correct error text.

Going back to our opening premise, computers are dumb.  There are no UI threads or messages interfering here.  The error message bubbles through the system and is returned at the end of the process.  But we're clearly getting different results when stepping through the debugger as opposed to just running the code.  It's time to start thinking critically and logically about this and we start looking over all the code carefully.

When working with systems like this (RevG systems converted to ARev, then to OI), there are times where you feel a bit like you're practicing a programming version of anthropology.  You look at the code and how the style has changed and how variables are named and you can see the evolution of Rev coding styles and standards.  Generally, you can pinpoint about when this code was originally written, just on the use of CASE v IF/THEN statements or how things are capitalized.

As mentioned earlier, this code is old.  Even though the earliest comment date is 1993, we know the code is much older by the style and function.  It's been around since the origin of the system, a RevG application from 1982.  And as RevG code it uses RevG style syntax.  And RevG style calling parameters.  And RevG style error handling.

Ahh..error handling.  I could write a whole new post on inconsistencies in error handling, and whether FALSE$ means success or failure as we move from system to system (and programming epochs).  But in this case, it wasn't how the status was returned.  It was how the status was checked.  Most of us probably forget now, because OpenInsight (in it's modern form) is 25 years old, but in the ARev days, we didn't have get_status() and set_status().  We had status().  And we had...well, that was pretty much it.  There was @FILE.ERROR, but that always seemed too embedded with LH and the filing system to piggy-back on for your own use.

This code used status().  And it used get_status() and set_status() as well.  Needless to say, it was a complicated mess.  But, status() was the key and the source of our error.

It turns out, that when stepping through the debugger, when you return from a subroutine or function call, the contents of status() is cleared.  During normal execution, the system found a value in status(), and jumped into the error routine related to a failed shipping rate call.  However, stepping through the debugger, status()was set to 0, and the system continued on.  Here it checked get_status() for additional errors, and we received the warning about the mis-configured client.

The OI programming documentation says

Be aware, however, that between the time you set the value of Status() and next check it, some other procedure might have set its own value.

This is not related to the Get_Status and Set_Status functions.

While we expect this when calling multiple functions and routines, we didn't expect it to be cleared by the debugger when popping back on the return stack.

The lesson to be learned here is just because your old ARev code recompiles in OI, doesn't mean it's still working.  ARev is ARev and OI is OI, and while they might be very similar and compatible, they're not the same thing.  Something to keep in mind for those hoping to just ARev/32 their way into OpenInsight.  It's not all just cut and paste.
By Sprezz | Thursday, 16 November 2017 17:52 | 0 Comments
Sometimes it doesn't matter how esoteric your knowledge of the internals of the product are - the only way to get to the bottom of an obscure mystery can just be Elbow Grease.

Recently we were contacted by a client with a predicament. He was (finally) converting his client's Rev G system to OpenInsight and he'd run into a snag. Every time he quick painted a form to deal with a specific table, the form was created with no problem. But the moment he reopened the form and tried to look at the properties of specific controls, the controls were no longer data-bound. And to add insult to injury, the columns they had been associated with no longer appeared in the dropdown of selectable columns ; they were still in the dictionary, but not selectable from within the form designer dialog.

Our first thought was that the column names might have retained their Rev G periods. But that wasn't the case. "OK", we queried, "are they in %FIELDS%?". Predictably they were. And anticipating this question the client had already forced a rebuild by clearing the dictionary and copying everything back in.

"Can you check the SYSREPOSWINEXE? Are the columns showing there?". At this point the client indicated that the rows seemed to be corrupted and that the columns weren't showing there. So we suggested REPOSITORY DELETE the EXE and recompiling.

Still no joy.

"OK - check SYSREPOSWINS, SYSREPOSWINEXES and SYSOBJ for GFEs". None. So we decided to try and establish the root cause. Essentially if the design process is removing the column from the control, it's an indicator that the designer hasn't found the column in the dictionary. But we have established that it IS there, so let's start an LH log and see why the read is failing.

Shortly thereafter armed with an LH log, we took a good look at the relevant section and quickly established that the designer was using a TEMP table, not the actual table. Without bothering to test further we simply instructed the client to stop using a TEMP table, as this was likely the cause. The client remonstrated that they WEREN'T using a TEMP table, so at this point we asked for the dictionary and SYSREPOSWIN row to test for ourselves. We ran with the actual table and to our surprise, the LH log showed that regardless of what we told the form designer, a temp table was created and populated with all of the dictionary items from the actual table. And to make matters worse, the columns that wouldn't show up were present both in the temp table AND in the %FIELDS% of the temp table.

Employing Occam's Razor, we then quick painted a form with just two controls, the key prompt and one of the disappearing columns. It quick painted fine BUT the moment we tried to modify the disappearing column's control properties, it was unbound from the data table. All we could gather from that, was that the initial quick paint uses a different column list than the form designer column selection dialog.

Working on the hunch that something in the form read process was removing the column, we then copied all but the two columns needed by our test form into a separate dictionary, and developed a program to copy in a dictionary item, REPOSITORY ACCESS the form, REPOSITORY COMPILE the form, then ACCESS it again to see at what point the column was blanked down. (There were over 700 dictionary items so doing this manually would have been too tedious). To our consternation the column was never blanked down, BUT the moment we entered the form designer it was immediately removed.

At this point all fingers were pointing to the form designer as the culprit, so we had to take a peek inside to see what it was up to. In the absence of source code, the only way to do this was to run an oeprofile.log and dissect that.

The profile log showed that during the loading process, the form designer called DICT_MFS_BUILD, which in turn called COMPILE.PROTECT for a number of dictionary items that was less than the total dictionary items in the table. So in another wild goose chase, we wrote a program to emulate this behaviour and see which dictionary items were failing to compile. Naturally this failed to produce the results we needed.

At this point we were pulling our hair out with frustration, so we just populated the dictionary with only the columns needed for the original data entry form the client had provided. The form worked and the columns remained intact in the controls. So we copied in the rest of the dictionary items and again the columns were removed from the errant controls. It was time to abandon abstruse investigative techniques and just go back to plain old gumshoeing.

It was obvious that at least ONE of the columns in the dictionary was causing the issue but which one? The only way to investigate would be to copy the dictionary items in one by one, go into the form designer, check if the control had had the column removed and if so the last dictionary item copied in was our culprit. The idea of doing this for over 700 columns frankly sucked. Enter our old friend - 'binary chop'.

We wrote a program that selected the temporary dictionary in sorted order , and then copied in the first 360 or so columns. We went into the form designer and sure enough, the affected controls had their columns removed. So we modified the program to do the first 180. Same problem. First 90. Same problem. First 45. The controls kept their columns. First 72. Same problem. First 58. The controls kept their columns. First 65. Same problem. First 61. The controls kept their columns. First 63. Same Problem. First 62. The controls kept their columns.

Ladies and Gentlemen we have a winner! Dictionary item 63 looks to be the culprit. But one final check. We copied in ALL dictionary items apart from that one and the form remained intact. It was the sole dictionary item responsible. We called the client and asked them to confirm. Delightedly they did...

Finally it was time to see WHY this dictionary item was such bad news. Opening it in the table builder showed no obvious reason, but reading it then dropping to the debugger so it could be examined properly gave the game away. There was object code on attribute 20. It was still a Rev G format dictionary item and for reasons best known to C++ this confused the form designer.

Armed with this knowledge we could easily inspect the table and others for dictionary items with code on attribute 20 - and to save ourselves the hassle of writing a program we just used a simple RLIST statement


Note that we could have opted to create a new dict item in SYSDICT pointing to column 20 and  query on that but as the AVERY_LABELS table already had a dictionary item pointing at column 20 we used that instead in combination with the RLIST "USING AltDict" syntax.

Now if only we'd gone down the simple route at the beginning. Still it's hard to beat the adrenaline boost you get when you finally get there!

By Sprezz | Friday, 20 May 2016 16:00 | 0 Comments
In what has been one of the most exciting announcements since the trailers for OI 10, Revelation Software have just released UD 4.7.2 and Whilst the small incremental release number might make this seem insignificant it actually marks one of the biggest changes in linear hash since the Universal Driver was released.

For some time now we have been aware of issues with "enterprise" sites where under certain ill-defined circumstances, the network would crawl to a halt and frustrated users would sit helpless until the system eventually recovered. Under certain extreme conditions the system would never recover and the only solution would be to reboot the server with possible ensuing data corruption. After such halts linear hash files would be seen to have "exploded". Growing in size from tens of megabytes to tens of gigabytes.

The suspicion has long been that some form of alpha corruption led to a massive resizing exercise and that this in turn led to the network slowdown.

With the help of a large UK client Revelation staff have finally been able to track this error down and to finally fix it! And while they were under the hood they've made a whole slew of other changes that make fine tuning an enterprise system so much easier!

VSS has been made more reliable.

Resizing has been made programmatically controllable. So a site that experiences peak transaction volumes at specific times can now tell the UD not to do any resizing until it is appropriate to do so. The underlying filing system naturally copes well with this and when the resizing is re-enabled  it can catch up with the necessary tasks.

Size-locking has been revisited and fixed. We have an unpublished blog article about how size-locking was broken in later releases of OI - which made it very difficult to control whether files expanded/contracted or not. This has now been fixed and even better enhanced so that it works with the hidden volume/share feature of the UD so the client no longer needs physical access to the file to set the size-lock.

The UD can now reliably be shut down even if clients are not responding. This fixes an issue where the UD would refuse to close and the server would have to be rebooted to force closure.

A new registry flag has been added called CreateFileFlags. The service expects that, if this registry entry exists, it has a DWORD value. If it’s not set, its default value is the value associated with:


So the developer can now ensure that writes are passed straight through to the disk and not cached. See the Microsoft documentation here.
Not forgetting the fact that the UD now supports encryption AND reestablishing dropped connections!

All of us at Sprezzatura salute Revelation for the mammoth efforts they invested into putting this right - along with grateful thanks to the UK client who made this possible.
By Sprezz | Tuesday, 3 May 2016 10:10 | 0 Comments
At the recent conference in Orlando I was given the opportunity to present a very early preview of the sample application that Sprezzatura will be providing for the final release of OpenInsight 10. To make the application simpler for new users to follow and understand how MV can be used to improve on SQL data structures the decision was made to convert an open source SQL bug tracking system (Bugzilla) to OpenInsight 10.

This article represents a distillation of the conference presentation without the rambling asides and with a little more depth given to some of the tools. If you were at the presentation then thank you for being there - but this isn't a PowerPoint of my talk! As you'll know the talk was just a live dem. (And we didn't hit the debugger once!).

To make the conversion easier pre-conference the decision was made to develop the application in 9.4 and then move it over. To keep this blog post focused I won't include the screen shots of the app that were demonstrated at conference but suffice to say that the data tables were populated with a small sample data set (500 clients, 8 products, 5000 bugs, 1-4 incidents per bug) and supporting windows were constructed to allow viewing of these.

An interesting thing to come out of the work undertaken during the conversion was to see just how tight OpenInsight security has been made. At one stage I found myself unable to log into my system to continue working as the system told me that my passwords were wrong. I was slightly taken aback by this as I was fairly sure that I'd remembered them correctly but rather than waste time asserting that I was in the right I decided to cheat. I installed a new copy of the pre-Alpha in a different subdirectory, logged in using the default passwords and set up my accounts and users again. Then I made a note of the system tables used to store the user details and copied those corresponding DOS LK and OV files over to my compromised system.

I was still unable to log in.

I queried this with Revelation and all was revealed. To stop this sort of backdoor entry from happening, passwords are encrypted using a salt value that is NOT stored with the password.This is a significant improvement over previous behaviour. I still remember being at a PC Trade Show with Release C of Revelation when an attendee came up and suggested to me that he could easily break into our password protected system. I scoffed. He TYPEd the ROS file containing all the system details and logged straight in. It's nice to see this sort of security hole well and truly closed!

Back to the product!

The first thing that strikes you about the product is how simplified and clean the interface appears.

As has been explained before - the above window is just an OpenInsight form designed using several of the new translucency features that make UI potentially so much more attractive in 10. Logging in takes you to the launch pad.

Gone are the myriad of tools and differing ways of opening an entity or creating a new one. Now if you want to create a new message, you simply File/New Entity/Message. Whereas if you want to create a new form you have to File/New Entity/Form. Popups on the other hand are created using File/New Entity/Popup... I think you get the idea! The only exceptions to this currently is for entities using the new improved system editor which have their own menu options.

Choosing the File/New Entity launches the Select Entity window from where you can choose the class and type of the entity you wish to create (or in the case of existing entities File/Open Entity). No more do we have to remember the correct tool to use for an entity. Choose the entity and the correct tool launches. (I know this was possible in the Application Manager but you had to know that - it wasn't intuitive). If you know that the entity you want doesn't use the new system editor then just clicking the New or Open folder image will launch the appropriate selection dialog.

The New Entity dialog contains all possible entities

Whereas the Open Entity dialog only shows entities you actually have - you can hardly open something you don't have now can you?!

Message Designer

The message designer has added a few new features which were the subject of a completely separate talk by David Hendershot, so rather than duplicate efforts I simply made reference to the ability of the designer to render simple HTML commands to improve message appearance...

Consistently throughout the product now when a designer is open, a property panel provides access to the properties of the selected control or entity. You'll see here that I've highlighted the icon property and the cursor property. You can change the cursor to be displayed at run time to a standard cursor or to custom ones of your own.

As stated above the HTML selection is limited in the message designer to those tags shown in the image below.


When QuickHelp was introduced we all hoped that this would remove the burden of creating proper HTML help for users. In AREV we were used to delivering a new system to the end user and training their power user in the use of the system so that THEY could document the system in a way that their colleagues could understand. Unfortunately Windows users are used to better help than plain text so QuickHelp never really took off.

OI 10 addresses this issue and makes QuickHelp editable HTML. So if I define a QuickHelp as follows :-

When I run the QuickHelp it remains editable

but if I set it to read-only the edit controls disappear.

Note also that if you're a real code jockey you can edit the HTML directly by clicking the HTML button at the end of the toolbar.

Form Designer

Where to start with the revised form designer? Well immediately it has to be said that so much has changed that the Form Designer was the subject of several sessions at conference, so my presentation simply highlighted some of the areas that I was most impressed by.

One of the most fundamental  internal changes made to the product has been the way it has been redesigned to be much more "object oriented". Entities have been designed to be reflective so the tool set can ask an entity what properties and methods it supports. No more hard coded lists. You may have noticed that with newer releases of the product, newer properties were not reflected in the form designer - you had to set them at run time. This added to the coding burden in a way that was entirely avoidable if the form designer had allowed access to them at design time. The issue was that the Form Designer had one list of properties and the Presentation Server had another. Keeping them in sync was an issue that was neglected.

With OI 10 all of this has changed. The form designer now exposes EVERY property that is settable meaning that less code has to be written at run time. The properties are exposed in the property panel - so selecting a control allows access to the properties associated with that control :-

If you have multiple controls selected, only the properties common to those controls are displayed in the property panel. So consider EDITFIELD properties and BITMAP properties

The BITMAP obviously has more "Appearance" properties. But if you select an EDITFIELD and a BITMAP together the property panel changes to just "Common Properties" and these common properties can be set by a single adjustment.

Worth noting is the improvement of support for images. Selecting the BITMAP control allows access to the bitmap property dialog where properties of the image in this context can be set. Note that some properties are of the image itself so cannot be set via this dialog.

The property panel also provides access to the events associated with a control via the Events tab

The Events Editor dialog is a work in progress but it has a logical flow that is easily understood. Clicking on an event launches the Events Editor. So clicking on the Click event for the BITMAP control displays an "options button".

and clicking that leads to the Events Editor

At first I was confused by this dialog as nothing was showing. But then I noticed the check boxes from which I can select whether I want a quick event or an event script - or both.

Checking the event script check box displays the event editor

and praise be! The event script finally defaults to 1! The amount of grief that the event script defaulting to 0 caused can now finally be avoided!

Checking the quick event check box displays a slightly familiar set of choices

So - if on the double click of the bitmap we decided that we wanted to send an "Options" event to the Clock No edit line we'd do the following...

Firstly select what we want to happen

Then we identify the control we want it to happen to

and finally we identify the event to be sent

So double clicking the bitmap will send an "Options" event to the Clock Number edit line. As for the "Options" event on the edit line - firstly we tell it we wish to execute a repository method against a chosen popup entity

Then we tell it that on return it should populate the current editfield.

So far all well and good - familiar territory. But then a stroke of genius...

How many times have you had to write code to launch a popup and then send a read event to the screen? No more - there's a new "Finalize" section for quick events. What should happen after the quick event has fired? A wrap up quick event as it were.

So with one simple addition creating screens just got a whole lot easier.

There are so many features of the new form designer to get excited about. For now I'll just leave you with a screen shot of some of the  new control types available to us.

An Aside

When I first started using the product I kept looking to the File menu for the "Most Recently Used" menu so I could return rapidly to wherever I was last working. I couldn't find it so queried this with Rev. Suffice to say that sometimes it's easy to miss what's under your nose! The start screen has the MRU embedded within it!

Even better - the open dialog remembers the tool you were working with last and reorders the open dialog to present you with the tool you were lasting with in a style reminiscent of an MRU. See how this open dialog differs from the initial open dialog presented in the article as since then I've worked with messages, quickhelp and forms!

Another nice touch is the tabbed interface showing you all of the entities that you have open allowing quick return to them.


 Remember reflection?

Well now that tools can simply ask what properties a control exposes the debugger has been re-engineered to take advantage of this! So now ALL properties are available for inspection from the debugger. It now shows all nested controls, all their properties, including UDPs and it has improved fonts so you can work in High DPI.

OpenInsight 10 is a landmark release for us developers and personally I can't wait to get developing real world applications with it. I'd actively encourage you to play with the Alpha available for download for Works members from here.

I look forward to interacting with you all on the Beta forum in due course!
By apk | Tuesday, 26 April 2016 15:28 | 0 Comments
One of our largest customers decided to use the Good Friday holiday to handle some server maintenance.  While normally a 24/7 shop, this is one of the few days of the year that not only are they on a skeleton crew, it's a skeleton of a skeleton crew and they generally receive no calls on this day.

After performing and verifying the backups, upgrading the OS with all the relevant patches, the server was rebooted.  A quick check, and the LH service was not running, which seemed a bit odd mostly because it's never failed to start before.  Starting the service immediately displayed an error stating that the service did not start in a timely manner.  While none of us was completely sure what's considered "a timely manner", we were all in agreement that "a timely manner" was not "immediately".

At this point, we thought it's time to examine the Window's event log for some clues.  However, this proved to be a problem because the event viewer wouldn't load.  This did not seem like a good sign, so we rebooted the server, but there were no changes.  Looking deeper into the system, we found that the event viewer service wasn't starting either.  Now we think there's something horribly wrong with the server and something went wrong with the patch installation.  While some people were checking on what was installed and what side-effects there might have been, others looked into why the event viewer wouldn't work.

Eventually, we worked out that the event viewer wouldn't start because the subdirectory storing the log files was read-only.  Once we set those files to read-write, the event viewer service started.  Once the event viewer started, the LH Service also started.

As near as we can work out, the LH Service couldn't update the event log and immediately failed.  This started an interesting discussion with the client.  How would we have coded for this particular error.  Revelation is correct in that the LH Service should halt when an OS feature so basic as event logging is unavailable.  This points to a fundamental error on the server which should be handled immediately.  There isn't a very good way to log the error.  Normally the error would go into the event log files, but the error was that it couldn't write to the event logs.  The LH service managed to avoid the perpetual loop of writing to the event log, generating an error, which writes to the event log, generating another error.

The most interesting thing in all this was that Windows never bothered to inform us of the error, and all (most?) Windows services loaded.  We really have no idea what started and what failed.  Had the LH service not acted correctly, a major production server could have run for weeks in a potentially inoperable state.

By Sprezz | 15:25 | 3 Comments
This is going to be one of those blog posts that will either have you saying "Well d'uh everybody knows that" or "Wow what a neat trick". I know that I fell into the latter camp which is why I'm blogging it.

Aaron and I are working together on a new tool for network administrators and it has been a fun ride. Recently we had cause to have Aaron TeamViewer into my machine to help debug a specific routine. So I watched as he took over and waited for him to fire up the System Editor, open the program, insert a DEBUG, compile and run. This is how I've traditionally done it and of course you have to be really careful to remember to remove the DEBUG before shipping the code to anybody. (Or run your release through a release checker that warns of the DEBUG opcode in object code). Instead he performed the neat trick documented below. When I expressed admiration he was incredulous. "I've been doing it this way since OI 2.0" quoth he.

So allow me to present an illustrated guide to debugging without DEBUG statements.

Firstly open the engine window

and click on the Debugger button. Now give focus back to the System Editor or any active OI screen in a way that causes it to trigger an event. The debugger will be invoked.

Now from within the debugger, from the File Menu choose "Open Stored Procedure" and select the routine you wish to debug

Scroll through the code and select your break point in the usual way by double clicking on a line of code

then click on the Run button or press F5 to continue.

The system will return to "Normal". Now invoke the program you wish to debug (for simplicity I will just illustrate by running from the System Monitor)

et voilà - the program breaks at the nominated break point.

This is so cool - it's slightly faster than inserting a DEBUG and you don't run the risk of forgetting to remove the statement!

By Sprezz | 15:23 | 0 Comments
Of late at Sprezz Towers we've been all about taking apart Linear Hash frame headers to diagnose some, frankly bizarre, issues being experienced by one of our clients. Our utilities were working fine on "old style" Linear Hash files where the maximum frame size was 64K and the maximum file size was 4GB but on the newer UD3+ files (or "type 3" as they're referred to) we just didn't seem to be getting the consistent results we were expecting.

As an example consider this section of code for examining the "Alpha Space Usage" - the total bytes of data stored in the Primary frames :-

  lo_alpha  = file[alphaPtr$, 4]
  hi_alpha  = file[alphaPtrHi$, 4]

  If hiBitSet Then lo_alpha := hi_alpha

  value = lo_alpha
  Gosub Convert
  lo_alpha = value

  hlo_Alpha = Oconv( lo_alpha, "MX")

So this snippet takes the 8 bytes that comprise the Alpha value and converts them into a very large integer.

When the Alpha was a value of 3,349,830,462 the MX conversion returned C7AA5B3E which is indeed correct. The issue arose when the Alpha had increased to 7,644,806,759, then the MX conversion returned an erroneous value and got the hex conversion wrong.

Those of you with knowledge of typed languages can probably see where this is going! As OpenInsight is a 32 bit app, the largest value that can be represented in an unsigned integer is 4,294,967,295, which the 3,349,830,462 is less than - 7,644,806,759 however is over this limit so the MX conversion failed.

Fortunately for us the solution was simple (once we realised that something needed solving. The MX conversion works off an integer, but the HEX conversion works off an ASCII string. So all we had to do was modify our code to use this, and convert the actual string value not the number value as below :-

  lo_alpha  = file[alphaPtr$, 4]
  hi_alpha  = file[alphaPtrHi$, 4]

  If hiBitSet Then lo_alpha := hi_alpha
  hlo_Alpha = Oconv( lo_alpha, "HEX")

  value = lo_alpha
  Gosub Convert
  lo_alpha = value

and all was once again right with the world with the HEX conversion returning 677EAAC701000000.

Finally we were able to report on the corrupted file accurately.

Frame length 1,634,013,184 00 10 65 61
Modulo 2,342,159 0F BD 23 00
Alpha 7,644,806,759 67 7E AA C7 01 00 00 00
Threshold 80
Sizelock 0
Row Count 20,379,590 C6 F7 36 01
Alpha% .00

Header 32 0 0 0 0 0 0 0 0 15 189 35 0 0 16 103 126 170 199 204 0 0 198 247 54 1 101 97 1 0 0 0
Header 20 0 0 0 0 0 0 0 0 F BD 23 0 0 10 67 7E AA C7 CC 0 0 C6 F7 36 1 65 61 1 0 0 0

It should be noted that the code snippet above is not UTF-8 safe. We knew that the data we were working on was purely ANSI and had customised one of our routines accordingly. The square bracket operators, CHAR and SEQ are generally not safe when processing binary data so unless you're 100% sure you're in ANSI mode avoid them. In this case we should have been using GetBinaryValue.
Pixel Footer R1 C1 Pixel