tag:blogger.com,1999:blog-26078842044455478772024-03-13T14:35:07.721+00:00Sprezzatura :: Making Databases HappenMat O'Marahhttp://www.blogger.com/profile/13399126449062272733noreply@blogger.comBlogger145125tag:blogger.com,1999:blog-2607884204445547877.post-77583428480839282602024-03-04T09:27:00.003+00:002024-03-04T09:27:34.511+00:00A Forest Of Logs<p>Since the sad demise of <a href="https://www.revelation.com/knowledge-base/530-creating-openinsight-and-linear-hash-log-files" target="_blank">Revelation's article</a> on the subject, there seems to be no quick reference guide available for the various kinds of log that can be created by OpenInsight to assist in debugging strange occurrences and things that go bump in the night.</p><p>As a service to the Rev community we therefore offer up our guide to all things log related. Speaking of logs, my best friend at school was nicknamed "Beaver". Steven Norwood. Oh the fun we had in maths lessons (this was pre-calculator days so we had to use log books)... Anyway</p><h1>Event Logs</h1><div>These logs are initiated when the "Start Log" button is pressed on the engine. The log file is created under the OpenInsight subdirectory.</div><div><br /></div><h3>Version 9</h3><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGDeDmFaFO-TjnXu8uOJPi5ONhkmkzLA1boaYsa4HfvHQAaK4awX_r3y_uhtnwA0DeV_SJyPe2Yrfp9iw88blCUmvZJ4oxazvfPqmwfTQD8zS6dWZYL3L2GZCMXwqEiTWK1AHys5E8ggO1xi9ZIATTJwv-diCANkqOJ-S2goXERO61JxSQQ_o68sNP8Q/s458/2024-02-24_13-58-13.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="47" data-original-width="458" height="66" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGDeDmFaFO-TjnXu8uOJPi5ONhkmkzLA1boaYsa4HfvHQAaK4awX_r3y_uhtnwA0DeV_SJyPe2Yrfp9iw88blCUmvZJ4oxazvfPqmwfTQD8zS6dWZYL3L2GZCMXwqEiTWK1AHys5E8ggO1xi9ZIATTJwv-diCANkqOJ-S2goXERO61JxSQQ_o68sNP8Q/w640-h66/2024-02-24_13-58-13.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div>The file is named OELOG<i>NNN</i>.LOG and will roll over at 1000. </div><div><br /></div><div>The log will contain every event triggered and all programs run not called from BASIC+ along with the passed parameters. For example</div><div><br /></div><div><div><span style="font-family: courier;">Start OpenEngine log - 2/24/2024 13:55:03</span></div><div><span style="font-family: courier;"><br /></span></div><div><span style="font-family: courier;">******************************************************************************</span></div><div><span style="font-family: courier;">Begin processing time: 2/24/2024 13:55:10</span></div><div><span style="font-family: courier;">RUN REPOSITORY 'WRITE', #1, #2, #3, #4, #5, #6, #7, #8, #9, #10, #11</span></div><div><span style="font-family: courier;"> #1: 'SYSPROG*OIWIN**ZZ_TEST'</span></div><div><span style="font-family: courier;"> #2: '0'</span></div><div><span style="font-family: courier;"> #3: ''</span></div><div><span style="font-family: courier;"> #4: ''</span></div><div><span style="font-family: courier;"> #5: ''</span></div><div><span style="font-family: courier;"> #6: ''</span></div><div><span style="font-family: courier;"> #7: ''</span></div><div><span style="font-family: courier;"> #8: ''</span></div><div><span style="font-family: courier;"> #9: ''</span></div><div><span style="font-family: courier;"> #10: 'ZZ_TEST'</span></div><div><span style="font-family: courier;"> #11: '300þ1þÿZZ_TESTýýWINDOWýý574ý258ý-484ý-311ýUntitled...'</span></div><div><span style="font-family: courier;">Stop processing time: 2/24/2024 13:55:10</span></div><div><span style="font-family: courier;">Execution time: 250 milliseconds.</span></div><div><span style="font-family: courier;">Execution status: successful.</span></div><div><span style="font-family: courier;">******************************************************************************</span></div></div><div><br /></div><div><div><span style="font-family: courier;">******************************************************************************</span></div><div><span style="font-family: courier;">Begin processing time: 2/24/2024 13:55:10</span></div><div><span style="font-family: courier;">RUN RUN_EVENT 'SYSPROG*OIWIN', 'ZZ_TEST.EDITLINE_1', 'EDITFIELD', 'GOTFOCUS*3*SYSPROG*GOTFOCUS..OIWIN*', 'ZZ_TEST.EDITLINE_1'</span></div><div><span style="font-family: courier;">Stop processing time: 2/24/2024 13:55:10</span></div><div><span style="font-family: courier;">Execution time: 46 milliseconds.</span></div><div><span style="font-family: courier;">Execution status: successful.</span></div><div><span style="font-family: courier;">******************************************************************************</span></div></div><div><br /></div><div>The program's parameters are listed individually whereas the parameters for the event are passed in line. It should be noted that the engine log only logs programs that are not called directly from Basic+ so it is not as useful as it might seem for debugging.</div><div><br /></div><h3>Version 10</h3><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhecg4RChaimNEC3H3MrxkwRpv9-kTmlo9MvHvW46uI1qG5kNkdQCOYRETi-ZHLI67wDnhsTJfXiEbKXonNhse8jt2afscSingDOSvvZQaDZsF9FgEjXKpP1WcJXjJbMcNpNvlQBEWakobAhuSNqPsnUJhC3RPPwEmKNbk-YOnNZ3AUHUppdV3P_Hr_9Q/s540/2024-02-24_13-59-28.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="58" data-original-width="540" height="68" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhecg4RChaimNEC3H3MrxkwRpv9-kTmlo9MvHvW46uI1qG5kNkdQCOYRETi-ZHLI67wDnhsTJfXiEbKXonNhse8jt2afscSingDOSvvZQaDZsF9FgEjXKpP1WcJXjJbMcNpNvlQBEWakobAhuSNqPsnUJhC3RPPwEmKNbk-YOnNZ3AUHUppdV3P_Hr_9Q/w640-h68/2024-02-24_13-59-28.png" width="640" /></a></div><br /><div><br /></div><div>The file is named REVENGINE<i>NNN</i>.LOG and will roll over at 1000. </div><div><br /></div><div>The log will contain every event triggered with the passed parameters. For example</div><div><br /></div><div><div>Start RevEngine A log - 2/24/2024 14:09:40</div><div><br /></div><div><span style="font-family: courier;">******************************************************************************</span></div><div><span style="font-family: courier;">Begin processing time: 2/24/2024 14:09:45</span></div><div><span style="font-family: courier;">RUN RUN_EVENT 'SYSPROG*OIWIN','RTI_IDE','WINDOW','ACTIVATED*2*SYSPROG*ACTIVATED.WINDOW.OIWIN*'</span></div><div><span style="font-family: courier;">Stop processing time: 2/24/2024 14:09:45</span></div><div><span style="font-family: courier;">Execution time: 16 milliseconds.</span></div><div><span style="font-family: courier;">Execution status: successful.</span></div><div><span style="font-family: courier;">******************************************************************************</span></div></div><div><br /></div><div>Due to the fact that OpenInsight is now written in OpenInsight, all program calls originate from Basic+ so we no longer see programs being launched. Previously the various tools were external executables that relied upon calls to the engine to execute Basic+ code. These calls could be tracked in the log. Now that the tools are written in OI they don't make calls to the engine to execute code, they just call the code directly.</div><div><br /></div><h1>Profile Logs</h1><div>As the name suggests, these logs record every single program called and returned to, along with granular timings, whilst the logs are active. In OI 9 these logs can only be recorded for the entirety of the OI session. In OI 10 it is possible to toggle them. In both versions the creation of a dummy text file in the OpenInsight subdirectory is required to record the log for the session.</div><div><br /></div><div>Once you have this log it is possible to analyse the information to zoom in on where you may be experiencing speed issues, recursive code <i>et al</i>. </div><div><br /></div><div>NB These logs slow the program speed down exponentially so it is a good idea to remove the dummy text file when it is no longer used (for example after you have started logging).</div><div><br /></div><h3>Version 9</h3><div>To trigger the recording of a log simply create a text file called OEPROFILE.LOG before logging into OpenInsight. The system will create a file called OEPROFILE_<i>MACHINENAME</i>_<i>PROCESSNUMBER</i>.LOG. All timings in the log are in milliseconds - but only to a granularity of 16ms - hence the zeroes in the log.</div><div><br /></div><div>As an example of a log starting OpenInsight here's the first few lines - </div><div><br /></div><div><div><span style="font-family: courier;"><span> </span>LOAD_SYSPROGDBT 0</span></div><div><span><span style="font-family: courier;"><span style="white-space: pre;"> </span>RTP57 16</span></span></div><div><span><span style="font-family: courier;"><span style="white-space: pre;"> <span> </span></span>GETNETWORKTYPE 16</span></span></div><div><span><span style="font-family: courier;"><span style="white-space: pre;"> <span> </span></span>GETNETWORKTYPE 31 15</span></span></div><div><span><span style="font-family: courier;"><span style="white-space: pre;"> <span> </span></span>RTP57A 31</span></span></div><div><span><span style="font-family: courier;"><span style="white-space: pre;"> <span> </span></span>RTP57A 47 16</span></span></div><div><span><span style="font-family: courier;"><span style="white-space: pre;"> <span> </span></span>RTP57A 47</span></span></div><div><span><span style="font-family: courier;"><span style="white-space: pre;"> <span> </span></span>RTP57A 47 0</span></span></div><div><span><span style="font-family: courier;"><span style="white-space: pre;"> <span> </span></span>RTP57A 47</span></span></div><div><span><span style="font-family: courier;"><span style="white-space: pre;"> <span> </span></span>RTP57A 47 0</span></span></div><div><span><span style="font-family: courier;"><span style="white-space: pre;"> </span>RTP57 47 31</span></span></div><div><span><span style="font-family: courier;"><span style="white-space: pre;"> </span>RTP50 47</span></span></div><div><span><span style="font-family: courier;"><span style="white-space: pre;"> </span>RTP50 47 0</span></span></div></div><div><br /></div><div>What this tells us is that the program LOAD_SYSPROGDBT has started, and the first thing it did at tick 16, was to call RTP57, which in turn called GETNETWORKTYPE which took 15 ticks to complete. Some quick calls follow - some too fast to measure, until RTP57 exits 31 ticks after it started.</div><div><br /></div><div>For reference here is another section where RUN_EVENT is referenced.</div><div><br /></div><div><div><span style="font-family: courier;"><span> </span>RUN_EVENT 2044</span></div><div><span><span style="font-family: courier;"><span> <span> </span></span>RTP27 2044</span></span></div><div><span><span style="font-family: courier;"><span> <span> <span> </span></span></span>GETOISTATE 2044</span></span></div><div><span><span style="font-family: courier;"><span> <span> <span> </span></span></span>GETOISTATE 2044 0</span></span></div><div><span><span style="font-family: courier;"><span> <span> <span> </span></span></span>RTP57 2044</span></span></div><div><span><span style="font-family: courier;"><span style="white-space: pre;"><span> </span> <span> <span> </span> </span></span>RTP57A 2044</span></span></div><div><span><span style="font-family: courier;"><span style="white-space: pre;"><span> </span><span> <span> <span> </span></span></span></span>RTP57A 2044 0</span></span></div><div><span><span style="font-family: courier;"><span><span> </span> <span> </span></span>RTP57 2044 0</span></span></div><div><span><span style="font-family: courier;"><span> <span> </span></span>RTP27 2044 0</span></span></div><div><span style="white-space: pre;"><span style="font-family: courier;"> </span></span></div></div><div><br /></div><div>This will become relevant in the Version 10 section.</div><div><br /></div><div>Whilst the log is useful, there are no tools provided for consuming it.</div><div><br /></div><h3>Version 10</h3><div>To trigger the recording of a log simply create a text file called REVPROFILE.LOG before logging into OpenInsight. The system will create a file called REVPROFILE_<i>MACHINENAME</i>_<i>PROCESSNUMBER</i>.LOG. </div><div><br /></div><div>As an example of a log starting OpenInsight here's the first few lines - </div><div><br /></div><div><div><span style="font-family: courier;"><span> </span>LOAD_SYSPROGDBT 27.36</span></div><div><span><span style="font-family: courier;"><span> <span> </span></span>RTP57 32.16</span></span></div><div><span><span style="font-family: courier;"><span> <span> <span> </span></span></span>GETNETWORKTYPE 32.23</span></span></div><div><span><span style="font-family: courier;"><span> <span> <span> </span></span></span>GETNETWORKTYPE 33.95 1.72</span></span></div><div><span><span style="font-family: courier;"><span> <span> <span> </span></span></span>MSWIN_GETUSERNAME 33.99</span></span></div><div><span><span style="font-family: courier;"><span> <span> <span> </span></span></span>MSWIN_GETUSERNAME 34.79 0.79</span></span></div><div><span><span style="font-family: courier;"><span> <span> <span> </span></span></span>MSWIN_GETCURRENTPROCESSID 34.83</span></span></div><div><span><span style="font-family: courier;"><span> <span> <span> </span></span></span>MSWIN_GETCURRENTPROCESSID 34.85 0.02</span></span></div><div><span><span style="font-family: courier;"><span> <span> <span> </span></span></span>RTP57A 34.88</span></span></div><div><span><span style="font-family: courier;"><span><span> </span> <span> <span> </span></span></span>RTP57A 35.58 0.71</span></span></div><div><span><span style="font-family: courier;"><span> <span> <span> </span></span></span>RTP57A 35.61</span></span></div><div><span><span style="font-family: courier;"><span> <span> <span> </span></span></span>RTP57A 35.63 0.01</span></span></div><div><span><span style="font-family: courier;"><span> <span> <span> </span></span></span>RTP57A 35.64</span></span></div><div><span><span style="font-family: courier;"><span> <span> <span> </span></span></span>RTP57A 35.66 0.02</span></span></div><div><span><span style="font-family: courier;"><span> <span> </span></span>RTP57 35.69 3.53</span></span></div><div><span><span style="font-family: courier;"><span> <span> </span></span>RTP50 35.71</span></span></div><div><span><span style="font-family: courier;"><span> <span> </span></span>RTP50 35.73 0.02</span></span></div><div><span><span style="font-family: courier;"><br /></span></span></div><div>The first thing that jumps out is that the timings are now to two decimals places, and they're no longer in ticks, rather they're in 0.01ms. So 1,600 times more granular.</div><div><br /></div><div>The second thing that jumps out is when looking at a RUN_EVENT call -</div><div><br /></div><div><div><span style="font-family: courier;"><span> </span>RUN_EVENT 5153.86 ("SYSTEM", "LOGIN", "1", "SYSPROG", "SYSPROG", <span> </span><span> </span><span> </span><span> </span><span> </span><span> </span>"SYSPROG")</span></div><div><span><span style="font-family: courier;"><span> </span><span> </span>RTP27 5153.87</span></span></div><div><span><span style="font-family: courier;"><span style="white-space: pre;"> <span> </span></span>GETOISTATE 5153.88</span></span></div><div><span><span style="font-family: courier;"><span style="white-space: pre;"> <span> </span></span>GETOISTATE 5153.88 0.00</span></span></div></div><div><br /></div><div><br /></div><div>We are now actually provided with what RUN_EVENT was doing.</div><div><br /></div><div>Version 10 also has an analysis tool for the log files AND provides for manipulating the logging programmatically. Rather than reinvent the wheel we just refer you to <a href="https://revdevx.com/2022/11/09/profile-logging-updates-in-openinsight-10-2/" target="_blank">the source.</a></div><div><br /></div><h1>Linear Hash Logs</h1><div>These logs provide a record of every single file i/o operation performed at the workstation doing the logging. As with profile logging, linear hash logging is initiated by the creation of a specifically named file at the OpenInsight location. Unlike with profile logging, linear hash logging at the client is performed only for the first person to log in after the creation of the trigger table, so there is no performance impact on other users. If you wish to record all file i/o operations for all service users then server logs should be used instead <i>qv</i> but be warned these are very verbose so get very big very quickly.</div><div><br /></div><h3>UD3</h3><h3>Client</h3><div>The trigger file in this case is LH3.LOG.</div><div><br /></div><div>As an example of an LH3.LOG file, here's the first few lines </div><div><span style="white-space: pre;"><br /></span></div><div><span style="font-family: courier; white-space: pre;">SN REVMEDIA OK
SU OK
UL 0 OK
OP REPOSIX 1 OK
OP REVDICT 2 OK
OP REVREPOS 3 OK
LO 3 U47961 OK
UL 3 U47961 OK
LO 3 U47961 OK
SU OK
OP REVMEDIA 0 OK
OP DATAVOL\REVMEDIA 4 OK
OP AREV_DIR\REVMEDIA 5 OK
OP O4WFILES\REVMEDIA 6 OK
RO 0 SYSOBJ*GLOBAL OK
OP REV30000 7 OK</span></div><div><span style="white-space: pre;"><br /></span></div><div>Each line represents a single i/o operation, with the first value being an opcode that determines the subsequent parameters.</div></div><div><br /></div><div>Looking at some of the obvious operations, OP REVMEDIA 0 OK, means open the REVMEDIA file to handle 0. Then RO 0 SYSOBJ*GLOBAL OK, means make a cached read (READO) of the file entry for SYSOBJ*GLOBAL from file handle 0 - the REVMEDIA map. </div><div><br /></div><div>Regretfully there are no system tools to analyse the log files.</div><div><br /></div><h3>Server</h3><div>The trigger file in this case is LH.LOG. </div><div><br /></div><div>As an example of an LH.LOG, here's an exercise for the reader.... </div><div><h2>UD4</h2><h3>Client</h3><div>The trigger file in this case is LH4.LOG.</div><div><br /></div><div>As an example of an LH4.LOG file, here's the first few lines </div></div><div><h3><span style="font-family: courier; font-size: medium; font-weight: 400; white-space: pre;">SN REVMEDIA OK
SU OK
UL 0 OK
OP REPOSIX 1 OK
OP REVDICT 2 OK
OP REVREPOS 3 OK
LO 3 U47961 OK
UL 3 U47961 OK
LO 3 U47961 OK
SU OK
OP REVMEDIA 0 OK
OP DATAVOL\REVMEDIA 4 OK
OP AREV_DIR\REVMEDIA 5 OK
OP O4WFILES\REVMEDIA 6 OK
RO 0 SYSOBJ*GLOBAL OK
OP REV30000 7 OK</span></h3></div><div>Notice the subtle difference from the UD3 log? That's right, there isn't one. </div><div><br /></div><h3>Server</h3><div>The trigger file in this case is LH47SRVC.LOG.</div><div><br /></div><div>As an example of an LH47SRVC.LOG, here's the first few lines, in a smaller font to prevent wrapping - it <i>is</i> verbose</div><div><br /></div><div><div><span style="font-family: courier; font-size: x-small;">Initialize...done.</span></div><div><span style="font-family: courier; font-size: x-small;">Start pending...Running.</span></div><div><span style="font-family: courier; font-size: x-small;">Connect...client 0.</span></div><div><span style="font-family: courier; font-size: x-small;">0:Version Check...done.</span></div><div><span style="font-family: courier; font-size: x-small;">0SRVC Connecting...passed parameter X99999999|0</span></div><div><span style="font-family: courier; font-size: x-small;">Validating...bValid 1, bAuthorized 1</span></div><div><span style="font-family: courier; font-size: x-small;">:Open Session,X99999999,250...session 0.</span></div><div><span style="font-family: courier; font-size: x-small;">0,0,ZZ\ZZ15\REVMEDIA:Open File (resolved to E:\ZZ\ZZ15\REVMEDIAðNf)...file 0.</span></div><div><span style="font-family: courier; font-size: x-small;">0,0:Unlock All...done.</span></div></div><div><br /></div><div>There are some gotchas analysing these files as the first two lines are CRLF delimited and all subsequent are LF delimited, but the verbosity of the text makes understanding what is going on a lot easier.</div><div><br /></div><h3>UD5</h3><div><h3>Client</h3></div><div>The trigger file in this case is REVLH.LOG.</div><div><br /></div><div>As an example of a REVLH.LOG file, here's the first few lines </div><div><br /></div><div><div><span style="font-family: courier;">SN</span></div><div><span style="font-family: courier;"> REVMEDIASU OK</span></div><div><span style="font-family: courier;">UL 0 OK</span></div><div><span style="font-family: courier;">OP REPOSIX 1 OK</span></div><div><span style="font-family: courier;">OP REVDICT 2 OK</span></div><div><span style="font-family: courier;">OP REVREPOS 3 OK</span></div><div><span style="font-family: courier;">LO 3 U50707 OK</span></div><div><span style="font-family: courier;">SU OK</span></div><div><span style="font-family: courier;">OP AREV_DIR\REVMEDIA 4 OK</span></div><div><span style="font-family: courier;">OP LH_DIST\REVMEDIA 5 OK</span></div><div><span style="font-family: courier;">OP O4WFILES\REVMEDIA 6 OK</span></div><div><span style="font-family: courier;">OP REVMEDIA 0 OK</span></div><div><span style="font-family: courier;">OP DATAVOL\REVMEDIA 7 OK</span></div><div><span style="font-family: courier;">OP FAQS\REVMEDIA 8 OK</span></div><div><span style="font-family: courier;">RO 0 SYSOBJ*GLOBAL OK</span></div></div><div><br /></div><div>This time there IS a subtle difference - there's a weird bug where it puts the CRLF after the SN and swallows the OK., Presumably an offset issue in the osbwrite. Also the login semaphore logic is slightly different. Beyond that the log file follows the pattern of the others.</div><div><br /></div><div>Random trivia - logging in and out of 9 generates a 10Kb log file. Doing the same on 10 generates a 168Kb log file. Now that OI is written in OI there's a lot more i/o needed to bootstrap the system.</div><div><br /></div><div>Useful random trivia - you can restrict the operations recorded by creating a file called REVLH.DETAILS containing a comma delimited list of the opcodes you wish to capture. The log will then only contain those opcodes and be correspondingly quicker to generate.</div><div><br /></div><h3>Server</h3><div><div>The trigger file in this case is REVLHSRVC.LOG.</div><div><br /></div></div><div>As an example of a REVLHSRVC.LOG, here's the first few lines, with wrapping left in place.</div><div><span style="font-size: x-small;"><br /></span></div><div><div><span style="font-family: courier; font-size: x-small;">Initialize...done.</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">Start pending...</span></div><div><span style="font-family: courier; font-size: x-small;">VSS: UDVSSWriter Initializing...</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">Running.</span></div><div><span style="font-family: courier;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"> [156699562] initialized</span></div><div><span style="font-family: courier; font-size: x-small;"> [156699562] [156711625] Connect... [156711625] client 0.</span></div><div><span style="font-family: courier; font-size: x-small;"> [156711625] [156711625] 0 [156711625] :Version Check... [156711625] OK; secure channel check (0\0)... [156711625] done.</span></div><div><span style="font-family: courier; font-size: x-small;"> [156711625] [156711625] 0 [156711625] NUL Connecting...passed parameter W99999999|1</span></div><div><span style="font-family: courier; font-size: x-small;"> [156711625] [156711625] Validating...bValid 1, bAuthorized 1</span></div><div><span style="font-family: courier; font-size: x-small;"> [156711625] [156711625] :Open Session [156711625] , [156711625] W [156711625] 9 [156711625] 9 [156711625] 9 [156711625] 9 [156711625] 9 [156711625] 9 [156711625] 9 [156711625] 9 [156711625] ,9 [156711625] ... [156711625] session 0.</span></div><div><span style="font-family: courier; font-size: x-small;"> [156711625] [156711625] 0 [156711625] ,0 [156711625] ,E:\OpenInsight\UD Test\REVMEDIA [156711625] :Open File (resolved to E:\OpenInsight\UD Test\REVMEDIA)... [156711640] file 0.</span></div><div><span style="font-family: courier; font-size: x-small;"> [156711640] [156711640] 0 [156711640] ,0 [156711640] :Unlock All... [156711640] done.</span></div><div><span style="font-family: courier; font-size: x-small;"> [156711640] [156711640] 0 [156711640] ,0 [156711640] ,E:\OpenInsight\UD Test\REPOSIX [156711640] :Open File (resolved to E:\OpenInsight\UD Test\REPOSIX)... [156711640] file 1.</span></div><div><span style="font-family: courier; font-size: x-small;"> [156711640] [156711640] 0 [156711640] ,0 [156711640] ,E:\OpenInsight\UD Test\REVDICT [156711640] :Open File (resolved to E:\OpenInsight\UD Test\REVDICT)... [156711640] file 2.</span></div><div><span style="font-family: courier; font-size: x-small;"> [156711640] [156711640] 0 [156711640] ,0 [156711640] ,E:\OpenInsight\UD Test\REVREPOS [156711640] :Open File (resolved to E:\OpenInsight\UD Test\REVREPOS)... [156711640] file 3.</span></div><div><span style="font-family: courier; font-size: x-small;"> [156711640] [156711640] 0 [156711640] ,0 [156711640] ,E:\OpenInsight\UD Test\REVMEDIA [156711640] :Open File (resolved to E:\OpenInsight\UD Test\REVMEDIA)... [156711640] file 0.</span></div></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div>There are some gotchas analysing these files as all lines are CRLF delimited apart from the VSS line and the Running line which are CR delimited, but the verbosity of the text makes understanding what is going on a lot easier.</div><div><br /></div><h1>Additional Tools</h1><div>A big shout out to Revelation who made us aware of an additional tool allowing you to observe LH Statistics directly from the workstation. Not only that - you can dynamically turn linear hash logging on or off from the tool.</div><div><br /></div><div>To use EXEC RTI_LH_INFO_VIEWER at TCL and the following window displays -</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRoirBGjjyzNGcA73IFgJeEVz2fVnlIK5Ng32sowQMdkOT5WojCvDUuWGWJsIw2-l_6Y_-kr-HUk13RIfYbO0N9uq8d3MFIYtBRnBujymqP4SfK8SZZU2K-kTXnUZra9dJMu5yZ0OIvIkbDzDCIm5A86ljeztvFNUuuvE1GrWM_ewPBXIxHpyvpDDVEQ/s1523/2024-02-27_17-01-50.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="858" data-original-width="1523" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRoirBGjjyzNGcA73IFgJeEVz2fVnlIK5Ng32sowQMdkOT5WojCvDUuWGWJsIw2-l_6Y_-kr-HUk13RIfYbO0N9uq8d3MFIYtBRnBujymqP4SfK8SZZU2K-kTXnUZra9dJMu5yZ0OIvIkbDzDCIm5A86ljeztvFNUuuvE1GrWM_ewPBXIxHpyvpDDVEQ/w640-h360/2024-02-27_17-01-50.png" width="640" /></a></div><br /><div>There is lots of information available to you here so explore at leisure! To start logging simply select "Client" or "Server" from the "Logger" dropdown and then press "Go". To stop logging, select "Stop Logging" from the "Action" dropdown and then press "Go".</div><div><br /></div><div>Finally - log files can get a bit overwhelming so if you want to set a "place marker" in a linear hash log, just read a non-existent row using an easily recognisable dummy row id like "ZZ_STARTS_HERE" then you can search the log for that without wading through lots of extraneous stuff.</div>Sprezzhttp://www.blogger.com/profile/08866141305592910267noreply@blogger.com0tag:blogger.com,1999:blog-2607884204445547877.post-22548623301345532552024-02-07T16:32:00.001+00:002024-02-07T16:32:22.186+00:00NosOpen<p>Recently we were playing with a routine to recurse through directory structures on a nominated disk and attempt to osOpen a specific file at a location - a quick utility to hunt down rogue OpenInsight installations by looking for SYSPROG DBTs. What started off as a vanity project very quickly became a learning exercise about how the system handles OS files behind the scenes.</p><p>The routine was working fine, correctly identifying locations containing OpenInsight but then we tried pointing it at Drive C. Suddenly the routine was finding rogue OpenInsight installations all over the disk, SYSPROG.DBTs were opening like they were a dime a dozen. Rogue installation-a-rama.</p><p>Except they weren't actually there. OsOpen <i>claimed</i> they were there - well it reported that it had successfully opened the file - but on closer inspection there was no file actually there.</p><p>There seemed to be no great mystery about what the apparent rogue installations had in common - they all had humongously long folder paths. Once the path gets beyond a certain length, attempts to open files that aren't there succeed. Rather than keep you in suspense we'll just confirm that this length is a common Windows constant called MAX_PATH - which if you check your msWin_MAX_PATH_Equates insert (yes - there is one) equates to 260 characters.</p><p>We reported this to those good folks at Revelation and further inspection revealed that, yes, there is an issue when opening files whose locations are longer than 260 characters. It was explained that internally the system stores the OS handle in an array of up to 128 values and that these values were predeclared at MAX_PATH plus a bit. </p><p>This interested us, because we never realised that there was a limit of 128 concurrently open OS files in the Rev product line. We'd always assumed that (given that the osOpen file handle is just the name of the file) the system opened and closed the file each time it was written to or read from. That assumption was incorrect as, as explained above, Rev keep an array of OS file handles. They take the osOpen handle, look it up in an array and extract the OS file handle. </p><p>This got us thinking, because we aren't always diligent about osClosing handles. Why had we never seen an issue with over 128 files? So we set about testing our assumptions.</p><p>It transpires that, if the system uses up the 128 handles, it starts to reuse the array slots in a FIFO manner. So if you subsequently try an OS operation on a handle that has been dropped, Rev reopens it and drops another. </p><p>The implication of this (which we tested to be true) is that osOpen is not actually needed for OS operations.</p><p>We don't recommend NOT using it we hasten to add, this was just an academic exercise which could be invalidated at any time. </p><p>As an aside when Rev gets the OS handle it places a lock on the file in question. You can see this if you attempt to access the file from outside of OpenInsight. You'll see a message like this -</p><p><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOU05tVtYXRE180r1ldkpYoBQwwCJbeGm9i7jBJu6loWWtNH937yVLiJlTinheXEbnKJYdX1ghAujzLo8v83fy7GM6T3u0Ew2Wbq5SGXhSfSrsybY8Avm07OVNgrDUp-gy61lswXwtWqEKu09cIRRzRfwwzDPXLOpPQzrKTjKHoKDyNxAjzxayKbdFbg/s449/2024-02-07_15-41-49.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="289" data-original-width="449" height="258" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOU05tVtYXRE180r1ldkpYoBQwwCJbeGm9i7jBJu6loWWtNH937yVLiJlTinheXEbnKJYdX1ghAujzLo8v83fy7GM6T3u0Ew2Wbq5SGXhSfSrsybY8Avm07OVNgrDUp-gy61lswXwtWqEKu09cIRRzRfwwzDPXLOpPQzrKTjKHoKDyNxAjzxayKbdFbg/w400-h258/2024-02-07_15-41-49.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><p>The lock is removed when either you osClose the file or the system does so during its FIFO operation. A good tip from Rev is that, and I quote<br /></p><p>"when logging to a file I like to use</p><p>osOpen myFile to myHandle</p><p>offset = dir(myfile)<1></p><p>oswrite myChunk on myHandle at offset</p><p>osClose myHandle</p><p>This avoids holding the lock, so you can use notepad++ to look at the changes while a process is running.".</p><p></p><p>Anyway you'll be pleased to know that for subsequent releases of OpenInsight the restriction on long path names has been removed - along with the 128 element array limitation. </p>Sprezzhttp://www.blogger.com/profile/08866141305592910267noreply@blogger.com0tag:blogger.com,1999:blog-2607884204445547877.post-54216768435294184362023-10-04T10:00:00.000+01:002023-10-04T10:00:04.410+01:0040 Years to life...<p>Last month marked the 40th anniversary of my having worked with Revelation Software products, so I'm going to indulge myself with a little wander down memory lane.</p><p>Cast your mind back to 1983 - the IBM PC had just been released in all its twin-floppied glory. For personal reasons I had to relocate away from home, and I was determined to find a job with a company car. An advertisement for a new company called IDM (with a logo that was suspiciously close to another Three Letter Acronym company) offered a sales position with a new software product just imported from the US - Revelation C. Their main business was selling Pick on IBM Series/1 and they had taken on Revelation as an afterthought due to the built in Terminal Emulator which allowed you to use your PC as an Adds Regent 100 emulator to any Pick based system. In those days hardware was EXPENSIVE, and a dumb terminal actually cost more to buy than buying Revelation. So, if you happened to have a PC and needed a terminal, buying Revelation was a no-brainer.</p><p>The early days were heady as everybody was scrambling to implement standalone solutions using this new PC and the market flooded with database programs. Companies made inflated claims for their products (I'm looking at you dBase II - you were NEVER relational despite what you claimed at the time) but Rev just powered ahead with a series of well thought out adverts that attracted likeminded developers.</p><p>Revelation D was an incremental development, but Revelation E blew our socks off. The guys from Cosmos came over to the UK to explain this new-fangled technology called "Networking", which Rev E supported. Now applications could scale to departmental level and with the scaling came an increasingly diverse client base. New features were added, and Rev F and Rev G made their way into the world. It was whilst working on a banking system written in Rev G that I got to work with an assistant who'd just graduated from Harvard. I'd complained that I needed a Business Analyst, and I got Jeff Bezos. But that's another story. (Spoiler - we didn't see eye to eye).</p><p>The other database companies started putting out more attractive development environments and Cosmos struggled to keep up, until one of their aspiring Sales People took it upon himself to rewrite Rev and thus was born Advanced Revelation (AREV). Microsoft's SQL Server was flying out of the door as people sought to build larger applications, and the fact that AREV had a <a href="https://techmonitor.ai/technology/revelation_technologies_to_bundle_revelation_with_sql_server_in_uk" target="_blank">SQL Bond</a> that allowed rapid app development, made it a prime candidate for expansion. Business boomed and at one stage Revelation won an award from Microsoft for selling more SQL Server licenses than anybody else that year.</p><p>At the time the company I worked with split its database sales between Revelation and Microsoft SQL Server. As a rule of thumb, we told clients that if they had more than 50,000 rows in their main data table, they should look at SQL over Revelation. How I giggle looking back at that when lots of our clients these days have tables with tens of millions of rows.</p><p>During the next couple of decades as AREV matured, I got to work on some wonderfully varied systems. Seconded to HMRC I wrote some fascinating tax investigation software. There didn't seem to be a Government department who DIDN'T use Revelation, so I spent time at the Lord Chancellor's Office, the Home Office, MAFF, MOD et al. We even NEARLY came first in a Database Development Competition organised by a UK Computer journal. I say "nearly" because at the close of the practical part of the competition, the judges came to our stand and congratulated us on winning. It came as a surprise to both us and them, when a completely different company was announced as the winner. Though in fairness WE weren't taking out monthly full colour adverts in said Computer Journal.</p><p>When Sprezzatura launched in 1989 we started to collect an even more diverse client base, and the publication of REVMEDIA was a delightful 4 years where I got to work with some of the most interesting developers on the planet. I'd sit up until the early hours of the morning repeating experiment after experiment to see what changing Window Common actually did. I'd investigate issues brought up by subscribers and I'd try and work out compiled code structure to make working out what routines did just that little bit easier.</p><p>Another milestone during this time, was our involvement in the very first prosecution under the new Computer Misuse Act. We were occasionally consulting to a marketing company who employed their own in-house consultant. They decided that they no longer needed his services and so they let him go. Several months later their system began to behave strangely. Important data was suddenly meaningless gibberish - it had been encrypted. We were called in to investigate and what we found actually seriously impressed me. Putting together the pieces we established that the erstwhile former employee, knowing his time was limited, had placed an MFS on the main data table that, as it wrote to disk encrypted the data, decrypting it on reads, until the trigger date came when the MFS removed itself from the table and consequently stopped decrypting. We were able to show this to be the case and were called as Expert Witnesses for the upcoming trial at the Old Bailey. Turning up suited and booted we were actually quite disappointed that the gentleman in question pled guilty before the trial started. </p><p>But then talk turned to OpenInsight (OI) and the AREV world went into limbo for a few years. Initial attempts to deliver a Windows product were wildly flawed. Reasoning that middleware was the way forward, Revelation released a Database Engine (oengine.exe) with Linear Hash support and blithely suggested that the established user base go away and learn something like Visual Basic to write their front end in.</p><p>There was rebellion and shortly thereafter OpenInsight 2 was born with the rudiments of what we know and love today. It would be fair to describe it as a little flaky. Revelation invited us to partner with them in competing in an internationally famous Database Challenge. There were hundreds of entrants, but we were quietly confident of our ability to deliver. The challenge was to build a database application to a provided specification over the course of 8 hours. 5 hours in, disaster struck. The Repository became corrupted, and all of our work was lost. Knowing what we do now we could have fixed this, but this was very early days. So, with three hours to go for the challenge we had to start again. Regretfully this meant that we only came in the Top 20. If you ever wondered why the system USED to keep a backup duplicate of the Repository, that is why!</p><p>More years passed and Windows moved to 32 Bit. Once again Revelation was stuck in the mud. The 32 bit replacement was to be a similar rehash to OpenInsight 1 requiring the developer base to acquire Java skills - something many were reluctant to do. But after years of stagnation, Revelation passed into the hands of long term developer, Mike Ruane, who set about delivering a 32 bit version.</p><p>Shortly after commencing his tenure, he delivered on his promises and a fun few weeks were spent flying around the world with Mike and the crew showing the next 32 bit OI to an excited client base.</p><p>Once again, we got to work with great software, and to deliver some great technologies. In one particularly memorable assignment the Sprezz team rocked up on our courier client's premises and in two weeks delivered a fully functional on line booking system that blew the socks off the competition. In another, using S/Web we managed to create web sites processing millions of discrete transactions a day while the big database boys were boasting about their hundreds of thousands.</p><p>And now here we are with a completely rewritten OI, a thing of beauty in my mind and I'm glad I'm here to see it! We still get to work with a diverse group of people around the world, though sadly, some of our long-term colleagues are no longer with us. The core team of Sprezzatura delights me with our complementary skill sets and I can honestly not think of a group of people I'd enjoy working with more.</p><p>Over the past 40 years I have been privileged to work with Rev developers in Albania, Australia, Belgium, Canada, the Caribbean, Czechoslovakia, Denmark, England, Finland, France, Germany, Ghana, Hong Kong, India, Ireland, the Netherlands, New Zealand, Norway, Portugal, Puerto Rico, Saudi Arabia, Scotland, South Africa, Sweden, Switzerland, Turkey, Venezuela, Wales and of course in a large number of States of the good ol’ US of A. I’ve met some wonderful people and some of those have even changed my life in very positive ways outside of computing!</p><p>I count my blessings that 40 years ago I decided to put my money on the Revelation horse. I had no clue what I was doing at the time, but it has served me incredibly well. There aren't many people in IT who can say that they've not had to learn a new product since starting their career :). And it's a testament to both the product and ourselves that we still have clients we started work with back in 1984! We're all a bit older, hopefully a bit wiser, but no less enthusiastic.</p><p>So, in conclusion, if you're reading this, it's likely you're part of the Rev community and it's a pleasure to be in it with you. Here's to the next decade! Cheers!</p>Sprezzhttp://www.blogger.com/profile/08866141305592910267noreply@blogger.com10tag:blogger.com,1999:blog-2607884204445547877.post-40138339796124667832023-09-05T12:57:00.004+01:002023-10-05T15:04:29.984+01:00Snippets - Webviewer Issues<p> On one of our more recent projects, we were required to display a PDF document by double-clicking in an edit table. No real issue, we can use just use SHELLEXEC as documented <a href="https://revdevx.com/2021/07/14/the-saga-of-shellexecute/" target="_blank">here</a> right?</p><p>Wrong.</p><p>The problem with a SHELLEXEC, is that by default, it launches a browser that has an address bar containing the full URL to the document in question, allowing the user to modify the URL and potentially access information they were not privy to. (The users don't have browse rights so there isn't a problem of them browsing to other information, but knowing the fully formed URL they could take intelligent guesses at other potential document names). So, we considered looking at turning the address bar off, but then remembered the new WebView control. A control that allows you to embed the Microsoft WebView2 Edge Browser directly into an OpenInsight form and to interact with it.</p><p>This looked like it was going to be the easiest hack ever. Create a form with just two controls, the WebView control and a close button. Have it accept as a create parameter the document to display, and all is good, yes?</p><p>So we added a quickevent to the form that simply set the URI property of the WebView control, to the value passed in the createParam for the form. </p><p>It ran.</p><p>It did nothing.</p><p>Puzzled we modified the CREATE quickevent to also update the screen caption with the file name we were trying to display. (This ability to stack quickevents rocks!). </p><p>The caption changed to the correct value but still nada.</p><p>Thinking laterally we invoked the system monitor and used the SP command to set the URI of the control to the value we had passed in. </p><p>It displayed.</p><p>Rinse and repeat.</p><p>Chatting to the developers, it seems the issue here is that the WebView control takes a little time to instantiate itself, so it it might not be finished before the CREATE event runs. So we have to wait for the WebView control to be finished and THEN set the URI.</p><p>Sounds like a case for looping, querying status and waiting, yes?</p><p>No.</p><p>The WebView control is asynchronous. So all we have to do is wait for an event that tells us that the WebView control is ready, and THEN set the URI.</p><p>All this took was two quickevents. </p><p>One on the CREATE event, setting a synthetic property to contain the document name</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiel_q-v8EhGPG4YZl8xy4H83IcI5JmtZ0gr3Qk2UYYfMsJ3O1GoE5RkwvwANwxeSgyAzts5BGwBQkwNrFObFaJhktFpnrzCS6CSpqeHaQv_Rx8HHstKYG3Lzy9x0nmm_5iyLl7grBgkA7FyMJ1G2HhoXvHvD5cej3HkpSRuDK5CeEZ3Gq5CU3WLDyzbQ/s616/2023-07-12_17-31-05.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="445" data-original-width="616" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiel_q-v8EhGPG4YZl8xy4H83IcI5JmtZ0gr3Qk2UYYfMsJ3O1GoE5RkwvwANwxeSgyAzts5BGwBQkwNrFObFaJhktFpnrzCS6CSpqeHaQv_Rx8HHstKYG3Lzy9x0nmm_5iyLl7grBgkA7FyMJ1G2HhoXvHvD5cej3HkpSRuDK5CeEZ3Gq5CU3WLDyzbQ/s16000/2023-07-12_17-31-05.png" /></a></div><p></p><p><br /></p><p>and one on the WEBVIEWCREATED event for the WebView control (which is fired when the WebView is fully instantiated) which retrieves the synthetic property and uses it to set the URI property.</p><p><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUIOqc2uE4qxSr6a0TFe49sOwk9PdPDk33DJZcLi1AUG6xViCIJ-YB60KzuKxB7JrYvuEm6euUqOQ2zdCsoiNn-_DzE9bhQb1ZYk-goE_3BYcdqbzF2LI55UwT_uizciI4UqctPnFsUDCnzJfxqnFh7AE4VtdUmRg9Dk-3wfoz63fCEJ6r_Yvu-FY0qw/s616/2023-07-12_17-32-07.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="445" data-original-width="616" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUIOqc2uE4qxSr6a0TFe49sOwk9PdPDk33DJZcLi1AUG6xViCIJ-YB60KzuKxB7JrYvuEm6euUqOQ2zdCsoiNn-_DzE9bhQb1ZYk-goE_3BYcdqbzF2LI55UwT_uizciI4UqctPnFsUDCnzJfxqnFh7AE4VtdUmRg9Dk-3wfoz63fCEJ6r_Yvu-FY0qw/s16000/2023-07-12_17-32-07.png" /></a></div><p></p><p><br /></p><div class="separator" style="clear: both; text-align: center;"><br /></div>The results achieved what the client wanted. A displayed document with no identifying file paths. And no code. Sprezzhttp://www.blogger.com/profile/08866141305592910267noreply@blogger.com2tag:blogger.com,1999:blog-2607884204445547877.post-51867028953520818862023-08-01T15:59:00.002+01:002023-08-01T15:59:39.669+01:00Snippets - Date/Time Selection<p> Occasionally RTI slip out little tools and utilities that they've found useful. If you're very lucky they'll even ship source. One such gem in OI 10 is the OIWIN Date/Time picker - RTI_DATETIME_POPUP to its friends.</p><p>If ever you've wanted to offer your user a way of selecting date or time from a calendar/time control, and you've not been too happy with the datetimepicker OCX and the old POPUP_MONTH dialog seems a little dated, then this is the one for you.</p><p>It really is stunningly simple to use. Just add a quickevent to call a stored procedure and you're sorted.</p><p>For illustrative purposes, here's a sample window -</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggRU1pq6HJkLqw30iDV4NWIlQfd2tCHe0R26LpW9Kd-NjxpneoX2XryuxFkpA6Pthu_cBm-SvedpgFHwNgkU-f-vGTlabFlgcIt_-t7cFAt5LcRBE1pLIC8LDunQrwF13IZ5_9jYSfXLANDV4Uv5Q8gnFBO8xjeApkGyRmK6SgBooJsZVZIWJ7oww_Zw/s228/2023-06-29_18-27-39.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="190" data-original-width="228" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggRU1pq6HJkLqw30iDV4NWIlQfd2tCHe0R26LpW9Kd-NjxpneoX2XryuxFkpA6Pthu_cBm-SvedpgFHwNgkU-f-vGTlabFlgcIt_-t7cFAt5LcRBE1pLIC8LDunQrwF13IZ5_9jYSfXLANDV4Uv5Q8gnFBO8xjeApkGyRmK6SgBooJsZVZIWJ7oww_Zw/s16000/2023-06-29_18-27-39.png" /></a></div><br /><p>The cuebanners reflect the conversion on the edit line. The quickevent for the options on each editline is defined thusly - </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnVl4mKKypozmL6rPs0R3JAtFqok8d0AR1nzEuTKA3nNK9SUZ8mpol_x_IJ73wXPD7HMIKwNZ-Wz6zHm8biYIv2nxhNlAZjbgHwNgf1d2I06ftT4egauVCicmB8IcvQB6loBdtwA4XiA9CoLLsMwTmsDIaEtqSVu38UCc0DTQWMnLT3eLa2N7c3psgJQ/s536/2023-06-29_18-11-06.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="321" data-original-width="536" height="384" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnVl4mKKypozmL6rPs0R3JAtFqok8d0AR1nzEuTKA3nNK9SUZ8mpol_x_IJ73wXPD7HMIKwNZ-Wz6zHm8biYIv2nxhNlAZjbgHwNgf1d2I06ftT4egauVCicmB8IcvQB6loBdtwA4XiA9CoLLsMwTmsDIaEtqSVu38UCc0DTQWMnLT3eLa2N7c3psgJQ/w640-h384/2023-06-29_18-11-06.png" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><p>Once you've chosen the Target you can just accept the defaults other than DEFPROP which should be replaced with INVALUE.</p><p>We only need one options button because we're taking advantage of a newly exposed property - in the property panel under the Behavior section, we're setting ALLOWFOCUS to false and then we can just send an OPTIONS event to @FOCUS.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZIK-jATJaOgght7eEMh9xr7_LFN8WuWUh5AnEgR_eF26Oi3q3g5LB3dVi4Q_wRGZywVn7BhX3rlEHCU1s__i8M03jg7ByOevwU4GIFwm9-ZhAfgKDMAVc4gH7laLMKlLEiFO2xEuPEVAVyVcerEzHZeYkGb0Q-xj1zcKNHoN7Gi441i_gF_P5l1KAXg/s267/2023-06-29_18-05-17.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="170" data-original-width="267" height="254" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZIK-jATJaOgght7eEMh9xr7_LFN8WuWUh5AnEgR_eF26Oi3q3g5LB3dVi4Q_wRGZywVn7BhX3rlEHCU1s__i8M03jg7ByOevwU4GIFwm9-ZhAfgKDMAVc4gH7laLMKlLEiFO2xEuPEVAVyVcerEzHZeYkGb0Q-xj1zcKNHoN7Gi441i_gF_P5l1KAXg/w400-h254/2023-06-29_18-05-17.png" width="400" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgymTSbmxgJ7lVkAYi4uerBDUprYc9Gfijoo6MBhb6CY4hIpgNYLY66pHpDTEPLpsE3RpKHRqIDr86ezXU85KXnle1yxIme80VVbTJ6E2hrmw4lDmH6SBuKeBOGlIIgwqDPZ7AUSeSiV2SEfdAgnm86HOQKEvGgtRbt5tziT--dY4RBZEEH43YSnCdmJw/s615/2023-06-29_18-07-29.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="250" data-original-width="615" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgymTSbmxgJ7lVkAYi4uerBDUprYc9Gfijoo6MBhb6CY4hIpgNYLY66pHpDTEPLpsE3RpKHRqIDr86ezXU85KXnle1yxIme80VVbTJ6E2hrmw4lDmH6SBuKeBOGlIIgwqDPZ7AUSeSiV2SEfdAgnm86HOQKEvGgtRbt5tziT--dY4RBZEEH43YSnCdmJw/s16000/2023-06-29_18-07-29.png" /></a></div><br /><p>So how does the routine behave? See the following screen shots -</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnUNojf3XkfPDheu5jNuHBfWPsU-Bv4jdhEMhqWFRYWVPlnpLniw-0BDuijzS2fPJxjIdoJshXDr7lSOaeACCjGEQOWHFb9XTjHyLE_eUCHy_yOC8rQUKxh7u3zhE-rRZ-RgSy4xLrZ4SmB1feUoXkD2tUWGtJ4fcRnM_kSMYjjjqDpfTqMWfEundPuw/s338/2023-06-29_18-28-56.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="230" data-original-width="338" height="218" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnUNojf3XkfPDheu5jNuHBfWPsU-Bv4jdhEMhqWFRYWVPlnpLniw-0BDuijzS2fPJxjIdoJshXDr7lSOaeACCjGEQOWHFb9XTjHyLE_eUCHy_yOC8rQUKxh7u3zhE-rRZ-RgSy4xLrZ4SmB1feUoXkD2tUWGtJ4fcRnM_kSMYjjjqDpfTqMWfEundPuw/s320/2023-06-29_18-28-56.png" width="320" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXY37WGuASQZgWwEZUwvotBNIsEidzel9auN5vPvdp5YM75Z_rjgdvx24ZfS6mOugfYdpBAkuaRwfGb8hjz_A0m2VQpjeIsSNwZzCs5pObEPhU4P7gzmJfWDqR_cfGIyn3SrG_JBxfAU_3z57VWkjRHBPb-cDeSA-s5AU3ww9wrYyvQdRvUbyjRSTsfg/s339/2023-06-29_18-29-30.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="304" data-original-width="339" height="287" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXY37WGuASQZgWwEZUwvotBNIsEidzel9auN5vPvdp5YM75Z_rjgdvx24ZfS6mOugfYdpBAkuaRwfGb8hjz_A0m2VQpjeIsSNwZzCs5pObEPhU4P7gzmJfWDqR_cfGIyn3SrG_JBxfAU_3z57VWkjRHBPb-cDeSA-s5AU3ww9wrYyvQdRvUbyjRSTsfg/s320/2023-06-29_18-29-30.png" width="320" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRnbipdUeqYzZN-dch6ni9zwCsRo86m9d5jD-kCTN0tV6I9ZfT3jrG2FT2AumDc7w9tQDkC-825S-btBEACh35S-lfRj27sUQh7dXwbXzB0RKpLGWyJT2jddu260GfK_pXOsYOIW2H4-QHjg-r5lK5aYvNDh68j9i7CeHCpPGEIT7gd7gtcSDUKtznOA/s337/2023-06-29_18-30-16.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="328" data-original-width="337" height="311" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRnbipdUeqYzZN-dch6ni9zwCsRo86m9d5jD-kCTN0tV6I9ZfT3jrG2FT2AumDc7w9tQDkC-825S-btBEACh35S-lfRj27sUQh7dXwbXzB0RKpLGWyJT2jddu260GfK_pXOsYOIW2H4-QHjg-r5lK5aYvNDh68j9i7CeHCpPGEIT7gd7gtcSDUKtznOA/s320/2023-06-29_18-30-16.png" width="320" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnm1EyYruX_WIHZEdo_4GFvW1J0KquUR27TEsb_AljRYmO3sF3LoV5Y_BAhxT5yiWnGs7KZrfrPoLRhcT_6TimfJoQ1oaq1vg76_O25Foi0GQ9gho9B3Q7nP0g82rmdIIbD9a7573WuwtZf--XCGYBcRqwHlDlgUHedb_hwcjAC-aZA3KfmRa2Z1F-eg/s259/2023-06-29_18-30-45.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="210" data-original-width="259" height="210" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnm1EyYruX_WIHZEdo_4GFvW1J0KquUR27TEsb_AljRYmO3sF3LoV5Y_BAhxT5yiWnGs7KZrfrPoLRhcT_6TimfJoQ1oaq1vg76_O25Foi0GQ9gho9B3Q7nP0g82rmdIIbD9a7573WuwtZf--XCGYBcRqwHlDlgUHedb_hwcjAC-aZA3KfmRa2Z1F-eg/s1600/2023-06-29_18-30-45.png" width="259" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYig0FLDCQBsbJUVPBSiOBIIJRS_kJwDRq-nycGhVFbGWOARZ0cex6RJuDGLjuPWy-BzqcmhQUIIGWawCz3R735TWlL67FCDLd5AZ547jHUrWvoSZ4tz7u128NrsENQB_hQ35StMbNYOIS3a5Yxqq8xiOoKX9ZHghFT8TQgzNOFi2S5Qrd3qAvxlhDug/s335/2023-06-29_18-31-13.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="238" data-original-width="335" height="227" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYig0FLDCQBsbJUVPBSiOBIIJRS_kJwDRq-nycGhVFbGWOARZ0cex6RJuDGLjuPWy-BzqcmhQUIIGWawCz3R735TWlL67FCDLd5AZ547jHUrWvoSZ4tz7u128NrsENQB_hQ35StMbNYOIS3a5Yxqq8xiOoKX9ZHghFT8TQgzNOFi2S5Qrd3qAvxlhDug/s320/2023-06-29_18-31-13.png" width="320" /></a></div><br /><p>Now there <i>are </i>a couple of caveats that I need to mention. The first (as you can see) is that DT and DTS provide the same dialog. The second (due to a bug that I leave you to find) is that DTS always returns 1967 as the year. But as you are encouraged to save under a different name and compile your own version it is easily fixed! If you don't want to then it is all fixed with the latest beta.</p><p>The examples given below show what displays when you let the system determine default values. Examining the source reveals that, should you wish to, you may have much more granular control over the behaviour of the control. In this endeavour RTI_POPUP_DATETIME_EQUATES are your friend, but to save you having to look at this, we'll document their use here.</p><p>If you use DIALOG_BOX to launch the RTI_POPUP_DATETIME window, you can pass in an @Fm delimited create parameter having the following values -</p><p><span> <1><span> Mode, D, DT, DTS, MT, MTS<br /></span></span><span> <2><span> Initial date to use in internal format<br /></span></span><span> <3><span> Initial time to use in internal format<br /></span></span><span> <4><span> Parent<br /></span></span><span> <5><span> Horizontal alignment against owner (L or R)<br /></span></span><span> <6><span> Value mark delimited array containing the screen size of the owner<br /><span> <7><span> First year in the year dropdown<br /></span></span><span> <8><span> Last year in the year dropdown</span></span></span></span></p><p><span>We can override date ranges, set default values and even alter dialog positioning by passing in the correct values.</span></p>Sprezzhttp://www.blogger.com/profile/08866141305592910267noreply@blogger.com0tag:blogger.com,1999:blog-2607884204445547877.post-15721798857158883652023-07-11T12:17:00.001+01:002023-08-01T16:05:45.299+01:00Snippets - TCL Commands<br /><p>One of the biggest differences between OI TCL and AREV TCL is that the latter made use of the VOC file to allow the user to customise commands and even to add their own commands. This does not seem to be the case in OI, rather a cursory examination of the object code for RTI_IDE_TCL suggests that the command list is hard coded. </p><p>With this in mind it might be useful to document exactly what commands are supported, and where unclear, what they actually do. For the purposes of this article it will be assumed that the reader is familiar with the syntax of AREV TCL commands. When optional variables are nominated they will normally be in the order TABLE ROW(S) OPTIONS.</p><p>So in alphabetical order, the commands are as follows - </p><table><tbody style="background-color: #d6eeee;"><tr><th>Command</th><th>Description</th></tr><tr><td>.L</td><td>Display a popup of previously executed commands.</td></tr><tr><td>.<i>n</i></td><td>Copy the <i>n</i>th command to the command line.</td></tr><tr><td>ASSISTANT</td><td>Launch the Assistant popup.</td></tr><tr><td>ATTACH<br />ATTACH_TABLE<br />ATTACHTABLE</td><td>Attaches a table.</td></tr><tr><td>CLEAR<br />CLEARSELECT<br />CLEAR-LIST</td><td>Clears the active select list. Optionally if a name is specified, deletes that list.</td></tr><tr><td>CLEARFILE<br />CLEAR_FILE<br />CLEARTABLE<br />CLEAR_TABLE</td><td>Clears the nominated table.</td></tr><tr><td>COPY<br />COPY_ROW<br />COPYROW</td><td>Copies rows from one place to another. Can use an active select list.</td></tr><tr><td>COPYTABLE<br />COPY_TABLE</td><td>Launch the CopyTable dialog ignoring any command line parameters.</td></tr><tr><td>COUNT<br />COUNTROWS</td><td>Counts the rows in the nominated table with optional selection criteria</td></tr><tr><td>DELETE<br />DELETE_ROW<br />DELETEROW</td><td>Deletes the nominated rows from the nominated table, or uses an active select list against the nominated table, or launches a dialog.</td></tr><tr><td>DELETELIST<br />DELETE-LIST</td><td>Deletes the nominated list.</td></tr><tr><td>DICT</td><td>Either launches the new table dialog or if a table name is specified, opens the dictionary of that table in the IDE.</td></tr><tr><td>EDIT</td><td>Launches the appropriate tool to edit programs or record depending on the nominated table. Will accept a list of keys or an active select list. Particularly useful with FIND (<i>q.v.</i>).</td></tr><tr><td>EVAL</td><td>Compiles and runs the statement</td></tr><tr><td>FIND</td><td>Find the nominated string in the nominated table. Produces an active select list.Takes Option (G to produce a grid and (X to produce a list. Useful in conjunction with EDIT.</td></tr><tr><td>GETLIST<br />GET-LIST</td><td>Activates the nominated select list.</td></tr><tr><td>LIST</td><td>Runs the LIST statement.</td></tr><tr><td>LISTBASIC<br />BLIST</td><td>List the nominated program to screen. Only works with SYSPROCS and requires uppercase row id.</td></tr><tr><td>LISTDICT</td><td>Launches the LISTDICT dialog prepopulated with any nominated table.</td></tr><tr><td>LISTFILES<br />LISTTABLES</td><td>Lists the tables.</td></tr><tr><td>LISTINDEX<br />LIST_INDEX</td><td>Lists all indexed tables or the indexes for the nominated table.</td></tr><tr><td>LISTVOLUME<br />LIST_VOLUME</td><td>List the contents of the nominated volume.</td></tr><tr><td>LISTVOLUMES<br />LIST_VOLUMES</td><td>List all volumes.</td></tr><tr><td>MAKEFILE<br />MAKE_TABLE</td><td>Currently not implemented.</td></tr><tr><td>MAKEVOC<br />VOC</td><td>Launches the MAKEVOC dialog.</td></tr><tr><td>NAME_VOLUME<br />NAMEMEDIA<br />NAMEVOL</td><td>Names the volume at the nominated location with the optionally nominated name. In the absence of a name a default date time will be used.</td></tr><tr><td>OFF</td><td>Closes OI.</td></tr><tr><td>PAINT</td><td>Opens the form designer for the nominated window.</td></tr><tr><td>QUERY_TABLE<br />QUERYTABLE</td><td>Allows selection and activation of a saved list from the query table.</td></tr><tr><td>RUN</td><td>Runs the nominated program passing the nominated parameters.</td></tr><tr><td>RUN_REPORT</td><td>Displays the run report selection dialog OR actions the passed report name, list command, file info comma delimited.</td></tr><tr><td>SAVELIST<br />SAVE-LIST</td><td>Saves the active select list under the nominated name.</td></tr><tr><td>SELECT<br />EXPLODE-ON</td><td>Performs the nominated select/explode-on.</td></tr><tr><td>SET_MFS</td><td>Launches the SET_MFS dialog.</td></tr><tr><td>SUM</td><td>Sums the nominated column in the nominated table.</td></tr><tr><td>WHO</td><td>Displays the WHO window.</td></tr></tbody></table><table><tbody style="background-color: #d6eeee;"><tr><th></th><th><br /></th></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr><tr><td></td><td><br /></td></tr></tbody></table>Sprezzhttp://www.blogger.com/profile/08866141305592910267noreply@blogger.com0tag:blogger.com,1999:blog-2607884204445547877.post-42690699677896303052023-06-27T18:42:00.003+01:002023-06-27T18:42:55.708+01:00It pays to be pragmatic...<p> Recently we were stumped by a compilation error when using pipes to create a multi line statement, this sort of thing,</p><p><span style="font-family: courier;"><span> </span>if value then</span></p><p><span style="font-family: courier;"><span> </span><span> </span>on inlist("ALPHA,BRAVO,CHARLIE", value, ",") goSub |</span></p><p><span style="font-family: courier;"><span><span> </span><span> </span> doAlpha, |</span><br /></span></p><p><span style="font-family: courier;"><span><span> </span><span> </span> doBravo, |</span><br /></span></p><p><span style="font-family: courier;"><span><span> </span><span> </span> doCharlie</span><br /></span></p><p><span style="font-family: courier;"><span><span> </span>end</span><br /></span></p><p>the compiler just kept complaining about an unmatched then/end else. We thought that the only way to get to the bottom of this was to look at what the precompiler produced to see where the error was. Struggling we tried to recall the syntax of the pragma to save the precompiled output. </p><p>Fortunately a more knowledgeable team member pointed out that using the pipe stripped spaces by design, to allow aesthetic alignments of strings. What this meant was that the compiler was <i>not</i> compiling goSub doAlpha, but rather, goSubdoAlpha.</p><p>The solution, repeating pipes. Using two pipes prevents the spaces being stripped and </p><p><span style="font-family: courier;"><span> </span>if value then</span></p><p><span style="font-family: courier;"> on inlist("ALPHA,BRAVO,CHARLIE", value, ",") goSub ||</span></p><p><span style="font-family: courier;"> doAlpha, |<br /></span></p><p><span style="font-family: courier;"> doBravo, |<br /></span></p><p><span style="font-family: courier;"> doCharlie<br /></span></p><p><span style="font-family: courier;"> end</span></p><p>compiled just fine. </p><p>Anyway it's been 16 years since our article on using pragmas and it's still as relevant as ever, so why not <a href="http://www.sprezzatura.com/library/senl/senl-vol4-4.pdf" target="_blank">check it out</a> and refresh your memory!</p>Sprezzhttp://www.blogger.com/profile/08866141305592910267noreply@blogger.com0tag:blogger.com,1999:blog-2607884204445547877.post-27833207844146134342023-03-01T17:42:00.001+00:002023-03-01T17:42:34.959+00:00FIXLH Explored<p>We recently came across a situation that we have literally never encountered in our decades of working with Linear Hash. Basically a FIXLH operation was interrupted mid process and hi-jinks ensued. The resultant mess took a while to sort out but our findings may prove useful if you ever find yourself in a similar situation.</p><p>This specific issue was encountered on an AREV 3.12 system but the logic for FIXLH remains roughly the same so the information remains applicable.</p><p>Basically, the FIXLH operation was interrupted about 10% of the way through processing (the NTVDM abended). A quick check of the table header revealed that it believed itself to be a clean empty table with no rows. Yet listing the table produced a set of row ids after an initial pause while nothing was apparently happening.</p><p>What had happened was that the table header had been reset to that of an empty table, and the first 10% or so of the primary frames had been blanked. This caused us to investigate the processing undertaken by FIXLH and we can confirm that it is as follows:</p><p><span style="font-family: courier;"><span> </span>Create and/or clear the temporary dumpfix table</span><span style="font-family: courier;"><br /></span></p><p><span style="font-family: courier;"><span> grab frame zero group</span><br /></span></p><p><span style="font-family: courier;"><span><span> write rows in group to temporary dumpfix table</span><br /></span></span></p><p><span style="font-family: courier;"><span><span><span> set frame zero header to that of an empty table</span><br /></span></span></span></p><p><span><span style="font-family: courier;"><span><span> </span>loop</span><br /></span></span></p><p><span><span><span style="font-family: courier;"><span> </span><span> grab next group</span><br /></span></span></span></p><p><span><span><span><span style="font-family: courier;"><span> </span><span> write rows in group to temporary dumpfix table</span><br /></span></span></span></span></p><p><span><span><span><span><span style="font-family: courier;"><span> </span><span> wipe primary frame to null</span></span></span></span></span></span></p><p><span style="font-family: courier;"><span> </span>until no groups left</span></p><p><span><span><span><span><span><span><span style="font-family: courier;"><span> repeat</span><br /></span></span></span></span></span></span></span></p><p><span><span><span style="font-family: courier;"> copy rows in temporary table back to source table</span></span><br /></span></p><p><span>So if the operation is interrupted, some of the data will be in the source table and some will be in the temporary dump fix table. </span></p><p><span>As an additional caveat, note that if the rows in the temporary dump fix table are not stored off elsewhere, they will be lost next time FIXLH is run.</span></p><p><span>Since the advent of the UD we've never had to actually fix a GFE for quite some time, so this was an eye-opening operation!</span></p><p><span>Backups are your friend...</span></p>Sprezzhttp://www.blogger.com/profile/08866141305592910267noreply@blogger.com0tag:blogger.com,1999:blog-2607884204445547877.post-41642933270236798492023-01-31T16:04:00.004+00:002023-01-31T17:15:38.275+00:00Sort of obvious in hindsight<p>Recently at a client site, we encountered an error that was a little more baffling than normal. Under very specific circumstances, RLIST would bail with no results. Eventually, we had a duplicatable test sentence which was basically <br /><br /> SELECT TABLE BY CALC_COL_1 WITH REAL_FIELD_1 = ‘XXX’ AND WITH CALC_COL_2 = ‘YYY’ <br /><br />When we removed the BY clause (CALC_COL_1) our sentence ran to completion. This put the problem squarely on CALC_COL_1, which is where we started debugging. <br /><br />We changed CALC_COL_1 to a simple “@ANS=1” and ran the sentence again. This worked correctly. To prove to ourselves that CALC_COL_1 was the problem, we put back the original code and changed our sentence to <br /><br /> SELECT TABLE BY CALC_COL_1 WITH REAL_FIELD_1 = ‘XXX’ AND WITH CALC_COL_3= ‘ZZZ’ <br /><br />This also worked. <br /><br />Now we’re starting to get a little confused. Modifying CALC_COL_1 solved the problem. Replacing CALC_COL_2 also solved the problem. It has to be some sort of interaction with the calculated columns, because there’s no obvious consistency lining up the errors with the sentence structure. <br /><br />It’s time to break out the profile log and see if something jumps out, and it did. Something appeared off with EXTERNAL.SORT. It seems like it executed a few times, and then everything stopped. We dusted off our copy of PROCMON.EXE<span style="font-size: x-small;"><sup> 1</sup></span> and ran the process again. PROCMON showed that the sort file was being opened, but that it was not being closed. It also showed a lot of file access We’re now convinced this has something to do with sorting in general, and not with the specific field being sorted. <br /><br />After trying well over a dozen different variations on the RLIST sentences, we finally worked out that we needed two things to happen for the error to occur. The first was that we had to have CALC_COL_1 as the sort column. The second was that the WITH clauses needed to return enough keys to force the system into using EXTERNAL.SORT instead of a simple in-memory sort. <br /><br />Normally, when OpenInsight starts behaving very oddly, the culprit is usually a function that’s not clearing set_status() before calling get_status. When that happens, the get_status() call could be returned an error from 10 programs back. We reworked the calculated columns to ensure we clear set_status, and feeling very proud of ourselves, sat back and waited to bask in the glory offered to us by our client. Obviously, the report failed again. <br /><br />Sitting back, we start wondering if maybe there’s a small part of the RLIST code that’s still thinks it’s Advanced Revelation and it’s actually checking the pseudo STATUS() variable. So, we reworked the calculated columns to ensure we clear set_status and status(), and feeling very proud of ourselves, sat back and waited to bask in the glory offered to us by our client. Obviously, the report failed yet again. <br /> <br />Surely there can’t be three ways to set an error condition in OpenInsight? It turns out that there is. We suddenly remembered @FILE.ERROR. So, we rework the calculated columns to ensure we clear set_status and status() and @FILE.ERROR, and feeling very proud of ourselves, sat back and waited to bask in the glory offered to us by our client. And this time there was much rejoicing and basking. <br /><br />With the solution in hand, we set out to find out exactly why this happened and where the system was registering the failure. What we found was the calculated field was doing a lot of file access and would attempt to access records that didn’t exist. This was what was setting @FILE.ERROR. But, we hit a two-fer, as they say. Some of the randomness had to do with the amount of data returned. If enough sort data was returned the system would call EXTERNAL.SORT to sort the data. EXTERNAL.SORT writes to temporary OS files, and the OS file commands use @FILE.ERROR to check for errors. EXTERNAL.SORT would execute an OS operation, check @FILE.ERROR, find the pre-existing error, and abort the process. But, this would only happen if the very last row processed set @FILE.ERROR. Otherwise RTP57 would clear any prior @FILE.ERROR settings, and @FILE.ERROR would be null during the EXTERNAL.SORT call. </p><p></p><p></p><p></p><p>1. PROCMON and other useful tools are available as part of the <a href="https://learn.microsoft.com/en-us/sysinternals/" target="_blank">Sysinternals suite of development tools</a>, which no programmer should be without.<br /></p><p><br /><br /> <br /><br /> <br /></p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2607884204445547877.post-48023438423266939212023-01-12T12:46:00.007+00:002023-01-13T16:59:55.370+00:00Y2K Redux - Indexing Issues With Dates OR 20100 - A Search Oddity<p>Those of you who've been in the industry for a while will remember the smugness with which we treated the Y2K issues the rest of the world were experiencing. It didn't affect us, we stored our dates in internal numerical format. I'm sure we all have favourite anecdotes. Mine was being called into the Press Office of a major Government department to certificate their AREV tracking system. I sat down and gave the system a cursory glance. "Ermmm - it doesn't seem to use dates?". "No, it doesn't". "Well, here's your certificate"... turns out they couldn't get the budget for system tweaks but they could for Y2K compliance. I spent the rest of the day implementing their desired changes.</p><p>Anyway, this week wiped the smile off of our collective faces (if you'd ignored the advice in <a href="https://revelation.com/revweb/KB_Articles/KB0042.htm" target="_blank">KB 42</a> thirty or so years ago - which to be honest you could be forgiven for) with the advent of our very own variant - we'll call it the 20100 bug, although it's not a bug, it's an unfortunate feature.</p><p>Users began reporting that date searches were failing for values after the 10th of January 2023. At first we couldn't see an obvious reason. We built a database containing date values going back to the previous century with five rows per date and indexed it. We wrote a test program and ran it</p><p>RUN ZZ_POP 10/01/2023</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhF5OIFEc-1z1QlvM2ZUtVbtNPNmfrgKe5-3ajVVeGz3rDV0sHkwQlSJBUmwD8sCqhmTSgyeSp9aetDyteM-qq5ewNFl1eSge-TlD-LbncQGKTpvvGZv9_gsc17DUR16iqlc-JsfkBZaKBharUrHywX_3OgmJNxmCKJwhzUWr0p4YdGi2FDMxg2bWI" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="180" data-original-width="148" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEhF5OIFEc-1z1QlvM2ZUtVbtNPNmfrgKe5-3ajVVeGz3rDV0sHkwQlSJBUmwD8sCqhmTSgyeSp9aetDyteM-qq5ewNFl1eSge-TlD-LbncQGKTpvvGZv9_gsc17DUR16iqlc-JsfkBZaKBharUrHywX_3OgmJNxmCKJwhzUWr0p4YdGi2FDMxg2bWI" width="197" /></a></div><br />RUN ZZ_POP 11/01/2023<p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjCJFGj32j0Cdz9yAhnfvp29XI9KSAK_gkTg_G39vitBghe9OtSIL1gx0IY-I4T8XAYeNN-OKVud6WtJOpdqaGxbDmYifGVgRSOswcmMqZ11o5j_TfYuwM1FJOXxgLF25S9RqSqDUw1R1vi20IB8QfFlBxT-0pgb_Yks2VR7-Q7M8cT_b5fUvZVPyI" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="180" data-original-width="148" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEjCJFGj32j0Cdz9yAhnfvp29XI9KSAK_gkTg_G39vitBghe9OtSIL1gx0IY-I4T8XAYeNN-OKVud6WtJOpdqaGxbDmYifGVgRSOswcmMqZ11o5j_TfYuwM1FJOXxgLF25S9RqSqDUw1R1vi20IB8QfFlBxT-0pgb_Yks2VR7-Q7M8cT_b5fUvZVPyI" width="197" /></a></div><p><br /></p>RUN ZZ_POP 12/02/2023<p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEglGSn62KeFVqWnI9TXwgGw4OSLnB4Y3cm7MpJek4271aoJyR4D2q3wluq4YPAlPjypkv5M9ha4RvMcqF7AI1Ii3foIkOy-ZjwHEyCFdHtvS8n8R5nbklacyb2FH-3z8mgz5pVuKJP4e94uKkxCeDFyU2H-YwfCQ6EZy2lQPoTcVEhLAXyPpUbP2JA" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="180" data-original-width="148" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEglGSn62KeFVqWnI9TXwgGw4OSLnB4Y3cm7MpJek4271aoJyR4D2q3wluq4YPAlPjypkv5M9ha4RvMcqF7AI1Ii3foIkOy-ZjwHEyCFdHtvS8n8R5nbklacyb2FH-3z8mgz5pVuKJP4e94uKkxCeDFyU2H-YwfCQ6EZy2lQPoTcVEhLAXyPpUbP2JA" width="197" /></a></div><p><br /></p>But then a throwaway remark from Martyn about pivot dates being discussed in the MV community led to a realisation. What if we used internal dates?<p></p><p>RUN ZZ_POP 20099</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgcci5wMWBceHf7idMGf1WWsMVX7Iw2jC0xjNu1-M3hlRKRMN-AqwQbw1g44Ckk_9r30C4HUqVecBlYB0XVnn1jrxN3UNt34IsmzsqtZuKrThe6f5RjDYkJc3Yw7cZy-mlS0EDnlyVDeVNBFVMRPueMcoO7dPMPAYo-k6xwZ4IUtU1we7HoYhM8sBA" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="180" data-original-width="148" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEgcci5wMWBceHf7idMGf1WWsMVX7Iw2jC0xjNu1-M3hlRKRMN-AqwQbw1g44Ckk_9r30C4HUqVecBlYB0XVnn1jrxN3UNt34IsmzsqtZuKrThe6f5RjDYkJc3Yw7cZy-mlS0EDnlyVDeVNBFVMRPueMcoO7dPMPAYo-k6xwZ4IUtU1we7HoYhM8sBA" width="197" /></a></div><p><br /></p>RUN ZZ_POP 20100<p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEirFFw1KXmDhafLVRWb0VRX8YdEViN5tKsSR5iBE9d8tGdZGfatWtY0MDQrSJeZ8jbfx_-KEMOy5pPgBlfzYnXH_x9MEkhLioj9sFxpXqGxynLO8612ByxD0Y41KwHrQbJ1dFNGzRflBYuAJGLvAmaYWunmA8v4khT15b2nzAvgyAIulnmPqayPMYw" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="180" data-original-width="148" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEirFFw1KXmDhafLVRWb0VRX8YdEViN5tKsSR5iBE9d8tGdZGfatWtY0MDQrSJeZ8jbfx_-KEMOy5pPgBlfzYnXH_x9MEkhLioj9sFxpXqGxynLO8612ByxD0Y41KwHrQbJ1dFNGzRflBYuAJGLvAmaYWunmA8v4khT15b2nzAvgyAIulnmPqayPMYw" width="197" /></a></div><p><br /></p>BINGO!<p></p><p>What we've fallen foul of is discussed in the KB reference earlier. Basically BTREE.EXTRACT takes what it is given and tries to ICONV it to use for the look up. If it can't ICONV it (20099 isn't a viable date) it uses the value passed. If it CAN ICONV it, is uses the ICONVed value. And guess what? 20100 ICONVs to the 2nd of January 2000 as you can see above.</p><p>Of course, this won't be the first time this has happened in the wild - for example looking for the 7th of December 1998 using 11299 would have returned the 1st of December 1999 and so on.</p><p>Note that the same issue will be experienced when using internal date formats with RLIST statements.</p><p>The solution? When calling BTREE.EXTRACT use EXTERNAL values as it will try and ICONV the data before using it.</p><h2 style="text-align: left;">Addendum</h2><p>We've been asked to share the code we used to locate btree.extracts in client systems to enable a manual inspection to determine possible failure points. This is a rough and dirty hack which met our requirements. Feel free to tailor to your own requirements.</p>
<br /><div style="background-color: #fefefe; border: 1px solid rgb(115, 137, 174); color: black; font-family: Consolas, "Courier New", Courier, Verdana, Arial; font-size: 10pt; margin: 0px 10px auto; padding: 10px 20px; white-space: nowrap;"><span style="color: grey; font-family: Courier New, Courier, monospace;">0001 </span><span style="color: blue;">Subroutine</span> zz_find_Btree_Extract<span style="color: purple;">(</span> void <span style="color: purple;">)</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0002 </span><span style="color: green; font-style: italic;">/*<br /></span><span style="color: grey; font-family: Courier New, Courier, monospace;">0003 </span><span style="color: green; font-style: italic;"> Author AMcA<br /></span><span style="color: grey; font-family: Courier New, Courier, monospace;">0004 </span><span style="color: green; font-style: italic;"> Date Jan 2022<br /></span><span style="color: grey; font-family: Courier New, Courier, monospace;">0005 </span><span style="color: green; font-style: italic;"> Purpose Quick hack to help identify system usage of btree.extract<br /></span><span style="color: grey; font-family: Courier New, Courier, monospace;">0006 </span><span style="color: green; font-style: italic;"> Provided as is with no warranty<br /></span><span style="color: grey; font-family: Courier New, Courier, monospace;">0007 </span><span style="color: green; font-style: italic;">*/</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0008 </span> <br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0009 </span> <span style="color: blue;">Gosub</span> initialise<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0010 </span> <span style="color: blue;">Gosub</span> process<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0011 </span> <br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0012 </span><span style="color: blue;">Return</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0013 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0014 </span><span style="font-size: 11pt; font-weight: bold;">initialise:</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0015 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0016 </span> filesToCheck <span style="color: purple;">=</span> <span style="color: teal;">"SYSPROCS,SYSREPOSEVENTS,SYSTABLES"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0017 </span> columnsToCheck <span style="color: purple;">=</span> <span style="color: teal;">",,8"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0018 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0019 </span> loopCtr <span style="color: purple;">=</span> Dcount<span style="color: purple;">(</span>filesToCheck<span style="color: purple;">,</span> <span style="color: teal;">","</span><span style="color: purple;">)</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0020 </span> resultString <span style="color: purple;">=</span> <span style="color: teal;">""</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0021 </span> <br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0022 </span><span style="color: blue;">Return</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0023 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0024 </span><span style="font-size: 11pt; font-weight: bold;">process:</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0025 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0026 </span> <span style="color: blue;">For</span> loopPtr <span style="color: purple;">=</span> <span style="color: maroon;">1</span> <span style="color: blue;">To</span> loopCtr<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0027 </span> file <span style="color: purple;">=</span> <span style="color: blue;">Field</span><span style="color: purple;">(</span> filesToCheck<span style="color: purple;">,</span> <span style="color: teal;">","</span><span style="color: purple;">,</span> loopPtr <span style="color: purple;">)</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0028 </span> column <span style="color: purple;">=</span> <span style="color: blue;">Field</span><span style="color: purple;">(</span> columnsToCheck<span style="color: purple;">,</span> <span style="color: teal;">","</span><span style="color: purple;">,</span> loopPtr <span style="color: purple;">)</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0029 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0030 </span> resultString <span style="color: purple;">:</span><span style="color: purple;">=</span> file <span style="color: purple;">:</span> <span style="color: purple;">\</span>0D0A<span style="color: purple;">\</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0031 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0032 </span> <span style="color: blue;">if</span> file <span style="color: purple;">=</span> <span style="color: teal;">"SYSTABLES"</span> <span style="color: blue;">Then</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0033 </span> starting <span style="color: purple;">=</span> <span style="color: teal;">"%"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0034 </span> <span style="color: blue;">Gosub</span> processSysTables<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0035 </span> <span style="color: blue;">End</span> <span style="color: blue;">Else</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0036 </span> starting <span style="color: purple;">=</span> <span style="color: teal;">"@"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0037 </span> <span style="color: blue;">Gosub</span> processRest<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0038 </span> <span style="color: blue;">End</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0039 </span> <br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0040 </span> resultString <span style="color: purple;">:</span><span style="color: purple;">=</span> <span style="color: purple;">\</span>0D0A0D0A<span style="color: purple;">\</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0041 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0042 </span> <span style="color: blue;">Next</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0043 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0044 </span> <span style="color: blue;">Oswrite</span> resultString <span style="color: blue;">On</span> <span style="color: teal;">"ZZ_BE.TXT"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0045 </span> <span style="color: blue;">Call</span> Set_Property<span style="color: purple;">(</span><span style="color: teal;">"CLIPBOARD"</span><span style="color: purple;">,</span> <span style="color: teal;">"TEXT"</span><span style="color: purple;">,</span> resultString <span style="color: purple;">)</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0046 </span> <br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0047 </span><span style="color: blue;">Return</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0048 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0049 </span><span style="font-size: 11pt; font-weight: bold;">processRest:</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0050 </span> <span style="color: blue;">Open</span> file <span style="color: blue;">To</span> v <span style="color: blue;">Then</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0051 </span> <span style="color: blue;">Gosub</span> processV<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0052 </span> <span style="color: blue;">End</span> <span style="color: blue;">Else</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0053 </span> <span style="color: blue;">Call</span> FSMsg<span style="color: purple;">(</span><span style="color: purple;">)</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0054 </span> <span style="color: blue;">End</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0055 </span><span style="color: blue;">Return</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0056 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0057 </span><span style="font-size: 11pt; font-weight: bold;">processV:</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0058 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0059 </span> <span style="color: blue;">Select</span> v<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0060 </span> eof <span style="color: purple;">=</span> <span style="color: maroon;">0</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0061 </span> <span style="color: blue;">Loop</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0062 </span> <span style="color: blue;">Readnext</span> id <span style="color: blue;">Else</span> eof <span style="color: purple;">=</span> <span style="color: maroon;">1</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0063 </span> <span style="color: blue;">Until</span> eof Do<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0064 </span> <span style="color: blue;">If</span> id<span style="color: purple;">[</span><span style="color: maroon;">1</span><span style="color: purple;">,</span> <span style="color: maroon;">1</span><span style="color: purple;">]</span> <span style="color: purple;">=</span> starting <span style="color: blue;">else</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0065 </span> <span style="color: blue;">Read</span> row <span style="color: blue;">From</span> v<span style="color: purple;">,</span> id <span style="color: blue;">Then</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0066 </span> ptr <span style="color: purple;">=</span> <span style="color: maroon;">1</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0067 </span> <span style="color: blue;">If</span> column <span style="color: blue;">Then</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0068 </span> saveRow <span style="color: purple;">=</span> row<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0069 </span> row <span style="color: purple;">=</span> row<span style="color: purple;"><</span> column <span style="color: purple;">></span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0070 </span> <span style="color: blue;">Convert</span> <span style="color: #8000ff;">@Vm</span> <span style="color: blue;">To</span> <span style="color: #8000ff;">@Fm</span> <span style="color: blue;">In</span> row<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0071 </span> <span style="color: blue;">end</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0072 </span> lenRow <span style="color: purple;">=</span> <span style="color: blue;">Len</span><span style="color: purple;">(</span>row<span style="color: purple;">)</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0073 </span> lineNo <span style="color: purple;">=</span> <span style="color: maroon;">0</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0074 </span> <span style="color: blue;">If</span> lenRow <span style="color: purple;">></span> <span style="color: maroon;">0</span> <span style="color: blue;">then</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0075 </span> <span style="color: blue;">Loop</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0076 </span> nextline <span style="color: purple;">=</span> row<span style="color: purple;">[</span>ptr<span style="color: purple;">,</span> <span style="color: #8000ff;">@Fm</span><span style="color: purple;">]</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0077 </span> ptr <span style="color: purple;">=</span> <span style="color: blue;">Col2</span><span style="color: purple;">(</span><span style="color: purple;">)</span> <span style="color: purple;">+</span> <span style="color: maroon;">1</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0078 </span> lineno <span style="color: purple;">+=</span> <span style="color: maroon;">1</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0079 </span> there <span style="color: purple;">=</span> <span style="color: blue;">IndexC</span><span style="color: purple;">(</span> nextLine<span style="color: purple;">,</span> <span style="color: teal;">"btree.extract("</span><span style="color: purple;">,</span> <span style="color: maroon;">1</span><span style="color: purple;">)</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0080 </span> <span style="color: blue;">If</span> there <span style="color: blue;">Then</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0081 </span> variable <span style="color: purple;">=</span> <span style="color: blue;">Trim</span><span style="color: purple;">(</span> nextLine<span style="color: purple;">[</span> there <span style="color: purple;">+</span> <span style="color: maroon;">14</span><span style="color: purple;">,</span> <span style="color: teal;">","</span><span style="color: purple;">]</span> <span style="color: purple;">)</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0082 </span> <span style="color: blue;">If</span> variable<span style="color: purple;">[</span><span style="color: maroon;">1</span><span style="color: purple;">,</span> <span style="color: maroon;">1</span><span style="color: purple;">]</span> <span style="color: purple;">=</span> <span style="color: teal;">"'"</span> <span style="color: blue;">Or</span> variable<span style="color: purple;">[</span><span style="color: maroon;">1</span><span style="color: purple;">,</span> <span style="color: maroon;">1</span><span style="color: purple;">]</span> <span style="color: purple;">=</span> <span style="color: teal;">'"'</span> <span style="color: blue;">Then</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0083 </span> <span style="color: green; font-style: italic;">// passing literals - check the line</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0084 </span> resultString <span style="color: purple;">:</span><span style="color: purple;">=</span> file <span style="color: purple;">:</span> <span style="color: purple;">\</span>09<span style="color: purple;">\</span> <span style="color: purple;">:</span> id <span style="color: purple;">:</span> <span style="color: purple;">\</span>09<span style="color: purple;">\</span> <span style="color: purple;">:</span> lineNo <span style="color: purple;">:</span> <span style="color: purple;">\</span>09<span style="color: purple;">\</span> <span style="color: purple;">:</span> nextLine <span style="color: purple;">:</span> <span style="color: purple;">\</span>0D0A<span style="color: purple;">\</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0085 </span> <span style="color: blue;">End</span> <span style="color: blue;">else</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0086 </span> <span style="color: green; font-style: italic;">// ok we're now going to work back through the code until we find = for our var</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0087 </span> tempLineNo <span style="color: purple;">=</span> lineNo<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0088 </span> <span style="color: blue;">Loop</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0089 </span> tempLineNo <span style="color: purple;">-=</span> <span style="color: maroon;">1</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0090 </span> line <span style="color: purple;">=</span> row<span style="color: purple;"><</span> tempLineNo <span style="color: purple;">></span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0091 </span> <span style="color: blue;">If</span> <span style="color: blue;">Trimf</span><span style="color: purple;">(</span> line <span style="color: purple;">)</span><span style="color: purple;">[</span><span style="color: maroon;">1</span><span style="color: purple;">,</span> <span style="color: maroon;">1</span><span style="color: purple;">]</span> <span style="color: purple;">=</span> <span style="color: teal;">"*"</span> <span style="color: blue;">Then</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0092 </span> line <span style="color: purple;">=</span> <span style="color: teal;">""</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0093 </span> <span style="color: blue;">End</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0094 </span> <span style="color: blue;">Convert</span> <span style="color: teal;">" "</span> <span style="color: blue;">To</span> <span style="color: teal;">""</span> <span style="color: blue;">In</span> line<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0095 </span> line <span style="color: purple;">=</span> <span style="color: teal;">" "</span> <span style="color: purple;">:</span> line<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0096 </span> <span style="color: blue;">Until</span> <span style="color: blue;">IndexC</span><span style="color: purple;">(</span> line<span style="color: purple;">,</span> <span style="color: teal;">" "</span> <span style="color: purple;">:</span> variable <span style="color: purple;">:</span> <span style="color: teal;">"="</span><span style="color: purple;">,</span> <span style="color: maroon;">1</span><span style="color: purple;">)</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0097 </span> <span style="color: blue;">Until</span> tempLineNo <span style="color: purple;">=</span> <span style="color: maroon;">0</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0098 </span> <span style="color: blue;">Repeat</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0099 </span> <span style="color: blue;">If</span> tempLineNo <span style="color: purple;">=</span> <span style="color: maroon;">0</span> <span style="color: blue;">then</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0100 </span> resultString <span style="color: purple;">:</span><span style="color: purple;">=</span> file <span style="color: purple;">:</span> <span style="color: purple;">\</span>09<span style="color: purple;">\</span> <span style="color: purple;">:</span> id <span style="color: purple;">:</span> <span style="color: purple;">\</span>09<span style="color: purple;">\</span> <span style="color: purple;">:</span> lineNo <span style="color: purple;">:</span> <span style="color: purple;">\</span>09<span style="color: purple;">\</span> <span style="color: purple;">:</span> <span style="color: teal;">"Not found "</span> <span style="color: purple;">:</span> row<span style="color: purple;"><</span> LineNo <span style="color: purple;">></span> <span style="color: purple;">:</span> <span style="color: purple;">\</span>0D0A<span style="color: purple;">\</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0101 </span> <span style="color: blue;">End</span> <span style="color: blue;">else</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0102 </span> resultString <span style="color: purple;">:</span><span style="color: purple;">=</span> file<span style="color: purple;">:</span> <span style="color: purple;">\</span>09<span style="color: purple;">\</span> <span style="color: purple;">:</span> id <span style="color: purple;">:</span> <span style="color: purple;">\</span>09<span style="color: purple;">\</span> <span style="color: purple;">:</span> lineNo <span style="color: purple;">:</span> <span style="color: purple;">\</span>09<span style="color: purple;">\</span> <span style="color: purple;">:</span> row<span style="color: purple;"><</span> tempLineNo <span style="color: purple;">></span> <span style="color: purple;">:</span> <span style="color: purple;">\</span>0D0A<span style="color: purple;">\</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0103 </span> <span style="color: blue;">end</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0104 </span> <span style="color: blue;">end</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0105 </span> <span style="color: blue;">End</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0106 </span> <span style="color: blue;">While</span> ptr <span style="color: purple;"><</span> lenRow<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0107 </span> <br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0108 </span> <span style="color: blue;">Repeat</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0109 </span> <span style="color: blue;">End</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0110 </span> <span style="color: blue;">End</span> <span style="color: blue;">Else</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0111 </span> <span style="color: blue;">end</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0112 </span> <span style="color: blue;">Call</span> send_info<span style="color: purple;">(</span> file <span style="color: purple;">:</span> <span style="color: teal;">" "</span> <span style="color: purple;">:</span> id <span style="color: purple;">)</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0113 </span> <span style="color: blue;">end</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0114 </span> <span style="color: blue;">repeat</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0115 </span><span style="color: blue;">return</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0116 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0117 </span><span style="font-size: 11pt; font-weight: bold;">processSystables:</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0118 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0119 </span> <span style="color: blue;">Open</span> file <span style="color: blue;">To</span> v <span style="color: blue;">Then</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0120 </span> <span style="color: blue;">Select</span> v<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0121 </span> saveV <span style="color: purple;">=</span> v<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0122 </span> eof <span style="color: purple;">=</span> <span style="color: maroon;">0</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0123 </span> dictCtr <span style="color: purple;">=</span> <span style="color: maroon;">0</span> <br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0124 </span> <br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0125 </span> <span style="color: blue;">Loop</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0126 </span> <span style="color: blue;">Readnext</span> id <span style="color: blue;">Else</span> eof <span style="color: purple;">=</span> <span style="color: maroon;">1</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0127 </span> <span style="color: blue;">Until</span> eof Do<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0128 </span> <span style="color: blue;">If</span> ID<span style="color: purple;">[</span><span style="color: maroon;">1</span><span style="color: purple;">,</span> <span style="color: maroon;">5</span><span style="color: purple;">]</span> <span style="color: purple;">=</span> <span style="color: teal;">"DICT."</span> <span style="color: blue;">Then</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0129 </span> <span style="color: blue;">Open</span> id <span style="color: blue;">To</span> v <span style="color: blue;">Then</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0130 </span> <br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0131 </span> file <span style="color: purple;">=</span> id<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0132 </span> <br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0133 </span> <span style="color: blue;">Call</span> push.Select<span style="color: purple;">(</span> v1<span style="color: purple;">,</span> v2<span style="color: purple;">,</span> v3<span style="color: purple;">,</span> v4 <span style="color: purple;">)</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0134 </span> <span style="color: blue;">Gosub</span> processV<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0135 </span> <span style="color: blue;">Call</span> pop.Select<span style="color: purple;">(</span> v1<span style="color: purple;">,</span> v2<span style="color: purple;">,</span> v3<span style="color: purple;">,</span> v4 <span style="color: purple;">)</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0136 </span> eof <span style="color: purple;">=</span> <span style="color: maroon;">0</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0137 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0138 </span> <span style="color: blue;">End</span> <span style="color: blue;">Else</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0139 </span> <span style="color: green; font-style: italic;">* Call FSMsg()</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0140 </span> <span style="color: blue;">End</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0141 </span> v <span style="color: purple;">=</span> saveV<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0142 </span> <span style="color: blue;">end</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0143 </span> <span style="color: blue;">Repeat</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0144 </span> <span style="color: blue;">End</span> <span style="color: blue;">Else</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0145 </span> <span style="color: blue;">Call</span> FSMsg<span style="color: purple;">(</span><span style="color: purple;">)</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0146 </span> <span style="color: blue;">End</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0147 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0148 </span><span style="color: blue;">return</span><br /></div>Sprezzhttp://www.blogger.com/profile/08866141305592910267noreply@blogger.com13tag:blogger.com,1999:blog-2607884204445547877.post-29661957617772042712023-01-04T10:16:00.015+00:002023-01-05T14:26:33.711+00:00Owned - By A Panel<p>Tabbed interfaces provide a much loved way of fitting lots of information onto a single entry form. The introduction of multi page forms and the improved integration of page controlling made this a much easier exercise - each tab could be a page of the form and we could simply move between pages on a tab click. In fact a quick event was added to make this even easier.</p><p>But what has not been possible until now, without a deal of smoke and mirrors, is to have one or more tab controls embedded within a page on a single or multi-page form and have them only appear on a specific page. The only way to accomplish this would be to have a set of controls per tab, all within the tab boundaries, and make them visible or invisible depending on the currently clicked tab. This makes form maintenance incredibly tedious and code overly complex.</p><p>Before OI10 there was no real concept of parent/child relationships in OI - other than that forms and group boxes owned all of the controls within their boundaries. This led to many issues, not least with group boxes and tab controls. With the advent of OI10 this has changed. OI now allows the implementation of, and respects, parent/child relationships.</p><p>The biggest example of this is the introduction of a "Panel" container type.</p><p></p><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhXTgQ9xqp8PTbycCnJT7IxlWamonCiLevl2s-ishyFjq5WpMN5DwaOwpxNkBSF5JhbEXviAwo_q9P1VKsIfo3V2AU0cXO4ie8H0Q-t_7JK3_j4D9yUxFotOBbQ0Tn15LjYRgzhDDRR9y_iCgdAco1TjX1OsW9AiT-Nk0BxJJL3mm1ehCyR-GCQ_8M" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="762" data-original-width="196" src="https://blogger.googleusercontent.com/img/a/AVvXsEhXTgQ9xqp8PTbycCnJT7IxlWamonCiLevl2s-ishyFjq5WpMN5DwaOwpxNkBSF5JhbEXviAwo_q9P1VKsIfo3V2AU0cXO4ie8H0Q-t_7JK3_j4D9yUxFotOBbQ0Tn15LjYRgzhDDRR9y_iCgdAco1TjX1OsW9AiT-Nk0BxJJL3mm1ehCyR-GCQ_8M=s16000" /></a></div><br /><br /></div><br />We are going to use the "Panel" (not the "Simple Panel") to enable tabs within a form. But first, what's the difference between a "Panel" and a Simple Panel?<p></p><p>A Panel is simply a container that can be placed anywhere on the screen so that when controls are pasted into the Panel they become children of the Panel, not of the Window. So move the Panel and the controls owned by the Panel move with it. Don't be too put out by the "Simple" part of the description, pretty much the only difference between a Panel and a Simple Panel has to do with paging. So looking at Simple Panel/Panel properties in the Form Designer we see this :</p><p><br /></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEj_kwZDY8hhcBy3Luf6lcqD2NE0EAoEbno0rPvaM3kExOXZoCghLIDt2QlbsgL0sgZrJKKnwhLCVXc-Pl99If2QNYCfC3qI8AUY4Qa6TKgZh6DIr_yUu-fE7iQf_jrnhW07JiMGpLAAKWCll5i-Q2m3e8NxHsxtQ77vVKzJi58yiB2siM7YuJN5gYA" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="752" data-original-width="176" height="640" src="https://blogger.googleusercontent.com/img/a/AVvXsEj_kwZDY8hhcBy3Luf6lcqD2NE0EAoEbno0rPvaM3kExOXZoCghLIDt2QlbsgL0sgZrJKKnwhLCVXc-Pl99If2QNYCfC3qI8AUY4Qa6TKgZh6DIr_yUu-fE7iQf_jrnhW07JiMGpLAAKWCll5i-Q2m3e8NxHsxtQ77vVKzJi58yiB2siM7YuJN5gYA=w150-h640" width="150" /></a><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgD-AiN-sY-V68tIhwA8LZE7oNU36flumUts8z0F6IMU-RY93X6n3T_bO-kt8eGpakFyXjRT33lTPVAnGhgZCFaSNESOnGylLhZ1in9Pqe-A9naE7i3qgbjbtEKblVgD3YdYMnBdaOsf_JQiMvcf_qsaufNhQHEVKQTQJXOGsLla52O8BfCiPFdsQ4" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="750" data-original-width="179" height="640" src="https://blogger.googleusercontent.com/img/a/AVvXsEgD-AiN-sY-V68tIhwA8LZE7oNU36flumUts8z0F6IMU-RY93X6n3T_bO-kt8eGpakFyXjRT33lTPVAnGhgZCFaSNESOnGylLhZ1in9Pqe-A9naE7i3qgbjbtEKblVgD3YdYMnBdaOsf_JQiMvcf_qsaufNhQHEVKQTQJXOGsLla52O8BfCiPFdsQ4=w152-h640" width="152" /></a><br /><br /></div><div class="separator" style="clear: both; text-align: center;"></div><div style="text-align: center;"><span style="color: #0000ee;"><u><br /></u></span></div>and comparing the two sets of properties we see that the only properties unique to Panels are<p></p><p> PageCount<br /><span> </span>Virtual Size<br /><span> </span>PageSwapRenderMode<br /><span> </span>ScrollMode<br /><span> </span>TabWithinPanel</p><p><span>and the only property unique to Simple Panels is the DummyCaption property.</span></p><p><span>So, to implement a tab within a form page, we can now combine the Tab Control, the Panel Control and one simple Quick Event to achieve the desired results.</span></p><p><span>Let's start with a simple <b>one page </b>entry screen.</span></p><p><span><span></span></span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEilIyHuwdqhtbJkbGK3cY_3YhfYwHo84Ucmi0mtdvtl5DQL2_7cFRQ2YIgEf6MDhV2l979PZ16IgxPNpjUYktc-M9N9e1DkMVsZu6CEookJVae0mkZlQKLNnLSgxu3Oyd2DhL_KEQqRF8GCs3sa2xdRM4dCAmwa92kK5ZV-Ui76S89dJVL7pU-BapU" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="355" data-original-width="333" src="https://blogger.googleusercontent.com/img/a/AVvXsEilIyHuwdqhtbJkbGK3cY_3YhfYwHo84Ucmi0mtdvtl5DQL2_7cFRQ2YIgEf6MDhV2l979PZ16IgxPNpjUYktc-M9N9e1DkMVsZu6CEookJVae0mkZlQKLNnLSgxu3Oyd2DhL_KEQqRF8GCs3sa2xdRM4dCAmwa92kK5ZV-Ui76S89dJVL7pU-BapU=s16000" /></a></div><br />Select "Panel" from the Containers and position it within the tab control - using Right-Click and drag to size it appropriately. (See Addendum for other keystroke combinations). There are no hard and fast rules about this but I tend to leave an 8 pixel border from the tab control to make it easier to edit in the form designer.<p></p><p><span><span></span></span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEggwUKPXOaPu6-cL4cGDVzRKEbp9lqFGeXT0ci7dpt6zd6eiGJsnraCHef0MYCaHS9AQZyX9RzY2wDfVzNTTcR1AGFH-qgJ_9yl7p3BihQSken64y3MkB8vBHnyRXhwd3YkWTu9JJglOf_IxNd8N8aAWfoWjuG6gZKSvhM4izkdC49tR_CNzbP4Kok" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="399" data-original-width="513" src="https://blogger.googleusercontent.com/img/a/AVvXsEggwUKPXOaPu6-cL4cGDVzRKEbp9lqFGeXT0ci7dpt6zd6eiGJsnraCHef0MYCaHS9AQZyX9RzY2wDfVzNTTcR1AGFH-qgJ_9yl7p3BihQSken64y3MkB8vBHnyRXhwd3YkWTu9JJglOf_IxNd8N8aAWfoWjuG6gZKSvhM4izkdC49tR_CNzbP4Kok=s16000" /></a></div><br /><br /><p></p><p><span>(As an aside, if you right-click on the Window you can un-anchor it to allow moving it wherever you want.)</span></p><p>Tell the Panel that it has three pages and label the tab accordingly (after setting the tab to three values) :</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiDPNbfIomlKneU69tNXzqY2UuvJ592k1WhjpjTwMEf_86vZ8VPUT6pjCfchx0CmakefcX-UQPdpprXTltnwCbubYpBFlH8NWuJaeDlJAYryHOT_fpGGWsfKDJyROIUyds7qYTWQhl4-B2rCZz36BiFWgie78Qnhb7nse6s3fEjhvlKb6Cf6_dHdf4" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="334" data-original-width="496" src="https://blogger.googleusercontent.com/img/a/AVvXsEiDPNbfIomlKneU69tNXzqY2UuvJ592k1WhjpjTwMEf_86vZ8VPUT6pjCfchx0CmakefcX-UQPdpprXTltnwCbubYpBFlH8NWuJaeDlJAYryHOT_fpGGWsfKDJyROIUyds7qYTWQhl4-B2rCZz36BiFWgie78Qnhb7nse6s3fEjhvlKb6Cf6_dHdf4=s16000" /></a></div><br /><br /><p></p><p>Select the Panel and add in the controls for the first page.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhjjZrDrIXBSeaxtQ2_LWCvrKPqJSDx-9BXu4YN1KL047CPyh7ZcN1niWAvmmagLRExgVYLHu74N48Y8k7CY0gBhBSUJRAJhFY6zd_xJdptMZtMKRAt7QDKhudWF8RSgAuLMKs-2aNflX5ab9oPgcEuAfAtgH2pBoGbMazx8ajjNsy43gxwXq4niy8" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="404" data-original-width="360" src="https://blogger.googleusercontent.com/img/a/AVvXsEhjjZrDrIXBSeaxtQ2_LWCvrKPqJSDx-9BXu4YN1KL047CPyh7ZcN1niWAvmmagLRExgVYLHu74N48Y8k7CY0gBhBSUJRAJhFY6zd_xJdptMZtMKRAt7QDKhudWF8RSgAuLMKs-2aNflX5ab9oPgcEuAfAtgH2pBoGbMazx8ajjNsy43gxwXq4niy8=s16000" /></a></div><br />Now select the Panel and use the spin control to move to page 2 and add in the controls for the second page. Note that the spin control applies to whichever control is both currently selected and supports paging - namely Windows and Panels. <p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgUJdbd_FWo-9ykVU4g14BNKIJFszgWF4-YxtrM2KRJa6QsBaVnSxFJgOfufRzAVz0_mu2j_Cvnlqd4xaWzJ_2Cp6sM-XIeiQsdWZfknVH4WOMeConLimu3vXvSlDsl3LGmVbiROmPX7jLtDDSeB4WIvIWtyayV0B80LxrTaFiAsNPvLqEaqS1WNtg" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="414" data-original-width="362" src="https://blogger.googleusercontent.com/img/a/AVvXsEgUJdbd_FWo-9ykVU4g14BNKIJFszgWF4-YxtrM2KRJa6QsBaVnSxFJgOfufRzAVz0_mu2j_Cvnlqd4xaWzJ_2Cp6sM-XIeiQsdWZfknVH4WOMeConLimu3vXvSlDsl3LGmVbiROmPX7jLtDDSeB4WIvIWtyayV0B80LxrTaFiAsNPvLqEaqS1WNtg=s16000" /></a></div><br />And finally the third page.<p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEh43Vk2QIRyuJpC3N49sl-9I_4KadmtlfjdlWRefKTQ-U3oC6kKNt2Zg7DtiIoSY3kdgsy_8JSsO0Wcvza0lOJr9pB_AOTSIC08QCYUwavnrqF-QyayRsss5RpDFwDZM4SzJoSHNNIyK0h9vOqIRczezf_EA4go6CnKaAyxbNXG52tiJJJJN6eN5PY" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="406" data-original-width="360" src="https://blogger.googleusercontent.com/img/a/AVvXsEh43Vk2QIRyuJpC3N49sl-9I_4KadmtlfjdlWRefKTQ-U3oC6kKNt2Zg7DtiIoSY3kdgsy_8JSsO0Wcvza0lOJr9pB_AOTSIC08QCYUwavnrqF-QyayRsss5RpDFwDZM4SzJoSHNNIyK0h9vOqIRczezf_EA4go6CnKaAyxbNXG52tiJJJJN6eN5PY=s16000" /></a></div><br />Finally we need to add a Quick Event on the Tab click. This needs to get the VALUE Property of the Tab control, and set the CURRENTPAGE Property of the Panel.<p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiis3aclYTSg1h20NXtN-8oa3wsyoCBJ6FR6H49h-nZHoQYyPq-A7pnFPhSR0STcNtNLbrQNUvFkkY7Z4qrzlt13fQxqMKQf66IKPSWiWbn3oQNizTRUHS40GcwnI7O1L8ymcBQpsSYdv7ycWY-DcZXb0JrdFEQICizFsczth6Ie9bl2CD51A79bLg" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="474" data-original-width="680" src="https://blogger.googleusercontent.com/img/a/AVvXsEiis3aclYTSg1h20NXtN-8oa3wsyoCBJ6FR6H49h-nZHoQYyPq-A7pnFPhSR0STcNtNLbrQNUvFkkY7Z4qrzlt13fQxqMKQf66IKPSWiWbn3oQNizTRUHS40GcwnI7O1L8ymcBQpsSYdv7ycWY-DcZXb0JrdFEQICizFsczth6Ie9bl2CD51A79bLg=s16000" /></a></div><br />and Bob, as they say, is your uncle...<p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjpyVsbPgJqAm77l50lW85BdVg6j2aZsUMz6OY2X7m2Lq4OF95x6Aj_R05s9dF6DmcSaQ1uvknMRkkOoh-5VmQurJFPGPdtOaYX9kAkItNAyGavNVp7D9zEFfdcdC_RNt7PwI8o7VlAb_0Q2IsqsiZFyPI3Tv5cvce8aaZ9ATHEVNQK66q6HkZRG1w" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="355" data-original-width="333" height="200" src="https://blogger.googleusercontent.com/img/a/AVvXsEjpyVsbPgJqAm77l50lW85BdVg6j2aZsUMz6OY2X7m2Lq4OF95x6Aj_R05s9dF6DmcSaQ1uvknMRkkOoh-5VmQurJFPGPdtOaYX9kAkItNAyGavNVp7D9zEFfdcdC_RNt7PwI8o7VlAb_0Q2IsqsiZFyPI3Tv5cvce8aaZ9ATHEVNQK66q6HkZRG1w=w188-h200" width="188" /></a><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjxlOkMeG4FLSqMZhyprE6Udk9Ro9t7FmfUkTQAnKAbIZSHizT2e9zWwQ0kjl9wQbtgRJmPmRKNVIvPDn-0fbfi045JF5a87HobfUCVfD_6WLpIV3rR9mNr_O2a45-MM1zqkxMhXrODLq10oXCU5ssf3OZ5OQsIRPK3NTzHp_jbNV2lFXnC091JwWQ" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="355" data-original-width="333" height="200" src="https://blogger.googleusercontent.com/img/a/AVvXsEjxlOkMeG4FLSqMZhyprE6Udk9Ro9t7FmfUkTQAnKAbIZSHizT2e9zWwQ0kjl9wQbtgRJmPmRKNVIvPDn-0fbfi045JF5a87HobfUCVfD_6WLpIV3rR9mNr_O2a45-MM1zqkxMhXrODLq10oXCU5ssf3OZ5OQsIRPK3NTzHp_jbNV2lFXnC091JwWQ=w188-h200" width="188" /></a><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhoINKTSus-q8DsCVPnim2ZT-_XTRQM4wzeqZ0ft26k49u2svO6T9NZtG1fy5cvvDCzRM9SOdU1zWwL50LvXXxIb9lhTD_CDl-efo1f98vSKTTZ9jT45EdWrTQDyKWAIpdajlk9rMdxk9xXhaGg36U0ToikH71uf_5Ebe275LxiMQrFFVSTphzxmuc" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="355" data-original-width="333" height="200" src="https://blogger.googleusercontent.com/img/a/AVvXsEhoINKTSus-q8DsCVPnim2ZT-_XTRQM4wzeqZ0ft26k49u2svO6T9NZtG1fy5cvvDCzRM9SOdU1zWwL50LvXXxIb9lhTD_CDl-efo1f98vSKTTZ9jT45EdWrTQDyKWAIpdajlk9rMdxk9xXhaGg36U0ToikH71uf_5Ebe275LxiMQrFFVSTphzxmuc=w188-h200" width="188" /></a><br /><br /><br /></div><p></p><div style="text-align: left;">Actually a quick revisit - internal discussion at Sprezz Towers brought up the fact that the article missed a fairly big point (because the author ass-u-med it was obvious which it obviously isn't :)). Panels can host panels that can host panels - as far as you are practically likely to go. So in the screen below we see multiple panels in action.</div><div style="text-align: left;"><br /></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgQZHpaakQzZBCK7LuJORuWRePi0Dij902nGILzQAfdoLLni8E_qjFo4s4Qi-86s9JUNPiad-QAsAGQ_y_PINmfDAgIxqm6IJvEplTnrZmIjWqMKMEAupmaqW55jebcxPevFE3MRwzT8BRx-x9jgLEYq_KV1i3WeCdBmw3Nd_gL3_8fIVrYyZWzGNI" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="480" data-original-width="482" src="https://blogger.googleusercontent.com/img/a/AVvXsEgQZHpaakQzZBCK7LuJORuWRePi0Dij902nGILzQAfdoLLni8E_qjFo4s4Qi-86s9JUNPiad-QAsAGQ_y_PINmfDAgIxqm6IJvEplTnrZmIjWqMKMEAupmaqW55jebcxPevFE3MRwzT8BRx-x9jgLEYq_KV1i3WeCdBmw3Nd_gL3_8fIVrYyZWzGNI=s16000" /></a></div><br /><br /></div><h2>Addendum - Mouse Use In Form Designer</h2><div><div>When in Draw Mode:</div><div> </div><div>Left Click</div><div>1) Left-click to drop a default-size control on a the form</div><div>2) Left-click and drag to draw a control on the form</div><div>3) Ctrl-left-click to drop a default size control on a container control</div><div>4) Ctrl-left-click and drag to draw a control on a container control.</div><div> </div><div>Right Click</div><div>1) Right-click and drag to draw a control on the form</div><div>2) Right-click and drag to draw a control on a container control.</div><div> </div><div> </div><div>When in Normal Mode:</div><div><br /></div><div>Left Click</div><div>==========</div><div> </div><div>1) Left-click on the form to unselect all controls</div><div>1) Left-click on an unselected control to select it</div><div>2) Left-click and drag around/across a group of unselected controls on the form to select them</div><div>3) Left-click and drag on an unselected or selected control to move it</div><div>4) Left-click and drag around a group of selected controls to move them</div><div>5) Ctrl-left-click on a selected container control and drag around/across unselected child controls to select them</div><div>6) Ctrl-left-click on a selected container control and drag around/across unselected child controls to select them</div><div>7) Shift-left-click to add an unselected control to a group of selected controls with the same parent</div><div>8) Shift-left-click on a group-selected control to remove it from a group of selected controls</div><div><br /></div><div>Right Click</div><div>===========</div><div><br /></div><div>1) Right-click on the form to display it's context menu</div><div>2) Right-click on an unselected control to select it and display it's context menu</div><div>3) Right-click on a selected control to display it's context menu</div><div>4) Right-click on a group of selected controls to display the group-selection context menu</div><div>5) Right-click and drag on the form to draw the most recently added type.</div><div>6) Right-click and drag on an selected container control to draw the most recently added type and add it as a child.</div><div>7) Right-click and drag on an unselected container to draw the most recently added type and add it as a child.</div><div>8) Shift-right-click on the form to drop the the most recently added type with a default size. </div><div>9) Shift-right-click on an selected container control to drop the the most recently added type with a default size and add it as a child.</div><div>10) Shift-right-click on an unselected container control to drop the the most recently added type with a default size and add it as a child.</div></div><div><br /></div>Sprezzhttp://www.blogger.com/profile/08866141305592910267noreply@blogger.com0tag:blogger.com,1999:blog-2607884204445547877.post-86239833521371425782022-11-24T14:42:00.003+00:002022-11-24T15:02:01.112+00:00You are Auth-ful - but I like you<p>Recently, a client was a little late in applying their authorisation code to their copy of OI10, and attempts to access OI were met with error messages "PSSI.66: ???". This seemed a strange message and at first we suspected that it wasn't even an OI message.</p><p>However chatting to the Rev developers, it seems that an insert (PS_RESOURCES) was missing from SYSENV and that it should in fact have had the following values </p><p><span style="font-family: courier;">///////////////////////////////////////////////////////////////////////////////</span></p><p><span style="font-family: courier;">//[PS_SYSINTIALIZE]////////////////////////////////////////////////////////////</span></p><p><span style="font-family: courier;">PSSI.00: No entry window defined for the %1% application.<br /></span><span style="font-family: courier;">PSSI.01: No visible entry window started for the %1% application<br /></span><span style="font-family: courier;">PSSI.02: Unable to start entry window "%1%" for the %2% application<br /></span><span style="font-family: courier;">PSSI.20: . Process aborted<br /></span><span style="font-family: courier;">PSSI.21: %1% initialization<br /></span><span style="font-family: courier;">PSSI.60: This Developer Class Server Deployment Pack for OpenInsight is due to expire on %1%.|Please contact Revelation Software at +1-800-262-4747 to renew your license.<br /></span><span style="font-family: courier;">PSSI.61: This copy of OpenInsight is due to expire on %1%.|Please contact Revelation Software at +1-800-262-4747 to renew your license.<br /></span><span style="font-family: courier;">PSSI.62: This copy of OpenInsight expired on %1%.|Use of this software is in violation of your OpenInsight Software License Agreement.|Please contact Revelation Software at +1-800-262-4747 to renew your license.<br /></span><span style="font-family: courier;">PSSI.63: This copy of OpenInsight has expired.||To purchase this product, contact Revelation Software on the web at:||www.revelation.com||Or call toll-free: (800) 262-4747<br /></span><span style="font-family: courier;">PSSI.64: This evaluation copy of OpenInsight expires on %1%.||To purchase this product, contact Revelation Software on the web at:||www.revelation.com||Or call toll-free: (800) 262-4747<br /></span><span style="font-family: courier;">PSSI.65: This evaluation copy of OpenInsight has expired.||To purchase this product, contact Revelation Software on the web at:||www.revelation.com||Or call toll-free: (800) 262-4747<br /></span><span style="font-family: courier;">PSSI.66: This Developer Class Server Deployment Pack for OpenInsight expired on %1%.|Use of this software is in violation of your OpenInsight Software License Agreement.|Please contact Revelation Software at +1-800-262-4747 to renew your license.<br /></span><span style="font-family: courier;">PSSI.67: Unable to process License Information.<br /></span><span style="font-family: courier;">PSSI.68: OpenInsight Licensing</span></p><p>So that clarified that issue.</p><p>The issue that we were left with was that normally in OI10, reauthorisation is done from <i>within</i> the product - and if you can't log in... you can connect the dots.</p><p>So, we went on search for a reauthorisation executable in the OI directory and not surprisingly found revauth.exe. This is a small executable, and clicking it seemed to do nothing. Until we realised that it was likely a command line executable. </p><p>Invoking powershell, we moved to the UNC containing revauth.exe and executed it with a /?. These were the results.</p><p><span style="font-family: courier;">PS Microsoft.PowerShell.Core\FileSystem::\\MyServer\Shares\Sprezz\programs\OINSIGHT_10> .\revauth.exe /?</span></p><p><span style="font-family: courier;">revauth <featurename> <authcode> <filename></span></p><p><span style="font-family: courier;">values for <featurename>:</span></p><p><span style="font-family: courier;">OI : OpenInsight<br />UDN: Universal Driver (network user license)<br />UDH: Universal Driver Heavy</span></p><p>So we instructed the client to run the following command</p><p><span style="font-family: courier;">revauth OI AuthCode revengine.lic</span></p><p>and lo and behold, the system worked again!</p><p>As an aside, the licensing information is no longer stored encrypted in a DLL but rather is stored in the revengine.lic file where it can be easily viewed - a modified example is shown below.</p><p><span style="font-family: courier;"><OI><br /></span><span style="font-family: courier;"> <Signature>Wwe23-Pg478-6h295-k1q62-00j9W-7jij8</Signature><br /></span><span style="font-family: courier;"> <SerialNumber>D99999999</SerialNumber><br /></span><span style="font-family: courier;"> <NumUsers>250</NumUsers><br /></span><span style="font-family: courier;"> <ExpirationDate>2023-10-17</ExpirationDate><br /></span><span style="font-family: courier;"> <ExpirationType>1</ExpirationType><br /></span><span style="font-family: courier;"></OI></span></p><p>Of course, you can't alter any of these values in notepad as they are actually encoded into the signature, but nice try!</p><p><a href="https://www.youtube.com/watch?v=Mls4sV0fKjE" target="_blank">And for readers who aren't British and of a certain age...</a></p><div><br /></div><p><br /></p><p><br /></p><p><br /></p><p></p><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both;"><br /></div><br /><br /></div><br />Sprezzhttp://www.blogger.com/profile/08866141305592910267noreply@blogger.com0tag:blogger.com,1999:blog-2607884204445547877.post-86190976060234452812022-10-01T21:02:00.004+01:002022-10-01T21:07:32.764+01:00OI 10 makes it easier to get onto the Property ladder<p>One of the intermittent problems we face when developing with OI 10 is knowing about the new properties and features that we now have access to. The pace of development is so rapid that the documentation just doesn't keep up. There's a fine source of documentation at <a href="https://revdevx.com/documentation/">revDevX.com</a> along with multiple blog posts at the same site but sometimes the Lord helps those who help themselves.</p><p>With this in mind, we'll use a real world example to illustrate how much easier life can be when we have access to such new features.</p><p>We recently wanted to have a radio button contract or expand based upon a control record. We knew how we would have accomplished this in the past - we'd grab the button control object, destroy it, modify it then recreate it. That's all well and good, it works and the control stays at the right place in the tab order - but it can change the Z-Order of the control which isn't always desirable.</p><p>Naturally we wondered if there was a better way in 10.</p><p>Of course there is, or we wouldn't be making this blog post.</p><p>Taking a simple example where we want to alter the available buttons based on the membership type, we'd have one set of radio buttons for the member type and another for the letter type.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiQa9Fy1kPkN3t7Kt0kMK9K4hcbcZYoRwxQ8spZhOO8KOCIBm8V7_vmTlCbCaxyl-ae-VJotLmhRSw7ZfTVdVy0OqS3r74_6l_zq0A8AlT4zpbsiqN_PKNEbLVBQOl3xcXHBdeL5zZnflrrI1tx4pPgl2X6Iu1KRsIV8rOHhLTLJmUN7l6VhZcKUmU" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="127" data-original-width="266" height="153" src="https://blogger.googleusercontent.com/img/a/AVvXsEiQa9Fy1kPkN3t7Kt0kMK9K4hcbcZYoRwxQ8spZhOO8KOCIBm8V7_vmTlCbCaxyl-ae-VJotLmhRSw7ZfTVdVy0OqS3r74_6l_zq0A8AlT4zpbsiqN_PKNEbLVBQOl3xcXHBdeL5zZnflrrI1tx4pPgl2X6Iu1KRsIV8rOHhLTLJmUN7l6VhZcKUmU" width="320" /></a></div><br />An existing member wouldn't need a Welcome Letter so clicking on "Existing Member" has to do this<p></p><p><br /></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhrqFqRQ-Itxny2LOXVG4L-XnT2BkrSNdaZ4Q57Va02UALyksdcC1ldBkrjHrmVb5DZOi4Xnvs-aUxQMLDAEnc13A7P3Xf0y4QThQyqsH2BmU31X-sQRAmqdC8o84XldzAt7AYoaRCVG3j6I_LM430iN3OMgCI28_29Q2q_YQsGs2he8-SNy82cjuw" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="127" data-original-width="266" height="153" src="https://blogger.googleusercontent.com/img/a/AVvXsEhrqFqRQ-Itxny2LOXVG4L-XnT2BkrSNdaZ4Q57Va02UALyksdcC1ldBkrjHrmVb5DZOi4Xnvs-aUxQMLDAEnc13A7P3Xf0y4QThQyqsH2BmU31X-sQRAmqdC8o84XldzAt7AYoaRCVG3j6I_LM430iN3OMgCI28_29Q2q_YQsGs2he8-SNy82cjuw" width="320" /></a></div><br />i.e. the "Welcome Letter" option is removed.<p></p><p>We all like to boast that OpenInsight is written in OpenInsight but the implications of this can be missed in the excitement of the new environment. We're so used to OI not exposing all of a control's properties that we lose track of the possibility that what we need may be staring us right in the face.</p><p>The simple fact is, that if something exists in the property panel in the form designer for a control, then it is an exposed property. So let's look at the property panel for a radio button.</p><p><br /></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgj8sKI4k24TsxGEgNmNhcWi8CFxr-uIbK2ESZTOSRjT4Wa7nQEjRhAQQcnCEXm40Fpu2BhT9vB5SDF8n6UtRMkKriU1XQjYQMadQ6O_KHGMSeXsiUyc0cdZoZHLsWBvEIt0_xRlH-X5v4JM_n_0hSExLvEAxVPZnK0nHzEYwZKhs7uc9rdpTJHlHs" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="753" data-original-width="250" src="https://blogger.googleusercontent.com/img/a/AVvXsEgj8sKI4k24TsxGEgNmNhcWi8CFxr-uIbK2ESZTOSRjT4Wa7nQEjRhAQQcnCEXm40Fpu2BhT9vB5SDF8n6UtRMkKriU1XQjYQMadQ6O_KHGMSeXsiUyc0cdZoZHLsWBvEIt0_xRlH-X5v4JM_n_0hSExLvEAxVPZnK0nHzEYwZKhs7uc9rdpTJHlHs=s16000" /></a></div><br />and what do we see as the fourth property? Buttons. <p></p><p>Clicking on the options button displays a dialog containing the text and values for the radio button :-</p><p></p><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEj-7R2kfHiiSXec05lIYT5YSkbccuLgrzwxCJofm4GgqMq-MELwvJmrezsz49Dh9P6HRSwSHb05P5WYIOmrxd9w2EoquwayWrPMploHc7SiEqaUGQMbYDA2xUGraEJX-kDrarPhqX7ZfYKEXBbIfOx_YPJAODHv5tLaMt5eWNApiKKhjcPUYH4CM9Y" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="115" data-original-width="301" height="122" src="https://blogger.googleusercontent.com/img/a/AVvXsEj-7R2kfHiiSXec05lIYT5YSkbccuLgrzwxCJofm4GgqMq-MELwvJmrezsz49Dh9P6HRSwSHb05P5WYIOmrxd9w2EoquwayWrPMploHc7SiEqaUGQMbYDA2xUGraEJX-kDrarPhqX7ZfYKEXBbIfOx_YPJAODHv5tLaMt5eWNApiKKhjcPUYH4CM9Y" width="320" /></a></div><br /><br /></div>As we've telegraphed this far in advance you can probably guess what this means - radio buttons expose a BUTTONS property. It consists of two columns, both multivalued. The first is the label description and the second is the associated code.<div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both;"><div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEinCg22pzDhdniyfVmWsJzb7ylKwFVPsoCHKRcTEkwOrC1IkQzz_j2GRPGZru6QGF4ROId7aRJzQ_9uU6Iaq9iAmjJ_KXXKpg1XD9ak4omEwF1GtT0jp8oVxncHLe46W9HZBMm0gQznPGuuG5ty5EsTsMHQwqg51bK4ILtNuJBPTVCWefGsEVo7SJI" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="107" data-original-width="860" src="https://blogger.googleusercontent.com/img/a/AVvXsEinCg22pzDhdniyfVmWsJzb7ylKwFVPsoCHKRcTEkwOrC1IkQzz_j2GRPGZru6QGF4ROId7aRJzQ_9uU6Iaq9iAmjJ_KXXKpg1XD9ak4omEwF1GtT0jp8oVxncHLe46W9HZBMm0gQznPGuuG5ty5EsTsMHQwqg51bK4ILtNuJBPTVCWefGsEVo7SJI=s16000" /></a></div><br /><br /></div></div><p>So now, to accomplish the above goal all we have to do is manipulate this property. Here's a simple code snippet to do this :-</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEina5TjF4bRJce2XLy5AqgTjk-fQZHFN8Mngu2y9YpXOASePJaqr2Oy-iO-TQk5vsHGmiwiQ7bRffM83UdbbJh-olbW00AAtrKowjmPZp_reTbCqYX3JgmvqcLocrKLatfj032Y_kIWgQs60gqyNhiKOMt4RHKrvkX1_tKS0ztmBjgA6DNZGDNxX4s" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="486" data-original-width="781" height="398" src="https://blogger.googleusercontent.com/img/a/AVvXsEina5TjF4bRJce2XLy5AqgTjk-fQZHFN8Mngu2y9YpXOASePJaqr2Oy-iO-TQk5vsHGmiwiQ7bRffM83UdbbJh-olbW00AAtrKowjmPZp_reTbCqYX3JgmvqcLocrKLatfj032Y_kIWgQs60gqyNhiKOMt4RHKrvkX1_tKS0ztmBjgA6DNZGDNxX4s=w640-h398" width="640" /></a></div><br />If you're not familiar with the syntax being used for getting and setting properties check out the <a href="https://revdevx.com/2016/04/29/object-notation-syntax/" target="_blank">blog post here.</a><div><br /></div><div>We'd encourage you to take a look around the property panels to see what other goodies you can find!<br /><p></p><p></p><div class="separator" style="clear: both; text-align: center;"><br /></div><p></p><p><br /></p></div></div>Sprezzhttp://www.blogger.com/profile/08866141305592910267noreply@blogger.com0tag:blogger.com,1999:blog-2607884204445547877.post-34570891006948259372022-06-07T14:25:00.000+01:002022-06-07T14:25:00.100+01:00Indexing issues on LARGE tables<p> We've been doing a lot of stress testing of LH at Sprezz Towers to help a client with speed issues on large tables. As part of that we've created some 60 million row tables to play with combinations and permutations of differing indexing setups.</p><p>In so doing, we came across a situation where the index sort would get to 80% and then just exit with an FS220 error. (FS_REL_NEED_REBUILD_ERR$). Now to be honest, this was confusing to us as there wasn't a relational index on the table. So speaking to the good folks at Rev, it was clarified that this was the wrong error but for fairly obvious reasons we were the first to notice. After discussing further with them we came to the conclusion that it must be related to disk space.</p><p>So began an increasingly frustrating attempt to free up disk space (why oh why did I format my USB sticks with FAT32 and its 4GB file size limit?). Subdirectories were zipped, old files deleted until - finally we had the 40GB or so free that we needed. </p><p>We tried again - and again around the 80% mark the index rebuild just stopped. It didn't crash, it just stopped - having cleared out the %ALL.IDS% token in the ! file.</p><p>As V119 was suspected to be the culprit, we redirected the temporary sort file in the environment to the same disk as the data tables so that we could keep an eye on what happened. </p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEh9nGehc4HvgZ8yGZ_gfgepreK-vFutgM1zcvGzouCORj7Rk4yP0q7nDQgBF_d96qdCj-U85Z9ntsnsDHkMSmT_XzzmiPaMKAJ-4X0R4hcuo2V6u0tTzYVffB5SdJdyrTptZdMI5nP23DYI-c3Jvk88JYBL-PT6oORNFtqFQCGxQkOL5m0PN9Sm7uo" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="152" data-original-width="362" src="https://blogger.googleusercontent.com/img/a/AVvXsEh9nGehc4HvgZ8yGZ_gfgepreK-vFutgM1zcvGzouCORj7Rk4yP0q7nDQgBF_d96qdCj-U85Z9ntsnsDHkMSmT_XzzmiPaMKAJ-4X0R4hcuo2V6u0tTzYVffB5SdJdyrTptZdMI5nP23DYI-c3Jvk88JYBL-PT6oORNFtqFQCGxQkOL5m0PN9Sm7uo=s16000" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div>At 77% and the sortfile is growing<div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEj6boohTgJfabP74uO8lze8G8oXJ28sdPz9gZ-AkvFdUk9neJiSUtIoFlxMSuFpEwggBNeSTLPjsVTQ5jbcd0E1loi5Mj4r7VdzA5ALFc5mHMGFt_vbLV5E7000kxKgnPHvTeX_EnizZqVimshtlb-pOvUF2yR1mQjK0c323pT92BcPe7sB53Cqoew" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="511" data-original-width="361" src="https://blogger.googleusercontent.com/img/a/AVvXsEj6boohTgJfabP74uO8lze8G8oXJ28sdPz9gZ-AkvFdUk9neJiSUtIoFlxMSuFpEwggBNeSTLPjsVTQ5jbcd0E1loi5Mj4r7VdzA5ALFc5mHMGFt_vbLV5E7000kxKgnPHvTeX_EnizZqVimshtlb-pOvUF2yR1mQjK0c323pT92BcPe7sB53Cqoew=s16000" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgSoiGKMOJARj_ExO-OAN325cKIXZ0j9FTWXzGVJbq_moLVht_wJUm80nG0lJL2Lujnos4-I5lDf8QzAH5IGA-8NtP15V5_S8ZRGqOZfQcuSgqSv7QFp4ASdnOHq8nYr5zbZpq_RwwO0xs4DyyNEKBTPnJ7B2phoW3c5DPqnX923bM5xTqZYnO9Hzg" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="150" data-original-width="357" src="https://blogger.googleusercontent.com/img/a/AVvXsEgSoiGKMOJARj_ExO-OAN325cKIXZ0j9FTWXzGVJbq_moLVht_wJUm80nG0lJL2Lujnos4-I5lDf8QzAH5IGA-8NtP15V5_S8ZRGqOZfQcuSgqSv7QFp4ASdnOHq8nYr5zbZpq_RwwO0xs4DyyNEKBTPnJ7B2phoW3c5DPqnX923bM5xTqZYnO9Hzg=s16000" /></a></div><br />78% and still going</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhqZWqVCPnm4lxB2XjynrIEzsZUkRuKhB4zc2dYpHz0Q_JEpHAvqbmPxERDuSs9g3M9uUN56bkAmtNASC3qjUEksGh1VZwCQ43tjBdPdqkp_WjoR2MKgb0O620YFZ9w2xJrbvZ-EQQXDAQlkmyTN5wWeke-P9Vm7BcGn9Kws_kZhdBGQ8Fjt4IExQo" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="507" data-original-width="360" src="https://blogger.googleusercontent.com/img/a/AVvXsEhqZWqVCPnm4lxB2XjynrIEzsZUkRuKhB4zc2dYpHz0Q_JEpHAvqbmPxERDuSs9g3M9uUN56bkAmtNASC3qjUEksGh1VZwCQ43tjBdPdqkp_WjoR2MKgb0O620YFZ9w2xJrbvZ-EQQXDAQlkmyTN5wWeke-P9Vm7BcGn9Kws_kZhdBGQ8Fjt4IExQo=s16000" /></a></div><br /><br />and then - boom</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhN5P6Ts0_79bFaR3aj3TR6Yg4JvZUWUxPw9UGzo8S2ihkOlmudewpW7pnBwMdqH6wMIlRe4tDJd7aXAMLf_tSF8hXSwCAD7TZPAisft-nXrUt7T9v6t9N4lcCLuSkqDD-HrjjJl0kDtgluD-WGsrbHOpeYk0BLZcPoEsCd15wB_QD32oaK3n2QBJ8" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="154" data-original-width="398" src="https://blogger.googleusercontent.com/img/a/AVvXsEhN5P6Ts0_79bFaR3aj3TR6Yg4JvZUWUxPw9UGzo8S2ihkOlmudewpW7pnBwMdqH6wMIlRe4tDJd7aXAMLf_tSF8hXSwCAD7TZPAisft-nXrUt7T9v6t9N4lcCLuSkqDD-HrjjJl0kDtgluD-WGsrbHOpeYk0BLZcPoEsCd15wB_QD32oaK3n2QBJ8=s16000" /></a></div><br />It seems that the largest sort file that can be created is 2GB and that attempts to exceed this will fail. Note that this applies to both IDX_SETS1 and 2. This is a limitation of a 32 bit OS rather than OpenInsight, so can not easily be addressed in version 9.x.</div><div><br /></div><div>Now it should be pointed out that this is a particularly extreme situation, as the row ids in this large table are 5 part and quite long. With a more normal key structure than the long complex one we were using, it is unlikely that this limit would be breached without having hundreds of millions of rows in the table... but it does mean that if you need to rebuild such large indexes you need to undertake the task in OI 10.1 where the issue has been resolved. Note also that this doesn't affect day to day use of the indexed table, normal additions and deletions will still update the index - this issue only affects a rebuild.</div><div><br /></div><div>As a side note - if you DO want to do this in 10.x there is a <b>major</b> caveat. Indexing has been rewritten for 10 and works in a different way than 9. This means that out of the box, OI 9 and OI 10 have different indexing routines <i>and are not compatible</i>. Fortunately Rev have provided a way to deal with this.</div><div><br /></div><div>All that we need to do is edit or create a record in SYSENV called CFG_RTI_UPDATE_INDEX. Set line 1 to RTI_UPDATE_INDEX_90 then save it, exit OI and restart. This will force 10 to use 9 indexing logic. We've been working a lot with indexes on large tables in 10 and we'd recommend using this setting in any case if you're working with large data volumes. By large tables, we are talking tens of millions of rows.</div><div><br /></div><div>For the avoidance of doubt - if you are sharing data between OI 9 and OI 10 you MUST do this or you will experience issues.</div>Sprezzhttp://www.blogger.com/profile/08866141305592910267noreply@blogger.com0tag:blogger.com,1999:blog-2607884204445547877.post-30299184854995993502021-08-04T17:48:00.003+01:002021-08-04T18:36:20.499+01:00ARRAY and LIST properties<p>This will probably be obvious to most, but it's been a real thorn in my side since day one of OpenInsight, and by day one I mean alpha testing and writing bits of OI 2.0 back in my apk@revelation.com days.</p><p>I've always had trouble remembering which property is LIST and which property is ARRAY. Every time I use these, I either get it wrong or just load HELP to check which one is column by row and which one is row by column. Finally, with a little help from Captain C, I have a working mnemonic.</p><p>ARRAY == <b>Across</b>, because the data moves across the table.<br />LIST == <b>Lines</b>, because the data comes back line by line.</p><p>Finally, almost 28 years later, I can stop searching HELP daily.<br /></p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2607884204445547877.post-58433564593468402612021-08-04T10:14:00.002+01:002021-08-04T10:14:18.026+01:00Demystifying clientsetup.exe<p> Over the years, we've had numerous queries as to what exactly clientsetup.exe does and why it has to be run on each and every machine that will be running OpenInsight. With the help of RTI stalwart Bryan Shumsky, we've put together this post to tell you all you need to know about client install.</p><p>Over the years, OpenInsight has evolved from a pretty much self contained environment, where you could just pick up an application folder, move it elsewhere and expect it to work, to an environment which requires increasing levels of workstation adaptation. Firstly the OIPI print engine required that an OCX be registered at the workstation before it could be used. Of course, the OCX could still reside on the server, so all that was required for the client was an OCX registration via REGSVR32.EXE. The same went for the AREV32/64 command window. Then the new scintilla editor.</p><p>But as more of OI began to be developed in external languages, (specifically .NET) the requirements became more onerous. Windows doesn't take too kindly to being asked to run .NET components over a network and to make it happen, various security overrides need to be put in place. These are beyond the capabilities of a run of the mill installation script, so the decision was taken to install the .NET components locally on the workstation and to register them there. At this point it's important to add that you MUST install these assemblies on the local machine not on a network drive,</p><p>For reference, it is worthwhile pointing out that whilst historically the client setup is run from the OINSIGHT subdirectory, it can actually be run from <i>any</i> location as long as the "Assemblies" and "Client Files" subdirectories exist (with contents) relative to the clientsetup.exe.</p><p>With Bryan's help we were able to put together this list of what actually happens during a client install. So with no more ado, here's what the program actually gets up to...</p><p>First things first. Check if the client setup has already been run at some stage on this workstation - so it's off to the local registry the program goes. This makes it easier for the program to suggest defaults for the new installation.</p><p>Next, just to be nice, the program sets up shortcuts to the documentation, website etc etc.</p><p>Then, checks if there are already existing .NET assemblies at the requested installation location. If there are, they are removed. This is to stop the installation process interjecting with annoying messages about pre-existence etc.</p><p>Penultimately it then copies the files from the aforementioned subdirectories (Assemblies, Client Files) to the specified location on the local machine.</p><p>It then finally registers and installs the OCXs and .NET assemblies at their new local location.</p><p>Of course, there are circumstances where the client install might not be needed - for example if your installation doesn't need to edit, print, or sort information. Paradoxically this does mean that if you're running the engine server on the network server, you <b>must</b> ensure you do the client install on that machine too!</p><p>Hopefully this information will help you in understanding your deployment issues, and a big shout out to Bryan for helping with this.</p>Sprezzhttp://www.blogger.com/profile/08866141305592910267noreply@blogger.com0tag:blogger.com,1999:blog-2607884204445547877.post-40082360577199502532021-04-14T17:52:00.000+01:002021-04-14T17:52:13.819+01:00PDISK issues<p>Like many Revelation consultants, we have a number of clients who continue to use decades old software under new, more modern technologies - specifically AREV32/64. A technology that was meant to provide a transition path to a more modern UI is frequently just used as a way to continue taking advantage of the massive ROI provided by Revelation Software - in this case AREV.</p><p>But sometimes, things go wrong. And this week we were bitten by a particularly pernicious bug that we hadn't seen before.</p><p>The client reported that suddenly, blank documents were being emailed to their customers rather than the order confirmations that they were expecting. Investigation was relatively easy - isolate the section of the code that creates the files and test this. The section of code in question simply executed a PDISK to redirect printer output to a file, produced the report, then PDISK PRNed to cancel the redirection.</p><p>Upon testing, it failed to produce any output, despite reporting that the redirection was successful. Following Occam's Razor we tried to reproduce the issue by issuing a PDISK at TCL, performing a simple LIST report to disk, then doing a PDISK PRN. Surprisingly, no disk file was produced. </p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-lBqjGZIq-Ws/YHcNWm75dsI/AAAAAAAAA3g/-JBnGsRiwXUXnYfcOQj-4A_t6EhfuKzoQCNcBGAsYHQ/s952/2021-04-14_15-59-26.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="242" data-original-width="952" height="162" src="https://1.bp.blogspot.com/-lBqjGZIq-Ws/YHcNWm75dsI/AAAAAAAAA3g/-JBnGsRiwXUXnYfcOQj-4A_t6EhfuKzoQCNcBGAsYHQ/w640-h162/2021-04-14_15-59-26.png" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-YOqgXkj4G9g/YHcNWuyqAdI/AAAAAAAAA3k/7PFHMJRRLxc8cuObe9Z3cHau5sPAvNXAQCNcBGAsYHQ/s1292/2021-04-14_16-00-04.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="395" data-original-width="1292" height="195" src="https://1.bp.blogspot.com/-YOqgXkj4G9g/YHcNWuyqAdI/AAAAAAAAA3k/7PFHMJRRLxc8cuObe9Z3cHau5sPAvNXAQCNcBGAsYHQ/w640-h195/2021-04-14_16-00-04.png" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-wIBIqSrqUMQ/YHcNWr7tgcI/AAAAAAAAA3c/RusHpVQH52U9YXr8bOb57BlbDyrvYBfqwCNcBGAsYHQ/s852/2021-04-14_16-00-37.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="238" data-original-width="852" height="178" src="https://1.bp.blogspot.com/-wIBIqSrqUMQ/YHcNWr7tgcI/AAAAAAAAA3c/RusHpVQH52U9YXr8bOb57BlbDyrvYBfqwCNcBGAsYHQ/w640-h178/2021-04-14_16-00-37.png" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-7GXv_6lSHm8/YHcNXUnUKPI/AAAAAAAAA3o/03VwD_lhkRYKqi4ClDnayYjJ2kbTb_-bwCNcBGAsYHQ/s683/2021-04-14_16-01-01.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="229" data-original-width="683" height="214" src="https://1.bp.blogspot.com/-7GXv_6lSHm8/YHcNXUnUKPI/AAAAAAAAA3o/03VwD_lhkRYKqi4ClDnayYjJ2kbTb_-bwCNcBGAsYHQ/w640-h214/2021-04-14_16-01-01.png" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/--oFmc_4XcT8/YHcNXkRQJII/AAAAAAAAA3s/LqpbFHJ7nzod7mdHs5FMYYvlCHtBA_g1ACNcBGAsYHQ/s962/2021-04-14_16-01-31.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="391" data-original-width="962" height="261" src="https://1.bp.blogspot.com/--oFmc_4XcT8/YHcNXkRQJII/AAAAAAAAA3s/LqpbFHJ7nzod7mdHs5FMYYvlCHtBA_g1ACNcBGAsYHQ/w640-h261/2021-04-14_16-01-31.png" width="640" /></a></div><div><br /></div>But looking at the subdirectory no file was created.<br /><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-8pSt0FXeDPM/YHcNXjTj4gI/AAAAAAAAA3w/2qfQE3MFdEAduLAeN_petgCBSprCPMTOwCNcBGAsYHQ/s786/2021-04-14_16-02-28.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="113" data-original-width="786" height="93" src="https://1.bp.blogspot.com/-8pSt0FXeDPM/YHcNXjTj4gI/AAAAAAAAA3w/2qfQE3MFdEAduLAeN_petgCBSprCPMTOwCNcBGAsYHQ/w640-h93/2021-04-14_16-02-28.png" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><p>So we reverted to an older version of the software and tried again - regretfully with the same result. It didn't matter how far back we went, the error persisted. At this point it became obvious that this was not the issue that the client was facing - all had been well until the last upgrade - but it WAS an issue that we were facing in our testing. But our software was a direct copy of their system, so what could it possibly be?</p><p>We tried calling SETPTR directly, we tried different filenames and different extensions but to no avail. So it was time to roll out the big guns and deploy PROCMON, the stunningly useful utility from SysInternals available from <a href="https://docs.microsoft.com/en-us/sysinternals/downloads/procmon">Process Monitor - Windows Sysinternals | Microsoft Docs</a>. We reproduced the lack of output with PROCMON running and examined the captured output. We filtered the output on process OENGINE.EXE and path containing ZZZZ.txt and saw 6 entries as below :-</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-0POBwC3-A8Q/YHcNXx6JpMI/AAAAAAAAA4Q/_SlrHZxc_aAPdDT1f_K9D1bRYxm7uztsQCPcBGAYYCw/s1669/2021-04-14_16-04-08.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="193" data-original-width="1669" height="74" src="https://1.bp.blogspot.com/-0POBwC3-A8Q/YHcNXx6JpMI/AAAAAAAAA4Q/_SlrHZxc_aAPdDT1f_K9D1bRYxm7uztsQCPcBGAYYCw/w640-h74/2021-04-14_16-04-08.png" width="640" /></a></div><br /><p>The first 4 were as expected, but the last two were strange to say the least. The spaces in our directory path had been replaced with underscores - and strangely, Windows could not find a path with that name.</p><p>This provided us with a working theory - so we copied the system to a subdirectory with no spaces in the name and repeated the experiment. This time we saw the results we expected - a file containing output :-</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-62_MBv0Ts2o/YHcNYGpO0gI/AAAAAAAAA4Q/-Q7tl4dPXqU9rU1n6KtHaLtaIHi9AT1fACPcBGAYYCw/s787/2021-04-14_16-06-53.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="404" data-original-width="787" height="328" src="https://1.bp.blogspot.com/-62_MBv0Ts2o/YHcNYGpO0gI/AAAAAAAAA4Q/-Q7tl4dPXqU9rU1n6KtHaLtaIHi9AT1fACPcBGAYYCw/w640-h328/2021-04-14_16-06-53.png" width="640" /></a></div><br /><p>and the PROCMON trace showed no errors</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-KF5FD3WnWvM/YHcNYEhIN1I/AAAAAAAAA4M/KTVAyss6N_494BeREi8iRx6FEWMEBUsbwCPcBGAYYCw/s1672/2021-04-14_16-07-18.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="194" data-original-width="1672" height="74" src="https://1.bp.blogspot.com/-KF5FD3WnWvM/YHcNYEhIN1I/AAAAAAAAA4M/KTVAyss6N_494BeREi8iRx6FEWMEBUsbwCPcBGAYYCw/w640-h74/2021-04-14_16-07-18.png" width="640" /></a></div><br /><p>So it would seem that PDISK has been engineered not to work with subdirectories containing spaces in the path. </p>Sprezzhttp://www.blogger.com/profile/08866141305592910267noreply@blogger.com4tag:blogger.com,1999:blog-2607884204445547877.post-14665245090051146342021-03-02T12:42:00.005+00:002021-03-02T12:44:00.623+00:00Prototyping DLLS in OI 10 using the new UI<p> With more and more applications (in Europe at least) moving to UTF8 we got to thinking about the inherent limitations in case conversion for developers in OpenInsight. Historically developers have changed from lower to upper case by simply converting @lower.case to @upper.case in the string to be converted. This is all well and good in an ANSI system but could create issues in a UTF8 system.</p><p>The strings @lower.case and @upper.case aren't magic - they are just text strings loaded by the system at startup, and there is no way that they can easily be made to contain all of the characters necessary in a UTF8 system. Naturally we could manually load them with all of the characters that we <i>think </i>might be required but the strong chances are we'd miss something, and in any case it's 2021 - there has to be a better way right?</p><p>Right.</p><p>Of course there is - it's an issue all Windows developers face - not just Rev developers. So naturally Microsoft have made it easy by providing two exported DLL functions for developers to use, namely <a href="https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-charupperw" target="_blank">CharUpperW</a> and <a href="https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-charlowerw" target="_blank">CharLowerW</a>. (For an explanation of why we are using the W version rather than the A see <a href="http://sprezzblog.blogspot.com/2009/06/dll-prototyping-strings-and-things-part.html" target="_blank">this blog</a> entry). These functions do the conversion of the string "in place" - so we simply have to call them passing in the string to be converted and it will be changed in the string (rather than returning a changed value).</p><p>The only drawback is that to be able to use it, we have to prototype it first in a DLL definition. Historically this was a messy process, involving creating a DLL Prototype for the functions, saving it and then running a system routine called DECLARE_FCNS against this definition. If you're not <a href="http://sprezzblog.blogspot.com/2009/06/dll-prototyping-namespaces.html" target="_blank">familiar with this</a>, where have you been for the last decade or so? ;). Then if we wanted to track the definition for deployment we'd have to create an APPROW definition because the OI Repository didn't know about the existence of DLL prototypes.</p><p>Fortunately in OI 10, DLL Prototypes are now part of the OI entity family and as such there are UI tools to accomplish all of the above. So let's see how we'd go about defining the above two functions.</p><p>Let's go to File/Entity/New</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-IO0vYtvPOIs/YD0vCK5meeI/AAAAAAAAA14/MbuGRH16j0YxSQn9p4CG-L_2Kq6D2ao-ACNcBGAsYHQ/s829/2021-03-01_16-23-32.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="194" data-original-width="829" height="150" src="https://1.bp.blogspot.com/-IO0vYtvPOIs/YD0vCK5meeI/AAAAAAAAA14/MbuGRH16j0YxSQn9p4CG-L_2Kq6D2ao-ACNcBGAsYHQ/w640-h150/2021-03-01_16-23-32.png" width="640" /></a></div><br /><p>and select DLL prototype record. The DLL Prototype Designer launches and we can define our functions. Let's start by telling it that the functions we need are in USER32 and define a namespace (a unique string to prepend to the name of the function so that somebody else's (potentially incorrect prototype) definition doesn't overwrite ours). This particular function doesn't return a value so we're going to use a return type of VOID :-</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-0kGuoEeeUVo/YD0vCEk3QvI/AAAAAAAAA2o/qoowPrbj1RMQBKi2DgSGQ9d7JNdZEPOsQCPcBGAYYCw/s777/2021-03-01_16-25-41.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="777" data-original-width="686" height="640" src="https://1.bp.blogspot.com/-0kGuoEeeUVo/YD0vCEk3QvI/AAAAAAAAA2o/qoowPrbj1RMQBKi2DgSGQ9d7JNdZEPOsQCPcBGAYYCw/w565-h640/2021-03-01_16-25-41.png" width="565" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div>It's a STDCALL type (like most definitions we make)<div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-eWFU5eitmLY/YD0vCEzOUbI/AAAAAAAAA2k/nX9FBTLuDLs8dlr-qUhSOmKhdrAQ487SgCPcBGAYYCw/s711/2021-03-01_16-26-17.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="150" data-original-width="711" src="https://1.bp.blogspot.com/-eWFU5eitmLY/YD0vCEzOUbI/AAAAAAAAA2k/nX9FBTLuDLs8dlr-qUhSOmKhdrAQ487SgCPcBGAYYCw/s16000/2021-03-01_16-26-17.png" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div>and it takes an LPWSTR type</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-KTjp5-GJl0A/YD00NwB6yhI/AAAAAAAAA24/JWIXXvfke6oazDdoijiwuMmYM5eWRhTowCNcBGAsYHQ/s437/2021-03-01_16-27-28.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="390" data-original-width="437" height="359" src="https://1.bp.blogspot.com/-KTjp5-GJl0A/YD00NwB6yhI/AAAAAAAAA24/JWIXXvfke6oazDdoijiwuMmYM5eWRhTowCNcBGAsYHQ/w400-h359/2021-03-01_16-27-28.png" width="400" /></a></div><br /><div><br /></div><div>Then define the arguments for both functions<div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-zb6skZWSIfE/YD0vDDHnTEI/AAAAAAAAA2s/OZc5xOMpjVYOsroMVmA0Cax4jcncVtJagCPcBGAYYCw/s741/2021-03-01_16-28-50.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="388" data-original-width="741" height="336" src="https://1.bp.blogspot.com/-zb6skZWSIfE/YD0vDDHnTEI/AAAAAAAAA2s/OZc5xOMpjVYOsroMVmA0Cax4jcncVtJagCPcBGAYYCw/w640-h336/2021-03-01_16-28-50.png" width="640" /></a></div><div><br /></div>and apply the namespace (to which I've remembered to add an underscore :))<br /><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-fZl6ICxcw-w/YD0vDG3-foI/AAAAAAAAA20/EYYoleVYWW09Pf1QvPTnlRGeS4uN2qFCgCPcBGAYYCw/s740/2021-03-01_16-30-20.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="388" data-original-width="740" height="336" src="https://1.bp.blogspot.com/-fZl6ICxcw-w/YD0vDG3-foI/AAAAAAAAA20/EYYoleVYWW09Pf1QvPTnlRGeS4uN2qFCgCPcBGAYYCw/w640-h336/2021-03-01_16-30-20.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div>Then save it using Ctrl-S</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-ikqj4LcVHks/YD0vDRIXlxI/AAAAAAAAA2s/FeCE2XnZbx4kz-O5Agz7VttYgZCFOwFlACPcBGAYYCw/s755/2021-03-01_16-30-37.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="445" data-original-width="755" height="378" src="https://1.bp.blogspot.com/-ikqj4LcVHks/YD0vDRIXlxI/AAAAAAAAA2s/FeCE2XnZbx4kz-O5Agz7VttYgZCFOwFlACPcBGAYYCw/w640-h378/2021-03-01_16-30-37.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div>The system obligingly tells us that is has saved the prototype</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-OqZfxPGCOEs/YD0vDuAjtLI/AAAAAAAAA2w/FP6RPGza2yUEN3EPu0pn6LMyf9W3YHmqQCPcBGAYYCw/s739/2021-03-01_16-30-59.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="91" data-original-width="739" height="78" src="https://1.bp.blogspot.com/-OqZfxPGCOEs/YD0vDuAjtLI/AAAAAAAAA2w/FP6RPGza2yUEN3EPu0pn6LMyf9W3YHmqQCPcBGAYYCw/w640-h78/2021-03-01_16-30-59.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div>and finally we can compile the prototype (running DECLARE_FCNS effectively) by pressing F9</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-EeMKNAvtE_A/YD0vDmitp6I/AAAAAAAAA2w/056gXz6ZEkAwJ5I1wu8vByoKIWFpc_cGgCPcBGAYYCw/s741/2021-03-01_16-33-12.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="178" data-original-width="741" height="154" src="https://1.bp.blogspot.com/-EeMKNAvtE_A/YD0vDmitp6I/AAAAAAAAA2w/056gXz6ZEkAwJ5I1wu8vByoKIWFpc_cGgCPcBGAYYCw/w640-h154/2021-03-01_16-33-12.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div>We can check that the system functions as in version 9 by checking for the DLL_ row in SYSPROCS</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-VLV0CGrxu6Y/YD0vD1q2sMI/AAAAAAAAA20/ezPvrMeQIVIONwcuq-b49BviSqheA37JwCPcBGAYYCw/s750/2021-03-01_16-33-57.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="228" data-original-width="750" height="196" src="https://1.bp.blogspot.com/-VLV0CGrxu6Y/YD0vD1q2sMI/AAAAAAAAA20/ezPvrMeQIVIONwcuq-b49BviSqheA37JwCPcBGAYYCw/w640-h196/2021-03-01_16-33-57.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div>and sure enough - the only difference in 10 from 9 is that there are now comment lines for the namespace and comments :-</div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-4ri2nr7W5Sc/YD0vEI2wIaI/AAAAAAAAA20/kXTHWImTl8wIJiMOkQXSuW8tSOHdssp0wCPcBGAYYCw/s739/2021-03-01_16-35-45.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="229" data-original-width="739" src="https://1.bp.blogspot.com/-4ri2nr7W5Sc/YD0vEI2wIaI/AAAAAAAAA20/kXTHWImTl8wIJiMOkQXSuW8tSOHdssp0wCPcBGAYYCw/s16000/2021-03-01_16-35-45.png" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div>The routines are now available to us to perform UTF8 compliant lower and uppercase conversions. So "convert @lower.case to @upper.case in string" becomes "call zz_CharUpperW( string )" and "convert @upper.case to @lower.case in string" becomes "call zz_CharLowerW (string )". Of course there's nothing to stop you aliasing the functions to more friendly names like "toUpper" or "toLower" but there's always the chance of a clash with existing names. </div><div><p><br /></p></div>Sprezzhttp://www.blogger.com/profile/08866141305592910267noreply@blogger.com0tag:blogger.com,1999:blog-2607884204445547877.post-63696414094083592052020-09-23T17:35:00.001+01:002020-09-24T11:30:53.275+01:00A word in your shell-like...<div>Are you sitting comfortably readers? Then buckle yourself in because this is going to be a long ride! </div><div><br /></div><h2 style="text-align: left;">The Challenge</h2><div>It all started when Martyn Phillips of Revelation UK approached us for some assistance with toggling button states in his new sample app. Originally he was interested in capturing the various actions that could be used to update the cut/copy/paste buttons in his app and we were able to point him to Carl’s <a href="https://revdevx.com/2017/08/31/the-editstatechanged-event/" target="_blank">EDITSTATECHANGED </a>blog post, which along with some hints from our own blog on promoting <a href="https://sprezzblog.blogspot.com/2020/05/promoting-new-oi-10-feature.html" target="_blank">HELP </a>events got him to where he wanted to be. </div><div><br /></div><div>Then Martyn asked if we could do something similar for his Save/Clear/Delete buttons. This was a tougher challenge as what we really need is a FORMSTATECHANGED event, not dissimilar to the above, but triggered when the form changes in such a way that the save/clear/delete buttons should be updated. (SPOILER ALERT – it is coming, so treat this blog post as educational not proscriptive!). The problem is, that so many things can change the state of the form. LOSTFOCUS, CLICK, CHANGED, whether it’s a new row, whether it’s an existing row etc, etc. </div><div><br /></div><div>So, we concluded that the most viable way would be to promote an event to the level of “all events for all controls” and perform our magic from there.</div><div><br /></div><h2 style="text-align: left;">The Chosen Solution</h2><div>But this is a sample app, and we’ve already got one promoted event, so we wanted another technique. Musing about how we could possibly know that something had changed the save status of the form, we recalled that the SAVEWARN property is set by the system when the current record is “dirty” and needs to be saved. </div><div><br /></div><div>So, we decided to try and intercept the SET_PROPERTY call that updates SAVEWARN. </div><div><br /></div><div>Historically we’ve done this using the time-honoured technique of copying $SET_PROPERTY to $RTI_SET_PROPERTY and providing our own shell $SET_PROPERTY. The issue with this, is that updates can overwrite OUR version of $SET_PROPERTY so it’s a maintenance nightmare.</div><div><br /></div><div>Checking LH logs gave us an idea. The program loader application, RTP27 always seems, when asked to load a program, to look first in the MD file, and if it doesn’t find what it’s looking for, then looks in SYSOBJ. (The reality of the situation is more complex as Revelation’s Bryan Shumsky explained to us when we asked. See below.)</div><div><br /></div><div>Those of you who are coming to OpenInsight from an AREV or Pick background will know that the MD file (“Master Dictionary”) is simply a collection of pointers telling the system (amongst other things) where to find the program that has just been requested. The traditional format would be as follows:</div><div><br /></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div><span style="white-space: pre;"> </span>ROWID</div><div><br /></div><div><span style="white-space: pre;"> </span>Type of Pointer</div><div><span style="white-space: pre;"> </span>Blank</div><div><span style="white-space: pre;"> </span>File to find Object in</div><div><span style="white-space: pre;"> </span>Name of Object</div></blockquote><div><br /></div><div>So, for example the row for SET_PROPERTY would be:</div><div><br /></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div><span style="white-space: pre;"> </span>RBASIC</div><div><span style="white-space: pre;"> </span></div><div><span style="white-space: pre;"> </span>SYSOBJ</div><div><span style="white-space: pre;"> </span>SET_PROPERTY.</div></blockquote><div><br /></div><div>OpenInsight did away with these pointers and just assumed that executable code would be found in SYSOBJ. But the introduction of the CTO made the MD required again.</div><div><br /></div><div>Given this information, and the fact that we can modify MD records as we wish, it becomes obvious that we can change the SET_PROPERTY entry to point to OUR replacement for SET_PROPERTY, add a new entry called say, RTI_SET_PROPERTY, and point this at the original SET_PROPERTY. When RTP27 comes to load SET_PROPERTY, it will find SET_PROPERTY (which redirects to ZZ_SET_PROPERTY) which will in turn find RTI_SET_PROPERTY (Which redirects to the original SET_PROPERTY).</div><div><br /></div><div>So, we would have an MD entry called SET_PROPERTY:</div><div><br /></div><div><span> </span><span> </span>RBASIC</div><div><br /></div><div><span> </span><span> </span>SYSOBJ</div><div><span> </span><span> </span>ZZ_SET_PROPERTY*PRACTICE_LOG</div><div><br /></div><div>And an MD entry called RTI_SET_PROPERTY:</div><div><br /></div><div><span> </span><span> </span>RBASIC</div><div><br /></div><div><span> </span><span> </span>SYSOBJ</div><div><span> </span><span> </span>SET_PROPERTY</div><div><br /></div><div>So, we can do whatever processing we want (in this case checking amongst other things the SAVEWARN property) and then call RTI_SET_PROPERTY to actually do the real work. (Well in our case, the other way round – let RTI_SET_PROPERTY do its work, then do the checking.)</div><div><br /></div><div>For an in-depth discussion of this technique, we recommend checking out SRP’s excellent (and amusingly titled) blog post on this subject at <a href="https://blog.srpcs.com/hooking-in-basic-using-different-bait/">https://blog.srpcs.com/hooking-in-basic-using-different-bait/</a>.</div><div><br /></div><div>We created our MD entries and tested. Logging out and back in to ensure that our new shelled routines were in memory, we were delighted to see that the concept was working. Our routine was being called! </div><div><br /></div><h2 style="text-align: left;">The First Hurdle</h2><div>Regretfully, we fell at the first hurdle. Whenever we tried to call our replacement SET_PROPERTY, the system would crash, complaining that we were being passed too many parameters. This seemed ludicrous, I mean, everyone knows that SET_PROPERTY takes 4 parameters, right?</div><div><br /></div><div>OR so we think – until we take advantage of the wonderful new System Editor’s ability to open Entity OBJECT rows without blowing chunks. ( and dictionary items - thanks SRP!) - let’s give that a try…</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-MC__iBpD8V0/X2oc_OT5wWI/AAAAAAAAAxM/mHM4zG3J-c0W2PaDTKry2n3nHDSLlU05wCNcBGAsYHQ/s958/2020-09-22_12-16-17.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="307" data-original-width="958" height="205" src="https://1.bp.blogspot.com/-MC__iBpD8V0/X2oc_OT5wWI/AAAAAAAAAxM/mHM4zG3J-c0W2PaDTKry2n3nHDSLlU05wCNcBGAsYHQ/w640-h205/2020-09-22_12-16-17.png" width="640" /></a></div><br /><div><br /></div><div><br /></div><div>Checking the property panel and the function takes FIVE parameters, not FOUR. As you can see, there’s an undocumented “bSetOnly” parameter. Presumably so that we can call SET_PROPERTY in place of SET_PROPERTY_ONLY and have it behave the same, although he who lives by the undocumented feature also dies by it, so make of that what you will. </div><div><br /></div><div>We modified our SET_PROPERTY to take five parameters and it was good.</div><div><br /></div><div>Except it wasn’t. It worked beautifully on single windows, but the moment that you swapped between MDI children or other dialogs, the buttons failed to reflect the current window until data changed. With hindsight this was a rookie mistake. Switching between windows doesn’t generate a SET_PROPERTY, it generates an ACTIVATED event.</div><div><br /></div><div>So back to square one. </div><div><br /></div><h2 style="text-align: left;">The NEXT Chosen Solution</h2><div>In a Windows based environment, all attempts to set a property will come from an event script context, but events also trigger when a window is activated. So, if we could intercept the running of an event, we could not only do our SAVEWARN property tests but we could react to a change of focus between windows, and remove the issue where doing so failed to update the buttons. The routine responsible for this is RUN_EVENT. </div><div><br /></div><div>We did some testing and established that RUN_EVENT is called about twice as often as SET_PROPERTY so as there wasn’t an order of magnitude difference we settled upon performing the same shelling trick with as before but with RUN_EVENT. And thereby we entered a world of pain.</div><div><br /></div><div><br /></div><h2 style="text-align: left;">A World of Pain, BFSs and Virtual MD Files</h2><div><div>The problem with the MD solution described above, is that, unlike in AREV, in OpenInsight the MD file has been made GLOBAL so any changes made in there will affect ALL users of ALL applications. </div><div><br /></div><div>We’re great believers in damage limitation, so we thought it’d be much nicer if this redirection only applied when we wanted it to. </div></div><div>So, we had a choice – we could create an application specific MD and add our pointer rows to that OR we could take advantage of another little tweak highlighted in SRP’s blog post. You see, they documented an area of labelled common utilised by RTP27 to store the file variable of the MD file. It essentially contains three variables, which for the sake of our program we referenced as follows:</div><div><br /></div><div>Common /RTP27COMMON/ mdFileHandle@, lastFileHandle@, mdHasBeenOpenedAlready@</div><div><br /></div><div>We knew that we weren’t actually using the MD file anywhere else in our application other than for this very specific redirection, so every time a new program is loaded, we’re wasting a disk read in trying to read the non-existent pointers for the programs that we’re trying to load. So we reasoned that if we could replace the MD file handle with a pointer to our own program, that recognised that it was being called, not to run an event, but to perform as a Base Filing System (BFS) – we could just return the pointer rows ourself and ignore disk reads for all else, thereby providing a small increase in performance overall. </div><div><br /></div><div>In theory this was simple, in practice it took a lot of getting right.</div><div><br /></div><div>The theory behind all file access in OpenInsight (and AREV) is that it is routed via a file handle. The file handle is made up of simply a multi-valued list of MFSs and BFSs, followed by a value mark then any BFS specific data required by the BFS to do its job. </div><div><br /></div><div>So, in the case of a normal OpenInsight file with no indexing this would be for example, </div><div><br /></div><div>RTP57²000000000062 MP_GPL\DATA\REV75001.LK</div><div><br /></div><div>for the same file with indexing it would be </div><div><br /></div><div>SI.MFS²RTP57²00036000000000093MP_GPL\DATA\REV75001.LK00051DICT.MFS...etc</div><div><br /></div><div>When an OpenInsight program tries to read using a file handle, the system calls the first program in the file handle (above RTP57 and SI.MFS respectively) passing it the code for the operation required along with the data needed to support the operation. The program then does what it needs to and returns information accordingly. </div><div><br /></div><div>In the first instance, our replacement RUN_EVENT code looked at the first parameter being passed, and if it was a number between 1 and 34 it assumed a BFS operation. If the operation was < 3 (so READ or READO) it would check if we were being asked for RUN_EVENT or RTI_RUN_EVENT, and if so return a structure that duplicated the MD entry. In all other cases, this returned a STATUS of FALSE$ indicating that the operation failed. We reasoned that this was safe to do as it would simply tell RTP27 to carry on to read from SYSOBJ.</div><div><br /></div><div>With our “virtual” MD file in place via calls to our replacement RUN_EVENT, testing could commence once more. And once again it failed. Our new MD pointers were being ignored, because RUN_EVENT was already in memory.</div><div><br /></div><h3 style="text-align: left;">A Little Bit On The Program Loader (RTP27)</h3><div>To explain the background behind this, when you first want to run a new program, the program loader – RTP27 – is invoked. It looks in the program stack to see if the program is already in memory, and if not if performs the following lookups (information provided by Revelation):</div><div><br /></div><div><span style="white-space: pre;"> </span>CTO Mode<span style="white-space: pre;"> <span> </span></span>MD->VOC->SYSOBJ</div><div><span style="white-space: pre;"> </span>AREV Mode<span style="white-space: pre;"> <span> </span></span>VOC->MD->SYSOBJ</div><div><span style="white-space: pre;"> </span>OpenInsight Mode<span style="white-space: pre;"> </span>MD->SYSOBJ-VOC</div><div><br /></div><div>When the object code is found it is loaded into the program array. All subsequent calls to load the program will find the program in the program array and use this object code without checking to see if any pointers, or even object code, have changed. </div><div><br /></div><div>As we want to modify the RUN_EVENT object code in the array , we need to replace what is already there, with our own modified code. </div><div><br /></div><div>The way in which we do this is EITHER to call RTP27 explicitly telling it to reload our two routines (RTI_RUN_EVENT and RUN_EVENT), or to issue a GARBAGECOLLECT which tells OpenInsight to drop everything in memory it doesn’t need and reload when requested. We tried both methods and settled on using RTP27 because using GARBAGECOLLECT on a start-up proc caused our OpenInsight to die!</div><div><br /></div><div>Armed with this new knowledge we were able to have our version of RUN_EVENT forward to the system RUN_EVENT and then check SAVEWARN and update the buttons accordingly. </div><div><br /></div><h2 style="text-align: left;">Baby Steps</h2><div>So, we added an INSTALL method to our RUN_EVENT replacement. It was a very straightforward piece of code:</div><div><br /></div><div><span> </span><span> </span>modifyMD:</div><div><span> </span><span> </span><span> </span><span> </span>mdFileHandle@<0, 1> = "ZZ_RUN_EVENT*PRACTICE_LOG" </div><div><span> </span><span> </span><span> </span><span> </span>call RTP27(“RTI_RUN_EVENT”)</div><div><span> </span><span> </span><span> </span><span> </span>call RTP27(“RUN_EVENT”)</div><div><span> </span><span> </span><span> </span><span> </span>retVal = 1</div><div><span> </span><span> </span>Return</div><div><br /></div><div>Now that the first value in the filehandle is the name of our RUN_EVENT replacement, when I/O operations are performed against the MD file, our program will be called to process it. </div><div><br /></div><div>We tested this by writing a small program that included the RTP27COMMON and tried to read rows from the “Virtual” MD file. It all worked as expected so we moved to the next stage. Testing it in real life.</div><div><br /></div><div>Invoking the System Monitor we installed our virtual MD table (by RUN ZZ_RUN_EVENT “INSTALL”) and we test ran the MP_MDI_MAIN window. To our delight, our program was invoked and behaved as expected. There were some minor glitches related to the actual business logic (see discussion later) but the proof of concept was a success.</div><div><br /></div><div>Buoyed by this, we sent Martyn a text file containing the program with instructions to compile it and to modify the CREATE event of the MDI form to call our install routine. We sat back and awaited the praise. </div><div><br /></div><div>Which was not forthcoming. </div><div><br /></div><div>Almost immediately the application started crashing in weird places in RUN_EVENT, referencing unassigned variables which clearly were assigned. It became apparent that something was going badly wrong. Yet it still continued to work fine on the development system.</div><div><br /></div><div>We were baffled, so we modified our copy of Martyn’s code to do the INSTALL call. Predictably our system now fell over. </div><div><br /></div><div>Thus began an infuriating round of logging, testing tweaking which achieved nothing other than frustration. Call the INSTALL from System Monitor, all good. Call from a CREATE event, abject failure. </div><div><br /></div><div>Finally, in a developer wide Teams chat, Carl made the (with hindsight obvious) observation, that if the object code for a program was in the returnStack (i.e. it's in use) then RTP27 should not be asked to reload the code. There would be pointers in memory to where the code is currently executing and modifying the object code would invalidate those pointers. </div><div><br /></div><div>When you’re in a CREATE event you are obviously inside RUN_EVENT so it shouldn’t be replaced in the array. When you’re in the System Monitor you’re not inside RUN_EVENT so it can be replaced. </div><div><br /></div><div>Knowing that the <a href="https://revdevx.com/2013/02/12/the-system-monitor-part-ii/" target="_blank">System Monitor can now be treated as an Object in the system</a>, we tried to programmatically run our INSTALL:</div><div><br /></div><div><span style="white-space: pre;"> </span>$systemMonitor->run( "ZZ_RUN_EVENT INSTALL" )</div><div><br /></div><div>but this didn’t have the desired effect. The engine was too busy processing our code to respond to the System Monitor. </div><div><br /></div><div>Then Aaron had the bright idea to run the install from the system Start-up Proc where it would not yet be in event context, et voilà – the pieces all fell into place – nearly.</div><div><br /></div><h2 style="text-align: left;">Code Coda</h2><div>The final twist was that something we were doing caused RTP27 to go into a recursive loop and abend OpenInsight. To cut a long story short, we replaced our virtual BFS as an MFS and logged all actions against the MD file. This led to a rewriting of the virtual BFS to return TRUE$ for three specific values and FALSE$ for all others and things finally worked as we expected them to.</div><div><br /></div><h2 style="text-align: left;">Business Logic</h2><div>So, with everything in place we now had to set about ensuring that our buttons were toggled as required in respect to the state of the current entry window. The buttons we were interested in were the save, the clear and the delete buttons. The save button was easy – is SAVEWARN set? If so, then enable the save button.</div><div><br /></div><div>The delete button was slightly more complicated. In AREV we would have just looked at WC_OREC% and if it was not empty, then the record could be deleted. (Stating the obvious you can’t delete a new row). Unfortunately, in this release, there is no such property. (Spoiler alert – Rev have added a new WINDOW property called NEWRECORD to the next version. Set to TRUE$ on the READ event if it's a new record, and reset to FALSE$ on a CLEAR and WRITE). </div><div><br /></div><div>The Window common variable origResultRow@ looked as though it had potential and we naively assumed that it would be of the structure RowID : @Fm : Row – and on simple windows we tested, it was indeed. But on more complex windows, sometimes the row id would appear in the middle of an otherwise blank origResultRow@. </div><div><br /></div><div>It transpired that origResultRow@ is ordered the same as controlMap@. Therefore, all we had to do to find out whether this was a new row, was to loop through the origResultRow@ variable, grabbing each value and if at the end we had a structure with a field mark it wasn’t a new row!</div><div><br /></div><div>Penultimately, we wanted to know when the Clear button could be enabled, and after experimentation we landed on using the rowLocks@ variable. If this contains a value then the system thinks it is displaying something (it is not set until you tab off the key prompt).</div><div><br /></div><div>The final piece of the jigsaw was acting on a close event – this initially didn’t work because all of our code happened after the system CLOSE event, so the window was no longer there to query. This was easily resolved by moving the GET_PROPERTIES we needed to before the RTI_RUN_EVENT.</div><div><br /></div><div>With all of these things taken into account, our solution was complete.</div><div><br /></div><div>The code is presented below as an exercise for the student 😊. </div><div><br /></div><h2 style="text-align: left;">The Final Program</h2><div><a href="https://revdevx.com/2016/06/17/blen-is-the-new-getbytesize/" target="_blank">With a reminder</a> as to why you should always use bLen in preference to Len...</div><div><br /></div>
2
<br /><div style="background-color: #fefefe; border: 1px solid rgb(115, 137, 174); color: black; font-family: Consolas, "Courier New", Courier, Verdana, Arial; font-size: 10pt; margin: 0px 10px auto; padding: 10px 20px; white-space: nowrap;"><span style="color: grey; font-family: Courier New, Courier, monospace;">0001 </span><span style="color: blue;">Function</span> zz_Run_Event<span style="color: purple;">(</span>appType<span style="color: purple;">,</span>controlID<span style="color: purple;">,</span>controlClass<span style="color: purple;">,</span>event<span style="color: purple;">,</span>arg1<span style="color: purple;">,</span><span style="color: purple;">.</span><span style="color: purple;">.</span><span style="color: purple;">.</span><span style="color: purple;"><</span>more<span style="color: purple;">></span><span style="color: purple;">)</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0002 </span> <span style="color: green; font-style: italic;">* Copyright (C) 2020 Sprezzatura. All Rights Reserved **</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0003 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0004 </span> <span style="color: blue;">Declare</span> <span style="color: blue;">Function</span> rti_Run_Event<span style="color: purple;">,</span> get_Property<span style="color: purple;">,</span> retStack<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0005 </span> <span style="color: blue;">$Insert</span> logical<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0006 </span> <span style="color: blue;">Common</span> <span style="color: purple;">/</span>RTP27COMMON<span style="color: purple;">/</span> mdFileHandle<span style="color: purple;">@</span><span style="color: purple;">,</span> lastFileHandle<span style="color: purple;">@</span><span style="color: purple;">,</span> mdOpenedAlready<span style="color: purple;">@</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0007 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0008 </span> <span style="color: blue;">if</span> <span style="color: blue;">assigned</span><span style="color: purple;">(</span> appType <span style="color: purple;">)</span> <span style="color: blue;">else</span> appType <span style="color: purple;">=</span> <span style="color: teal;">""</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0009 </span> <span style="color: blue;">if</span> <span style="color: blue;">assigned</span><span style="color: purple;">(</span> controlID <span style="color: purple;">)</span> <span style="color: blue;">else</span> controlID <span style="color: purple;">=</span> <span style="color: teal;">""</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0010 </span> <span style="color: blue;">if</span> <span style="color: blue;">assigned</span><span style="color: purple;">(</span> controlClass <span style="color: purple;">)</span> <span style="color: blue;">else</span> controlClass <span style="color: purple;">=</span> <span style="color: teal;">""</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0011 </span> <span style="color: blue;">if</span> <span style="color: blue;">assigned</span><span style="color: purple;">(</span> event <span style="color: purple;">)</span> <span style="color: blue;">else</span> event <span style="color: purple;">=</span> <span style="color: teal;">""</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0012 </span> <span style="color: blue;">if</span> <span style="color: blue;">assigned</span><span style="color: purple;">(</span> arg1 <span style="color: purple;">)</span> <span style="color: blue;">else</span> arg1 <span style="color: purple;">=</span> <span style="color: teal;">""</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0013 </span> <span style="color: blue;">if</span> <span style="color: blue;">assigned</span><span style="color: purple;">(</span> arg2 <span style="color: purple;">)</span> <span style="color: blue;">else</span> arg2 <span style="color: purple;">=</span> <span style="color: teal;">""</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0014 </span> <span style="color: blue;">if</span> <span style="color: blue;">assigned</span><span style="color: purple;">(</span> arg3 <span style="color: purple;">)</span> <span style="color: blue;">else</span> arg3 <span style="color: purple;">=</span> <span style="color: teal;">""</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0015 </span> <span style="color: blue;">if</span> <span style="color: blue;">assigned</span><span style="color: purple;">(</span> arg4 <span style="color: purple;">)</span> <span style="color: blue;">else</span> arg4 <span style="color: purple;">=</span> <span style="color: teal;">""</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0016 </span> <span style="color: blue;">if</span> <span style="color: blue;">assigned</span><span style="color: purple;">(</span> arg5 <span style="color: purple;">)</span> <span style="color: blue;">else</span> arg5 <span style="color: purple;">=</span> <span style="color: teal;">""</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0017 </span> <span style="color: blue;">if</span> <span style="color: blue;">assigned</span><span style="color: purple;">(</span> arg6 <span style="color: purple;">)</span> <span style="color: blue;">else</span> arg6 <span style="color: purple;">=</span> <span style="color: teal;">""</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0018 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0019 </span> <span style="color: blue;">equ</span> ON$ <span style="color: blue;">To</span> <span style="color: maroon;">1</span> <span style="color: purple;">;</span><span style="color: green; font-style: italic;">* Used to enable, or turn on buttons.</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0020 </span> <span style="color: blue;">equ</span> OFF$ <span style="color: blue;">To</span> <span style="color: maroon;">0</span> <span style="color: purple;">;</span><span style="color: green; font-style: italic;">* Used to disable, or turn off buttons.</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0021 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0022 </span> <span style="color: green; font-style: italic;">* install request/BFS Code, if not process as RUN_EVENT</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0023 </span> retVal <span style="color: purple;">=</span> TRUE$<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0024 </span> stack <span style="color: purple;">=</span> retStack<span style="color: purple;">(</span><span style="color: purple;">)</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0025 </span> <span style="color: blue;">if</span> stack<span style="color: purple;"><</span><span style="color: maroon;">2</span><span style="color: purple;">></span> <span style="color: purple;">=</span> <span style="color: teal;">"INITIALIZE"</span> <span style="color: blue;">then</span> appType <span style="color: purple;">=</span> <span style="color: teal;">"INSTALL"</span> <span style="color: purple;">;</span> <span style="color: green; font-style: italic;">*Startup Proc</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0026 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0027 </span> <span style="color: blue;">if</span> appType <span style="color: purple;">=</span> <span style="color: teal;">"INSTALL"</span> <span style="color: blue;">then</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0028 </span> <span style="color: blue;">goSub</span> modifyMD<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0029 </span> <span style="color: blue;">end</span> <span style="color: blue;">else</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0030 </span> <span style="color: blue;">if</span> <span style="color: blue;">num</span><span style="color: purple;">(</span> appType <span style="color: purple;">)</span> <span style="color: blue;">and</span> appType <span style="color: purple;">#</span> <span style="color: teal;">""</span> <span style="color: blue;">then</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0031 </span> <span style="color: blue;">if</span> appType <span style="color: purple;">></span><span style="color: purple;">=</span> <span style="color: maroon;">1</span> <span style="color: blue;">then</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0032 </span> <span style="color: blue;">if</span> appType <span style="color: purple;"><</span><span style="color: purple;">=</span> <span style="color: maroon;">34</span> <span style="color: blue;">then</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0033 </span> <span style="color: blue;">goSub</span> pretendToBeBFS<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0034 </span> <span style="color: blue;">end</span> <span style="color: blue;">else</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0035 </span> <span style="color: green; font-style: italic;">* if the BFS definition is extended to use higher numbers </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0036 </span> <span style="color: green; font-style: italic;">* react appropriately here</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0037 </span> <span style="color: blue;">end</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0038 </span> <span style="color: blue;">end</span> <span style="color: blue;">else</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0039 </span> <span style="color: green; font-style: italic;">* if the BFS definition is extended to use lower numbers </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0040 </span> <span style="color: green; font-style: italic;">* react appropriately here</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0041 </span> <span style="color: blue;">end</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0042 </span> <span style="color: blue;">end</span> <span style="color: blue;">else</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0043 </span> winID <span style="color: purple;">=</span> controlID<span style="color: purple;">[</span><span style="color: maroon;">1</span><span style="color: purple;">,</span> <span style="color: teal;">"."</span><span style="color: purple;">]</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0044 </span> objxArray2 <span style="color: purple;">=</span> winId<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0045 </span> propArray2 <span style="color: purple;">=</span> <span style="color: teal;">"SAVEWARN"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0046 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0047 </span> objxArray2 <span style="color: purple;">:</span><span style="color: purple;">=</span> <span style="color: #8000ff;">@Rm</span> <span style="color: purple;">:</span> winID<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0048 </span> propArray2 <span style="color: purple;">:</span><span style="color: purple;">=</span> <span style="color: #8000ff;">@Rm</span> <span style="color: purple;">:</span> <span style="color: teal;">"MDIFRAME"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0049 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0050 </span> dataArray2 <span style="color: purple;">=</span> Get_Property<span style="color: purple;">(</span> objxArray2<span style="color: purple;">,</span> propArray2 <span style="color: purple;">)</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0051 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0052 </span> bSaveWarn <span style="color: purple;">=</span> dataArray2<span style="color: purple;">[</span> <span style="color: maroon;">1</span><span style="color: purple;">,</span> <span style="color: #8000ff;">@Rm</span> <span style="color: purple;">]</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0053 </span> mdiFrame <span style="color: purple;">=</span> dataArray2<span style="color: purple;">[</span> <span style="color: blue;">bCol2</span><span style="color: purple;">(</span><span style="color: purple;">)</span> <span style="color: purple;">+</span> <span style="color: maroon;">1</span><span style="color: purple;">,</span> <span style="color: #8000ff;">@Rm</span> <span style="color: purple;">]</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0054 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0055 </span> <span style="color: blue;">$Insert</span> OIWIN_COMM_INIT<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0056 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0057 </span> lenOldRow <span style="color: purple;">=</span> <span style="color: blue;">bLen</span><span style="color: purple;">(</span> origResultRow<span style="color: purple;">@</span> <span style="color: purple;">)</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0058 </span> oldRow <span style="color: purple;">=</span> origResultRow<span style="color: purple;">@</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0059 </span> rowLocks <span style="color: purple;">=</span> rowLocks<span style="color: purple;">@</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0060 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0061 </span> retVal <span style="color: purple;">=</span> RTI_Run_Event<span style="color: purple;">(</span>appType<span style="color: purple;">,</span>controlID<span style="color: purple;">,</span>controlClass<span style="color: purple;">,</span><span style="color: purple;">.</span><span style="color: purple;">.</span><span style="color: purple;">.</span><span style="color: purple;"><</span>more<span style="color: purple;">></span><span style="color: purple;">)</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0062 </span> <span style="color: blue;">end</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0063 </span> <span style="color: blue;">end</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0064 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0065 </span> <span style="color: blue;">if</span> event <span style="color: purple;">=</span> <span style="color: teal;">"TIMER"</span> <span style="color: blue;">else</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0066 </span> <span style="color: blue;">if</span> controlId<span style="color: purple;">[</span><span style="color: maroon;">1</span><span style="color: purple;">,</span> <span style="color: maroon;">3</span><span style="color: purple;">]</span> <span style="color: purple;">=</span> <span style="color: teal;">"MP_"</span> <span style="color: blue;">and</span> controlId<span style="color: purple;">[</span> <span style="color: maroon;">3</span><span style="color: purple;">,</span> <span style="color: maroon;">5</span> <span style="color: purple;">]</span> <span style="color: purple;">!</span><span style="color: purple;">=</span> <span style="color: teal;">"_MDI_"</span> <span style="color: blue;">then</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0067 </span> <span style="color: green; font-style: italic;">* only react to Martyn's windows, except for the MDI Frame</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0068 </span> <span style="color: blue;">if</span> event _eqc <span style="color: teal;">"CLOSE"</span> <span style="color: blue;">then</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0069 </span> <span style="color: green; font-style: italic;">* disable all three buttons, the activated </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0070 </span> <span style="color: green; font-style: italic;">* on the next window will set accordingly if there</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0071 </span> dataArray2 <span style="color: purple;">=</span> OFF$ <span style="color: purple;">:</span> <span style="color: #8000ff;">@Rm</span> <span style="color: purple;">:</span> OFF$ <span style="color: purple;">:</span> <span style="color: #8000ff;">@Rm</span> <span style="color: purple;">:</span> OFF$<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0072 </span> <span style="color: blue;">end</span> <span style="color: blue;">else</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0073 </span> <span style="color: green; font-style: italic;">* Check whether there was a previous row</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0074 </span> ptr <span style="color: purple;">=</span> <span style="color: maroon;">1</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0075 </span> stripped <span style="color: purple;">=</span> <span style="color: teal;">""</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0076 </span> <span style="color: blue;">loop</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0077 </span> nextField <span style="color: purple;">=</span> oldRow<span style="color: purple;">[</span> ptr<span style="color: purple;">,</span> <span style="color: #8000ff;">@Fm</span><span style="color: purple;">,</span> TRUE$ <span style="color: purple;">]</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0078 </span> <span style="color: blue;">while</span> ptr <span style="color: purple;"><</span><span style="color: purple;">=</span> blen<span style="color: purple;">(</span> oldRow <span style="color: purple;">)</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0079 </span> <span style="color: green; font-style: italic;">/*<br /></span><span style="color: grey; font-family: Courier New, Courier, monospace;">0080 </span><span style="color: green; font-style: italic;"> Fun "easter egg" for those who read comments. <br /></span><span style="color: grey; font-family: Courier New, Courier, monospace;">0081 </span><span style="color: green; font-style: italic;"> When evaluating the blen (or the len of an ANSI string) <br /></span><span style="color: grey; font-family: Courier New, Courier, monospace;">0082 </span><span style="color: green; font-style: italic;"> the string length is stored in the descripter so it <br /></span><span style="color: grey; font-family: Courier New, Courier, monospace;">0083 </span><span style="color: green; font-style: italic;"> does not have to be calculated each time. It's arguable <br /></span><span style="color: grey; font-family: Courier New, Courier, monospace;">0084 </span><span style="color: green; font-style: italic;"> that this might be faster than assigning to a variable <br /></span><span style="color: grey; font-family: Courier New, Courier, monospace;">0085 </span><span style="color: green; font-style: italic;"> then using that variable<br /></span><span style="color: grey; font-family: Courier New, Courier, monospace;">0086 </span><span style="color: green; font-style: italic;"> */</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0087 </span> ptr <span style="color: purple;">=</span> <span style="color: blue;">bcol2</span><span style="color: purple;">(</span><span style="color: purple;">)</span> <span style="color: purple;">+</span> <span style="color: maroon;">1</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0088 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0089 </span> <span style="color: blue;">if</span> <span style="color: blue;">len</span><span style="color: purple;">(</span> nextField <span style="color: purple;">)</span> <span style="color: blue;">then</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0090 </span> stripped <span style="color: purple;">:</span><span style="color: purple;">=</span> nextField <span style="color: purple;">:</span> <span style="color: #8000ff;">@Fm</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0091 </span> <span style="color: blue;">end</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0092 </span> <span style="color: blue;">repeat</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0093 </span> stripped<span style="color: purple;">[</span> <span style="color: purple;">-</span><span style="color: maroon;">1</span><span style="color: purple;">,</span> <span style="color: maroon;">1</span> <span style="color: purple;">]</span> <span style="color: purple;">=</span> <span style="color: teal;">""</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0094 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0095 </span> bExistingRec <span style="color: purple;">=</span> <span style="color: purple;">(</span><span style="color: blue;">index</span><span style="color: purple;">(</span> stripped<span style="color: purple;">,</span> <span style="color: #8000ff;">@Fm</span> <span style="color: purple;">,</span> <span style="color: maroon;">1</span> <span style="color: purple;">)</span> <span style="color: purple;">></span> <span style="color: maroon;">0</span><span style="color: purple;">)</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0096 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0097 </span> dataArray2 <span style="color: purple;">=</span> bSaveWarn <span style="color: purple;">;</span> <span style="color: green; font-style: italic;">* save button</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0098 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0099 </span> <span style="color: blue;">if</span> <span style="color: blue;">len</span><span style="color: purple;">(</span> rowLocks <span style="color: purple;">)</span> <span style="color: blue;">then</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0100 </span> dataArray2 <span style="color: purple;">:</span><span style="color: purple;">=</span> <span style="color: #8000ff;">@Rm</span> <span style="color: purple;">:</span> ON$ <span style="color: purple;">;</span> <span style="color: green; font-style: italic;">* Clear button</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0101 </span> <span style="color: blue;">end</span> <span style="color: blue;">else</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0102 </span> dataArray2 <span style="color: purple;">:</span><span style="color: purple;">=</span> <span style="color: #8000ff;">@Rm</span> <span style="color: purple;">:</span> OFF$ <span style="color: purple;">;</span> <span style="color: green; font-style: italic;">* Clear button</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0103 </span> <span style="color: blue;">end</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0104 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0105 </span> dataArray2 <span style="color: purple;">:</span><span style="color: purple;">=</span> <span style="color: #8000ff;">@Rm</span> <span style="color: purple;">:</span> bExistingRec <span style="color: purple;">;</span> <span style="color: green; font-style: italic;">* delete button</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0106 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0107 </span> <span style="color: blue;">end</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0108 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0109 </span> targetWindow <span style="color: purple;">=</span> <span style="color: blue;">if</span> <span style="color: blue;">len</span><span style="color: purple;">(</span>mdiFrame<span style="color: purple;">)</span> <span style="color: blue;">then</span> mdiFrame <span style="color: blue;">else</span> winId<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0110 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0111 </span> objxArray2 <span style="color: purple;">=</span> targetWindow <span style="color: purple;">:</span> <span style="color: teal;">".BTN_SAVE"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0112 </span> propArray2 <span style="color: purple;">=</span> <span style="color: teal;">"ENABLED"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0113 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0114 </span> objxArray2 <span style="color: purple;">:</span><span style="color: purple;">=</span> <span style="color: #8000ff;">@Rm</span> <span style="color: purple;">:</span> targetWindow <span style="color: purple;">:</span> <span style="color: teal;">".BTN_CLEAR"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0115 </span> propArray2 <span style="color: purple;">:</span><span style="color: purple;">=</span> <span style="color: #8000ff;">@Rm</span> <span style="color: purple;">:</span> <span style="color: teal;">"ENABLED"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0116 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0117 </span> objxArray2 <span style="color: purple;">:</span><span style="color: purple;">=</span> <span style="color: #8000ff;">@Rm</span> <span style="color: purple;">:</span> targetWindow <span style="color: purple;">:</span> <span style="color: teal;">".BTN_DELETE"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0118 </span> propArray2 <span style="color: purple;">:</span><span style="color: purple;">=</span> <span style="color: #8000ff;">@Rm</span> <span style="color: purple;">:</span> <span style="color: teal;">"ENABLED"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0119 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0120 </span> objxArray2 <span style="color: purple;">:</span><span style="color: purple;">=</span> <span style="color: #8000ff;">@Rm</span> <span style="color: purple;">:</span> targetWindow <span style="color: purple;">:</span> <span style="color: teal;">".MENU.FILE.SAVE_ROW"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0121 </span> propArray2 <span style="color: purple;">:</span><span style="color: purple;">=</span> <span style="color: #8000ff;">@Rm</span> <span style="color: purple;">:</span> <span style="color: teal;">"ENABLED"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0122 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0123 </span> objxArray2 <span style="color: purple;">:</span><span style="color: purple;">=</span> <span style="color: #8000ff;">@Rm</span> <span style="color: purple;">:</span> targetWindow <span style="color: purple;">:</span> <span style="color: teal;">".MENU.FILE.CLEAR_FORM"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0124 </span> propArray2 <span style="color: purple;">:</span><span style="color: purple;">=</span> <span style="color: #8000ff;">@Rm</span> <span style="color: purple;">:</span> <span style="color: teal;">"ENABLED"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0125 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0126 </span> objxArray2 <span style="color: purple;">:</span><span style="color: purple;">=</span> <span style="color: #8000ff;">@Rm</span> <span style="color: purple;">:</span> targetWindow <span style="color: purple;">:</span> <span style="color: teal;">".MENU.FILE.DELETE_ROW"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0127 </span> propArray2 <span style="color: purple;">:</span><span style="color: purple;">=</span> <span style="color: #8000ff;">@Rm</span> <span style="color: purple;">:</span> <span style="color: teal;">"ENABLED"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0128 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0129 </span> dataArray2 <span style="color: purple;">:</span><span style="color: purple;">=</span> <span style="color: #8000ff;">@Rm</span> <span style="color: purple;">:</span> dataArray2<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0130 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0131 </span> <span style="color: blue;">call</span> set_Property<span style="color: purple;">(</span> objxArray2<span style="color: purple;">,</span> propArray2<span style="color: purple;">,</span> dataArray2 <span style="color: purple;">)</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0132 </span> <span style="color: blue;">end</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0133 </span> <span style="color: blue;">end</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0134 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0135 </span><span style="color: blue;">return</span> retVal<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0136 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0137 </span><span style="font-size: 11pt; font-weight: bold;">modifyMD:</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0138 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0139 </span> mdFileHandle<span style="color: purple;">@</span><span style="color: purple;"><</span><span style="color: maroon;">0</span><span style="color: purple;">,</span> <span style="color: maroon;">1</span><span style="color: purple;">></span> <span style="color: purple;">=</span> <span style="color: teal;">"ZZ_RUN_EVENT*PRACTICE_LOG"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0140 </span> <span style="color: blue;">call</span> rtp27<span style="color: purple;">(</span><span style="color: teal;">"RTI_RUN_EVENT"</span><span style="color: purple;">)</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0141 </span> <span style="color: blue;">call</span> rtp27<span style="color: purple;">(</span><span style="color: teal;">"RUN_EVENT"</span><span style="color: purple;">)</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0142 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0143 </span><span style="color: blue;">return</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0144 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0145 </span><span style="font-size: 11pt; font-weight: bold;">pretendToBeBFS:</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0146 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0147 </span> <span style="color: blue;">locate</span> appType <span style="color: blue;">In</span> <span style="color: teal;">"20,21,22"</span> <span style="color: blue;">using</span> <span style="color: teal;">","</span> <span style="color: blue;">setting</span> gotIt <span style="color: blue;">then</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0148 </span> arg3 <span style="color: purple;">=</span> TRUE$<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0149 </span> <span style="color: blue;">end</span> <span style="color: blue;">else</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0150 </span> arg3 <span style="color: purple;">=</span> FALSE$<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0151 </span> <span style="color: blue;">if</span> appType <span style="color: purple;"><</span> <span style="color: maroon;">3</span> <span style="color: blue;">then</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0152 </span> <span style="color: green; font-style: italic;">/*<br /></span><span style="color: grey; font-family: Courier New, Courier, monospace;">0153 </span><span style="color: green; font-style: italic;"> READ or READO<br /></span><span style="color: grey; font-family: Courier New, Courier, monospace;">0154 </span><span style="color: green; font-style: italic;"> */</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0155 </span> arg2 <span style="color: purple;">=</span> <span style="color: teal;">"RBASIC"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0156 </span> arg2 <span style="color: purple;">:</span><span style="color: purple;">=</span> <span style="color: #8000ff;">@Fm</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0157 </span> arg2 <span style="color: purple;">:</span><span style="color: purple;">=</span> <span style="color: #8000ff;">@Fm</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0158 </span> arg2 <span style="color: purple;">:</span><span style="color: purple;">=</span> <span style="color: teal;">"SYSOBJ"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0159 </span> arg2 <span style="color: purple;">:</span><span style="color: purple;">=</span> <span style="color: #8000ff;">@Fm</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0160 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0161 </span> <span style="color: blue;">begin</span> <span style="color: blue;">case</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0162 </span> <span style="color: blue;">case</span> event <span style="color: purple;">=</span> <span style="color: teal;">"RUN_EVENT"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0163 </span> arg2 <span style="color: purple;">:</span><span style="color: purple;">=</span> <span style="color: teal;">"ZZ_RUN_EVENT*PRACTICE_LOG"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0164 </span> arg3 <span style="color: purple;">=</span> TRUE$<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0165 </span> <span style="color: blue;">case</span> event <span style="color: purple;">=</span> <span style="color: teal;">"RTI_RUN_EVENT"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0166 </span> arg2 <span style="color: purple;">:</span><span style="color: purple;">=</span> <span style="color: teal;">"RUN_EVENT"</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0167 </span> arg3 <span style="color: purple;">=</span> TRUE$<br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0168 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0169 </span> <span style="color: blue;">end</span> <span style="color: blue;">case</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0170 </span> <span style="color: blue;">end</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0171 </span> <span style="color: blue;">end</span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0172 </span><br /><span style="color: grey; font-family: Courier New, Courier, monospace;">0173 </span><span style="color: blue;">return</span><br /></div>
Post settings
Labels
No matching suggestions
Published on
22/09/2020 16:58
Permalink
Location
Options
Sprezzhttp://www.blogger.com/profile/08866141305592910267noreply@blogger.com2tag:blogger.com,1999:blog-2607884204445547877.post-57380811104421018432020-07-14T16:19:00.002+01:002020-07-14T16:19:13.234+01:00Query By Form (QBF) revisitedWhilst working with an internal project it became apparent that, much to our surprise, the existing documentation for QBF is partial at best. We've used QBF to good effect in the past so it seems a shame not to have the full glory of this useful feature exposed, so we thought we'd write a quick exposé - it seemed appropriate.<br />
<br />
QBF is simply a method to use an existing entry form as the template for a lookup query on data contained in that table. You simply initialise the query, execute it, then browse the resultant data set using the appropriate commands. There are operators to filter the result set, sort the result set and even customise the query that is to be executed before it is run.<br />
<br />
The QBF commands can be found on the MDI frame under QBF:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-9vK1ZYHF9DM/XvM1YlZ5bKI/AAAAAAAAAp0/1v_5YtX8Wbsb8S8EiaqPP1J5caGa8vAlwCPcBGAYYCw/s1600/2020-06-24_12-06-53.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="677" data-original-width="964" height="224" src="https://1.bp.blogspot.com/-9vK1ZYHF9DM/XvM1YlZ5bKI/AAAAAAAAAp0/1v_5YtX8Wbsb8S8EiaqPP1J5caGa8vAlwCPcBGAYYCw/s320/2020-06-24_12-06-53.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
So, for example, say we wanted to use the CUSTOMERS screen to find all customers in California, we could initialise QBF then enter "=CA" in the STATE editline<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-uvlySezUcjY/XvM6qWDFV-I/AAAAAAAAAqM/Q9S2dhiMT8E3jkNWKxeab1bdCNua4zduACPcBGAYYCw/s1600/2020-06-24_12-34-19.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="351" data-original-width="620" height="181" src="https://1.bp.blogspot.com/-uvlySezUcjY/XvM6qWDFV-I/AAAAAAAAAqM/Q9S2dhiMT8E3jkNWKxeab1bdCNua4zduACPcBGAYYCw/s320/2020-06-24_12-34-19.jpg" width="320" /></a></div>
<br />
and execute the query, resulting in a browse list of the 8 Customers in the Customers table who were based in California.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-uAu-u4zl3hw/XvM7ZxQtshI/AAAAAAAAAqU/oytdaU9nRKsKqyP87LFa8vc30o6l2InbQCPcBGAYYCw/s1600/2020-06-24_12-38-29.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="351" data-original-width="620" height="181" src="https://1.bp.blogspot.com/-uAu-u4zl3hw/XvM7ZxQtshI/AAAAAAAAAqU/oytdaU9nRKsKqyP87LFa8vc30o6l2InbQCPcBGAYYCw/s320/2020-06-24_12-38-29.jpg" width="320" /></a></div>
<br />
The operators are outlined below :-<br />
<br />
<br />
<style type="text/css">
.Table
{
display: table;
}
.Title
{
display: table-caption;
text-align: center;
font-weight: bold;
font-size: larger;
}
.Heading
{
display: table-row;
font-weight: bold;
text-align: center;
}
.Row
{
display: table-row;
}
.Cell
{
display: table-cell;
border: solid;
border-width: thin;
padding-left: 5px;
padding-right: 5px;
}
</style>
<br />
<div class="Table">
<div class="Title">
QBF Operators</div>
<div class="Heading">
<div class="Cell">
Operator</div>
<div class="Cell">
Keystroke(s)</div>
<div class="Cell">
Usage</div>
</div>
<div class="Row">
<div class="Cell">
EQUALS</div>
<div class="Cell">
=</div>
<div class="Cell">
"=CA" - returns all rows where the column is CA.<br />
Note that "=" is the default operator so we could also just use "CA"</div>
</div>
<div class="Row">
<div class="Cell">
NOT EQUALS</div>
<div class="Cell">
#</div>
<div class="Cell">
"#CA" - returns all rows where the column is not CA.<br />
Note that this operator can be combined with other operators. For example to find rows where the column is not ending "Ltd" use "#[Ltd"</div>
</div>
<div class="Row">
<div class="Cell">
GREATER THAN</div>
<div class="Cell">
">"</div>
<div class="Cell">
"> 10000" - returns all rows where the column is greater than 10000.</div>
</div>
<div class="Row">
<div class="Cell">
GREATER THAN OR EQUAL TO</div>
<div class="Cell">
">="</div>
<div class="Cell">
">= 10000" - returns all rows where the column is greater than or equal to 10000.</div>
</div>
<div class="Row">
<div class="Cell">
LESS THAN</div>
<div class="Cell">
"<"</div>
<div class="Cell">
"< 10000" - returns all rows where the column is less than 10000.</div>
</div>
<div class="Row">
<div class="Cell">
LESS THAN OR EQUAL TO</div>
<div class="Cell">
"<="</div>
<div class="Cell">
"<= 10000" - returns all rows where the column is less than or equal to 10000.</div>
</div>
<div class="Row">
<div class="Cell">
STARTING</div>
<div class="Cell">
"]"</div>
<div class="Cell">
"]Sky" - returns all rows where the column starts with "Sky".</div>
</div>
<div class="Row">
<div class="Cell">
ENDING</div>
<div class="Cell">
"["</div>
<div class="Cell">
"[Soft" - returns all rows where the column ends with "soft".</div>
</div>
<div class="Row">
<div class="Cell">
CONTAINING</div>
<div class="Cell">
"[]"</div>
<div class="Cell">
"[]BLUE" - returns all rows where the column contains "blue".</div>
</div>
<div class="Row">
<div class="Cell">
FROM/TO</div>
<div class="Cell">
"..."</div>
<div class="Cell">
"2000...4000" - returns all rows where the column is from 2000 to 4000. <br />
Note that there is no BETWEEN operator".</div>
</div>
<div class="Row">
<div class="Cell">
OR</div>
<div class="Cell">
";"</div>
<div class="Cell">
"GA;CA" - returns all rows where the column is either GA or CA".</div>
</div>
<div class="Row">
<div class="Cell">
Debug/Alter Query</div>
<div class="Cell">
"?"</div>
<div class="Cell">
"?" - shows the query statement that will be executed in an editable message so that you can see what is about to happen, and more importantly, modify the statement before execution.<br />
This is especially useful when a query is not returning the expected results For example selecting "United Kingdom" from a drop down list would fail to return the correct values. Using ? allows us to see that the query has only taken the first word because the string is not quoted, so it looks for "WITH COUNTRY = "United".</div>
</div>
<div class="Row">
<div class="Cell">
ORDER BY</div>
<div class="Cell">
"BY"</div>
<div class="Cell">
"BY" - returns all rows sorted by the column with the "BY".</div>
</div>
<div class="Row">
<div class="Cell">
MULTI ORDER SORT</div>
<div class="Cell">
"BY<b>n</b>"</div>
<div class="Cell">
"BYn" - returns all rows sorted in the order of columns specified. So if "BY1", "BY2" and "BY3" are specified, the sort will proceed on column 1, then 2 then 3.<br />
Note, this order does not have to match the order of prompts on the screen</div>
</div>
<div class="Row">
<div class="Cell">
ORDER BY SPECIFIC COLUMN</div>
<div class="Cell">
"BY aaaaaa"</div>
<div class="Cell">
"BY STATE" - returns all rows sorted by the column specified, in this case STATE.<br />
This is especially useful when you want to have a comparison operator against a column that you also wish to order by.</div>
</div>
</div>
<br />
For example, say we want to sort all Customers in states beginning with "N" by State<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-i3WJI088c_k/XwSUbASIr6I/AAAAAAAAAwQ/cpugetMNuFMPWKRRgtOpRRM_FHeGeKnbQCNcBGAsYHQ/s1600/2020-07-07_16-26-08.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="351" data-original-width="620" height="181" src="https://1.bp.blogspot.com/-i3WJI088c_k/XwSUbASIr6I/AAAAAAAAAwQ/cpugetMNuFMPWKRRgtOpRRM_FHeGeKnbQCNcBGAsYHQ/s320/2020-07-07_16-26-08.jpg" width="320" /></a></div>
<br />
we'd get<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-1iQGdOrFOcc/XwSU9It0ZHI/AAAAAAAAAwY/fgtLQwIkcsUQPT7xaOW9lWFyfpWv8Qi6wCNcBGAsYHQ/s1600/2020-07-07_16-29-34.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="443" data-original-width="971" height="145" src="https://1.bp.blogspot.com/-1iQGdOrFOcc/XwSU9It0ZHI/AAAAAAAAAwY/fgtLQwIkcsUQPT7xaOW9lWFyfpWv8Qi6wCNcBGAsYHQ/s320/2020-07-07_16-29-34.jpg" width="320" /></a></div>
<br />
<br />
<br />
Note that the OR operator can also be used to OR between different columns - by default they will be ANDed. So "=CA" in the STATE column and "[]Soft" in the NAME column would look for all Customers in CA with "Soft" in their name. By comparison "=CA" in the STATE column and ";[]Soft" in the NAME column would look for all Customers in CA or all with "Soft" in their name.
<br />
<br />
Please note that some of the features described above will only work in versions of OI above 10.0.7.Sprezzhttp://www.blogger.com/profile/08866141305592910267noreply@blogger.com0tag:blogger.com,1999:blog-2607884204445547877.post-8371576478016190332020-05-12T16:15:00.000+01:002020-05-12T16:21:30.393+01:00Extending Our PromotionOur last blog article dealt with promoting a help event so that dictionary help could be displayed when the user pressed F1 on a prompt. This was well received<i> but</i> it was pointed out that the technique crashed and burned when used from a multi-column edit table.<br />
<br />
The reason for this is obvious - if an edit table has more than one column then it will logically also have more than one data dictionary item associated with it. So we need to determine which edit table column we are currently on and use this information to determine the correct dictionary item to use.<br />
<br />
When we ask for the COLUMN property of an edit table, what we are provided with is a sub-value mark delimited array of all of the columns in the edit table. (The reason for this using such an unusual delimiter is simply that the columns property is derived from a larger array maintained by the system behind the scenes - the "control semantics"). Then to establish what column we're currently on we simply get the DEFPOSPROP property. (We could just get the CARETPOS property - but having been bitten once by not considering all possible permutations, we're now allowing for the possibility that a custom OLE control (which supports multiple columns) might not expose the current column using CARETPOS. So we use DEFPOSPROP which will always return the current column position regardless of how it is exposed. This assumes that the OLE control has been configured correctly using the New OLE Entity window described <span style="color: #000120;"><a href="https://revdevx.com/2013/11/20/ole-control-integration/" target="_blank">in this blog entry</a>).</span><br />
<span style="color: #000120;"><br /></span>
<span style="color: #000120;">So without further ado we present the revised promoted event script!</span><br />
<br />
<br />
<div style="background-color: #fefefe; border: 1px solid #7389ae; color: black; font-family: "consolas" , "courier new" , "courier" , "verdana" , "arial"; font-size: 10pt; margin: 0px 10px auto; padding: 10px 20px; white-space: nowrap;">
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0001 </span> <span style="color: blue;">$Insert</span> DICT_EQUATES<br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0002 </span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0003 </span> <span style="color: green; font-style: italic;">! table = @ctrlEntId->table</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0004 </span> <span style="color: green; font-style: italic;">! column = @ctrlEntId->column</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0005 </span> table <span style="color: purple;">=</span> Get_Property<span style="color: purple;">(</span> ctrlEntId<span style="color: purple;">,</span> <span style="color: teal;">"TABLE"</span> <span style="color: purple;">)</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0006 </span> column <span style="color: purple;">=</span> Get_Property<span style="color: purple;">(</span> ctrlEntId<span style="color: purple;">,</span> <span style="color: teal;">"COLUMN"</span> <span style="color: purple;">)</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0007 </span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0008 </span> <span style="color: blue;">If</span> <span style="color: blue;">Index</span><span style="color: purple;">(</span> column<span style="color: purple;">,</span> <span style="color: #8000ff;">@Svm</span><span style="color: purple;">,</span> <span style="color: maroon;">1</span> <span style="color: purple;">)</span> <span style="color: blue;">Then</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0009 </span> <span style="color: green; font-style: italic;">/*</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0010 </span><span style="color: green; font-style: italic;"> This is an edittable so we need to get the column</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0011 </span><span style="color: green; font-style: italic;"> currently selected</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0012 </span><span style="color: green; font-style: italic;"> */</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0013 </span> <br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0014 </span> <span style="color: green; font-style: italic;">! currentPos = @ctrlEntId->defposprop< 1 ></span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0015 </span> currentPos <span style="color: purple;">=</span> Get_Property<span style="color: purple;">(</span> ctrlEntId<span style="color: purple;">,</span> <span style="color: teal;">"DEFPOSPROP"</span> <span style="color: purple;">)</span><span style="color: purple;"><</span> <span style="color: maroon;">1</span> <span style="color: purple;">></span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0016 </span> <span style="color: blue;">If</span> currentPos <span style="color: purple;">></span><span style="color: purple;">=</span> <span style="color: maroon;">1</span> <span style="color: blue;">then</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0017 </span> column <span style="color: purple;">=</span> column<span style="color: purple;"><</span><span style="color: maroon;">0</span><span style="color: purple;">,</span> <span style="color: maroon;">0</span><span style="color: purple;">,</span> currentPos <span style="color: purple;">></span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0018 </span> <span style="color: blue;">End</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0019 </span> <span style="color: blue;">End</span> <span style="color: blue;">Else</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0020 </span> currentPos <span style="color: purple;">=</span> <span style="color: maroon;">1</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0021 </span> <span style="color: blue;">end</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0022 </span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0023 </span> <span style="color: green; font-style: italic;">/*</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0024 </span><span style="color: green; font-style: italic;"> have we already read the help? If so then </span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0025 </span><span style="color: green; font-style: italic;"> just retrieve the cached version using a custom</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0026 </span><span style="color: green; font-style: italic;"> property (defined by using any word with an @ </span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0027 </span><span style="color: green; font-style: italic;"> at the beginning)</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0028 </span><span style="color: green; font-style: italic;"> */</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0029 </span> <br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0030 </span> <span style="color: green; font-style: italic;">! helpText = @ctrlEntId->$@HelpText< currentPos ></span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0031 </span> fullHelpText <span style="color: purple;">=</span> Get_Property<span style="color: purple;">(</span> ctrlEntId<span style="color: purple;">,</span> <span style="color: teal;">"@HELPTEXT"</span> <span style="color: purple;">)</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0032 </span> helpText <span style="color: purple;">=</span> fullHelpText<span style="color: purple;"><</span> currentPos <span style="color: purple;">></span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0033 </span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0034 </span> <span style="color: blue;">If</span> helpText <span style="color: blue;">else</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0035 </span> helpText <span style="color: purple;">=</span> <span style="color: blue;">Xlate</span><span style="color: purple;">(</span><span style="color: teal;">"DICT."</span> <span style="color: purple;">:</span> table<span style="color: purple;">,</span> column<span style="color: purple;">,</span> DICT_DESC$<span style="color: purple;">,</span> <span style="color: teal;">"X"</span><span style="color: purple;">)</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0036 </span> fullHelpText<span style="color: purple;"><</span> currentPos <span style="color: purple;">></span> <span style="color: purple;">=</span> helpText<br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0037 </span> <span style="color: green; font-style: italic;">! @ctrlEntId->$@HelpText = helpText</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0038 </span> <span style="color: blue;">call</span> set_Property_Only<span style="color: purple;">(</span> ctrlEntId<span style="color: purple;">,</span> <span style="color: teal;">"@HELPTEXT"</span><span style="color: purple;">,</span> fullHelpText <span style="color: purple;">)</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0039 </span> <span style="color: blue;">End</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0040 </span> <br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0041 </span> <span style="color: blue;">If</span> <span style="color: blue;">Len</span><span style="color: purple;">(</span> helpText <span style="color: purple;">)</span> <span style="color: blue;">Else</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0042 </span> helpText <span style="color: purple;">=</span> <span style="color: teal;">"No dictionary help has been entered for column "</span> <span style="color: purple;">:</span> column<br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0043 </span> <span style="color: blue;">End</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0044 </span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0045 </span> msgDef <span style="color: purple;">=</span> helpText<br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0046 </span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0047 </span> <span style="color: blue;">call</span> Msg<span style="color: purple;">(</span> <span style="color: #8000ff;">@Window</span><span style="color: purple;">,</span> msgDef<span style="color: purple;">,</span> <span style="color: teal;">"ZZ_HELP"</span> <span style="color: purple;">)</span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0048 </span><br />
<span style="color: grey; font-family: "courier new" , "courier" , monospace;">0049 </span><span style="color: blue;">return</span> <span style="color: maroon;">0</span></div>
Sprezzhttp://www.blogger.com/profile/08866141305592910267noreply@blogger.com0tag:blogger.com,1999:blog-2607884204445547877.post-41378958433028746672020-05-06T11:48:00.001+01:002020-06-12T15:42:29.056+01:00Promoting a new OI 10 feature. TECHNIQUES DESCRIBED HERE ONLY WORK IN 10.0.8+A recent query on the Works forum from a new OI user provided us with the perfect excuse to visit a useful tool introduced into OI 10. Those of you who've been developing for a while can probably guess what it is but those of you who haven't will just have to wait for the reveal at the end of the article!<br />
<br />
The query was how to emulate the AREV catalyst H,HD command. I'm sure that's instantly recognisable to all die-hard AREV programmers - it displays the dictionary description for the column associated with a prompt as a help message. OI lost some of the cooler features of AREV during the rewrite and regretfully this feature didn't make it. I imagine the initial thought back then was that people would expect proper Windows Help files, so it wasn't worth duplicating this.
<br />
<br />
Anyway, implementing this in OI 10 was actually a relatively straightforward exercise so we thought we'd document it here to give us an excuse to show off... you know what!<br />
<br />
So thinking of the steps involved here, we need to create a HELP event script that reads the dictionary to get the help, then displays a message containing that help. (Commercially we'd probably call a commuter module containing all of our promoted events from the script but for simplicity we'll stick with this). <br />
<br />
We also need to add a hidden menu item to trigger the event (of course you could have this on your MDI frame so that you didn't need to do this, but for the purposes of this example...).<br />
<br />
So let's illustrate this using the OI 10 EXAMPLES app... we'll use the CUST_ENTRY window<br />
<br />
<div class="separator" style="-webkit-text-stroke-width: 0px; clear: both; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: center; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<a href="https://1.bp.blogspot.com/-nBGyysyOhMw/XqxKO6okqDI/AAAAAAAAAmI/hbeDoYENB4Yhod7ib5AqtAykrVXFOJEFwCNcBGAsYHQ/s1600/2020-05-01_17-10-12.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="408" data-original-width="1165" height="224" src="https://1.bp.blogspot.com/-nBGyysyOhMw/XqxKO6okqDI/AAAAAAAAAmI/hbeDoYENB4Yhod7ib5AqtAykrVXFOJEFwCNcBGAsYHQ/s640/2020-05-01_17-10-12.jpg" style="cursor: move;" width="640" /></a></div>
<br />
Firstly let's do the easy bit and create our help message to display, by creating a new message entity.<br />
<br />
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<a href="https://1.bp.blogspot.com/-erFaJdYwA1Y/XqxN8lz7imI/AAAAAAAAAmo/biHUXeUFPrw50NcnvEMlWZhOCZbe2LAhwCNcBGAsYHQ/s1600/2020-05-01_17-27-04.jpg" imageanchor="1" style="color: #0066cc; font-family: "quot"; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-left: 1em; margin-right: 1em; text-align: center; text-decoration: underline; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><img border="0" data-original-height="399" data-original-width="990" height="256" src="https://1.bp.blogspot.com/-erFaJdYwA1Y/XqxN8lz7imI/AAAAAAAAAmo/biHUXeUFPrw50NcnvEMlWZhOCZbe2LAhwCNcBGAsYHQ/s640/2020-05-01_17-27-04.jpg" style="cursor: move;" width="640" /></a><b></b><i></i><u></u><sub></sub><sup></sup><strike></strike></div>
<br />
Now let's add the "Help" menu item to the CUST_ENTRY form<br />
<br />
<div class="separator" style="-webkit-text-stroke-width: 0px; clear: both; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: center; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<a href="https://1.bp.blogspot.com/-kCm4c-Fdhxs/Xq_2e7dGh9I/AAAAAAAAAm8/GaRF8FNMPrg2DhZuwgOByb29Ow36CaZXgCNcBGAsYHQ/s1600/2020-05-04_11-33-47.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="483" data-original-width="1014" height="304" src="https://1.bp.blogspot.com/-kCm4c-Fdhxs/Xq_2e7dGh9I/AAAAAAAAAm8/GaRF8FNMPrg2DhZuwgOByb29Ow36CaZXgCNcBGAsYHQ/s640/2020-05-04_11-33-47.jpg" style="cursor: move;" width="640" /></a></div>
<br />
<br />
We'll add a script to the HELP event for the ID_FIX editline which uses the ID dictionary in CUSTOMERS.<br />
<br />
<div class="separator" style="-webkit-text-stroke-width: 0px; clear: both; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: center; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<a href="https://1.bp.blogspot.com/-IHek60218x8/XrKTxtLw03I/AAAAAAAAAo0/ISa21PMERawBVtHOiwzrOk-dLP8ZlrqUgCNcBGAsYHQ/s1600/2020-05-06_11-35-37.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="656" data-original-width="855" height="490" src="https://1.bp.blogspot.com/-IHek60218x8/XrKTxtLw03I/AAAAAAAAAo0/ISa21PMERawBVtHOiwzrOk-dLP8ZlrqUgCNcBGAsYHQ/s640/2020-05-06_11-35-37.jpg" style="cursor: move;" width="640" /></a></div>
<br />
<br />
and we make sure that the dictionary actually has help defined<br />
<br />
<div class="separator" style="-webkit-text-stroke-width: 0px; clear: both; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: center; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<a href="https://1.bp.blogspot.com/-q9BYnhV7xz0/XqxNDb1PiRI/AAAAAAAAAmg/5bVN36BAdWsf1birHMgNqG7ary2tlrJAwCNcBGAsYHQ/s1600/2020-05-01_17-21-47.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="217" data-original-width="202" src="https://1.bp.blogspot.com/-q9BYnhV7xz0/XqxNDb1PiRI/AAAAAAAAAmg/5bVN36BAdWsf1birHMgNqG7ary2tlrJAwCNcBGAsYHQ/s1600/2020-05-01_17-21-47.jpg" style="cursor: move;" /></a></div>
<br />
<br />
Yes, it has. So putting it all together, we run the Window and press F1 in the Record Id prompt and<br />
<br />
<div class="separator" style="-webkit-text-stroke-width: 0px; clear: both; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: center; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<a href="https://1.bp.blogspot.com/-EpEp7AXRAu0/XqxO38E8m3I/AAAAAAAAAmw/AZqMwNbx6uIwYoHfLsRKLGM1BHxY-Z-ZgCNcBGAsYHQ/s1600/2020-05-01_17-31-01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="363" data-original-width="872" height="266" src="https://1.bp.blogspot.com/-EpEp7AXRAu0/XqxO38E8m3I/AAAAAAAAAmw/AZqMwNbx6uIwYoHfLsRKLGM1BHxY-Z-ZgCNcBGAsYHQ/s640/2020-05-01_17-31-01.jpg" style="cursor: move;" width="640" /></a></div>
<br />
Works like a dream - of course... but we're going to want this on every prompt on the Window - and that's going to be tedious. If only there were a way to tell OI that we want to use the same method EVERY time a HELP event is triggered.<br />
<br />
Obviously there IS a way or this paragraph'd be an outro so... you're probably already familiar with the concept of "Promoted Events" but what you may not have realised is just how easy OI 10 makes them!
(If you're not familiar with promoted events - the event chaining logic in OI firstly looks for a script associated with the control in question<i> but</i> it then looks for increasingly generic event handlers, including for example a script to be run for<b> all</b> HELP events for EDITLINES in this Window, or HELP for<b> all </b>HELP events for all EDITLINEs in this application, or a script to be run for<b> all</b> HELP events for all controls in any Window in this application. Before 10 this was achieved by copying the initial event script around to carefully named EVENTEXES - cumbersome at best AND OI didn't keep track of them in the repository so they were a bear to deploy).<br />
<br />
There's a new Window in OI 10 found here...<br />
<br />
<div class="separator" style="-webkit-text-stroke-width: 0px; clear: both; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: center; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<a href="https://1.bp.blogspot.com/-CAFaQXdul5U/XrAZb4PBQ3I/AAAAAAAAAnc/bX9DzM5JlmoF_kpZ6o3gpDaDTwTb4avyACEwYBhgL/s1600/2020-05-04_14-25-27.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="517" data-original-width="831" height="398" src="https://1.bp.blogspot.com/-CAFaQXdul5U/XrAZb4PBQ3I/AAAAAAAAAnc/bX9DzM5JlmoF_kpZ6o3gpDaDTwTb4avyACEwYBhgL/s640/2020-05-04_14-25-27.jpg" style="cursor: move;" width="640" /></a></div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<br /></div>
that allows us to edit a promoted event directly. The dialog prompts us for the control type, then event type and the form for which to create a promoted event. We wish to create a promoted HELP event for all controls in all windows, so we select <all types="">, <all types=""> Help and <all forms=""></all></all></all><br />
<all types=""><all forms=""><br /></all></all>
<div class="separator" style="-webkit-text-stroke-width: 0px; clear: both; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: center; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<a href="https://1.bp.blogspot.com/-iO1ahcLxZNg/XrAbuj1IrlI/AAAAAAAAAnw/Jj5bRS-AfeswXwkbl1DklKzZaY5mHj-VACNcBGAsYHQ/s1600/2020-05-04_14-38-24.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="369" data-original-width="599" height="394" src="https://1.bp.blogspot.com/-iO1ahcLxZNg/XrAbuj1IrlI/AAAAAAAAAnw/Jj5bRS-AfeswXwkbl1DklKzZaY5mHj-VACNcBGAsYHQ/s640/2020-05-04_14-38-24.jpg" style="cursor: move;" width="640" /></a></div>
<br />
and then we copy the code from our original edit line help into here. (Note that we've also included the event shorthand versions of get and set_property as comments. Shorthand has been extended in 10 and makes it possible to use in pretty much any situation. This makes the code easier to read for some developers and is faster to develop with).<br />
<br />
<div class="separator" style="-webkit-text-stroke-width: 0px; clear: both; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: center; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<a href="https://1.bp.blogspot.com/-bxDG2ohDPgc/XrKTxh7pW1I/AAAAAAAAAo8/XeaLJ-_nefwzAWbBjLPB2vjH4IxJ1RaXQCEwYBhgL/s1600/2020-05-06_11-36-41.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="697" data-original-width="818" height="544" src="https://1.bp.blogspot.com/-bxDG2ohDPgc/XrKTxh7pW1I/AAAAAAAAAo8/XeaLJ-_nefwzAWbBjLPB2vjH4IxJ1RaXQCEwYBhgL/s640/2020-05-06_11-36-41.jpg" style="cursor: move;" width="640" /></a></div>
<br />
We save and compile the code, then return to our original CUST_ENTRY window and clear down the original event code. It is no longer needed as our promoted event will do the work for us.<br />
<br />
There is however one last step required before our promoted event can be used. We have to tell the system that we actually want this to happen. Y'see when you compile a form, the system goes off and compiles into the executable version of the form ALL of the events used by the form, but as a rule it only checks for specific categories of promoted event to make the compilation process as quick as possible. We need to tell it to look for our promoted help event.
We do this using the Window found under Tools/Form Designer/Event Configuration...<br />
<br />
<div class="separator" style="-webkit-text-stroke-width: 0px; clear: both; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: center; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<a href="https://1.bp.blogspot.com/-b3BFnh6Ozz0/XrAetJN-NuI/AAAAAAAAAoE/6reM4D1wgEMPeWepltvjTnsFJgbhsh39QCNcBGAsYHQ/s1600/2020-05-04_14-54-04.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="493" data-original-width="797" height="394" src="https://1.bp.blogspot.com/-b3BFnh6Ozz0/XrAetJN-NuI/AAAAAAAAAoE/6reM4D1wgEMPeWepltvjTnsFJgbhsh39QCNcBGAsYHQ/s640/2020-05-04_14-54-04.jpg" style="cursor: move;" width="640" /></a></div>
<br />
We select the edit line control and we check that we'd like our promoted event to be enforced.<br />
<br />
Once we have saved this row (and depending on your version of OI you might have to go to SYSPROG to do this) we can compile our Window. This adds our promoted event into every edit line on our Window (remember other Windows will need to be recompiled for these changes to be reflected so it make sense to plan promoted events in advance at the start of development).
Now we can press F1 on a prompt we hadn't previously even looked at (Company) and receive help from the dictionary.<br />
<br />
<div class="separator" style="-webkit-text-stroke-width: 0px; clear: both; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: center; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<a href="https://1.bp.blogspot.com/-ERrQsFwQF-A/XrAhA5EYlNI/AAAAAAAAAoQ/QkPk0dpOX2cCHaXVA1CbVOL2y9em5niGACNcBGAsYHQ/s1600/2020-05-04_15-03-00.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="344" data-original-width="606" height="362" src="https://1.bp.blogspot.com/-ERrQsFwQF-A/XrAhA5EYlNI/AAAAAAAAAoQ/QkPk0dpOX2cCHaXVA1CbVOL2y9em5niGACNcBGAsYHQ/s640/2020-05-04_15-03-00.jpg" style="cursor: move;" width="640" /></a></div>
<br />
As the pièce de résistance we can even select these promoted events when defining RDK modules!<br />
<br />
<div class="separator" style="-webkit-text-stroke-width: 0px; clear: both; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: center; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<a href="https://1.bp.blogspot.com/-aOTa9wD-C7o/XrAiYmUbXJI/AAAAAAAAAoc/3gU58jfe8a8aeVoKyFG78RgzgeEGOmSCwCNcBGAsYHQ/s1600/2020-05-04_15-08-24.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="476" data-original-width="332" height="640" src="https://1.bp.blogspot.com/-aOTa9wD-C7o/XrAiYmUbXJI/AAAAAAAAAoc/3gU58jfe8a8aeVoKyFG78RgzgeEGOmSCwCNcBGAsYHQ/s640/2020-05-04_15-08-24.jpg" style="cursor: move;" width="446" /></a></div>
<br />
Of course, being programmers we always want stuff for free - so what'd be really nice was if the Promoted Event Designer actually updated the Event Configuration window for you - I mean, it's unlikely you're going to be promoting something and NOT want to use it - but for now this has made working with Promoted Events an order of magnitude easier - thank you Rev!
Sprezzhttp://www.blogger.com/profile/08866141305592910267noreply@blogger.com1tag:blogger.com,1999:blog-2607884204445547877.post-35124585628642497202020-03-21T15:14:00.000+00:002020-03-21T15:28:15.279+00:00Golden Slumbers Close OIsImagine the scenario - your client is a frugal sort and wants to have your system available to 25 of their office users but knows that it is highly unlikely that all 25 users will want to access the system at the same time - so they pay you for a 20 seat license.<br />
<br />
All is well - until their users start to leave the app running on their laptop - and their laptop is configured to sleep after a pre-set period to conserve battery life. Their laptop sleeps and takes with it an OI license. This happens on 5 machines - so now they have 20 users active in the office - but only 15 available licenses. And somehow this is YOUR fault. (Isn't it always - it's probably a bug :D).<br />
<br />
Is there anything to be done?<br />
<br />
Don't you just love those sort of rhetorical questions? If there wasn't then this blog post would be a little pointless.<br />
<br />
Those of you who've read our last blog post on the <a href="http://sprezzblog.blogspot.com/2020/03/openinsight-genesis.html" target="_blank">genesis of OpenInsight</a> will realise that Windows is always trying to tell OpenInsight stuff that frankly, OpenInsight doesn't really care about. And most of the time, the stuff that it ignores, isn't of practical benefit to neither the user nor the developer. But in the situation we're describing there's a Windows message that we DO care about - the <a href="https://docs.microsoft.com/en-gb/windows/win32/power/wm-powerbroadcast" target="_blank">WM_POWERBROADCAST</a> message. This is the Windows message that notifies the application that a power management event has occurred, and luckily for us - sleeping or suspending is just such an event. So if we can somehow listen out for that event we can take whatever action we want when it occurs. Well, as long as that action takes less than 2 seconds - the length of time that Windows waits after sending the message and actually doing the suspension.<br />
<br />
Using OI 10 to illustrate this we only have add two small snippets of code. The first tells OpenInsight that actually, yes, we are interested in knowing about the WM_POWERBROADCAST message. The second looks at the contents of the message, determines that this particular message is a suspension/sleep message and if it is, kills OpenInsight.<br />
<br />
<h3>
Listen Up!</h3>
To tell OpenInsight that we want to be told about the WM_POWERBROADCAST message we add the following lines to our main application window's create event.<br />
<br />
message = 0x218<br />
newQual = 1<br />
prevQual = Exec_Method( @window, "QUALIFYWINMSG", message, newQual)<br />
<br />
218 HEX (536 DEC) is the code for WM_POWERBROADCAST and the newQual parameter is defined as follows in the documentation "OpenInsight 10 Presentation Server Reference Manual.pdf" in the documents folder. We're effectively saying "If Windows tells you about this, please let me know by raising the WINMSG event on the current Window".<br />
<br />
<h3>
ZZ(Zzzzzzzzzzzzzz)</h3>
To act upon the notification we simply have to add this code to the WINMSG event (or any other event if you prefer (See the above documentation))<br />
<br />
If wParam = 4 Then<br />
call exec_Method("SYSTEM", "DESTROY", "SYSTEM")<br />
end<br />
<br />
Where 4 is the code for <a data-linktype="relative-path" href="https://docs.microsoft.com/en-gb/windows/win32/power/pbt-apmsuspend">PBT_APMSUSPEND</a> - the system is suspending operation. Naturally, we don't HAVE to close down OpenInsight - we can take whatever actions we want in the remaining 2 seconds before Windows actually suspends operation.<br />
<br />
Of course, when your user repowers up their workstation, OpenInsight will no longer be there - a surprise to them given that the point of a SLEEP is to return to where you left off - but if that's what you as the developer opt to do, that's your prerogative - and your parsimonious bill payer will remain happy!<br />
<br />Sprezzhttp://www.blogger.com/profile/08866141305592910267noreply@blogger.com0tag:blogger.com,1999:blog-2607884204445547877.post-31452209027943942062020-03-16T15:28:00.002+00:002020-03-21T15:11:59.422+00:00OpenInsight - GenesisAs I start to write this blog entry, Aaron has pointed out that it is 25 years to the day since Advanced Revelation (AREV) 3.12 was released. That means it is even longer since OpenInsight (OI) 1.0 was released. Recently working with some individuals, it became apparent that not everybody's memory goes back that far, so we thought it'd be a good idea to put together an article which combined a little bit of history with a dollop of technical information about OpenInsight load sequences - to assist in helping debug non-starting OpenInsights.<br />
<br />
When people launch OI, they might be aware that they're actually launching an executable file, Oinsight.exe (or OpenInsight.exe for 10+) and Oengine.dll (or RevEngine.dll for 10+), but they might not be aware why this turn of events came to pass. To understand this we have to cast our mind back to the early 90s when the days of DOS were numbered and the future lay in the Windows GUI.<br />
<br />
The team at Revelation were justifiably proud of the success of the myriad of alternative Base Filing Systems (BFSs) that were available for the developer community. The separation of the programming logic layer from the physical filing system layer had proven to be very successful with AREV. In fact Revelation had won a special award from Microsoft for driving the sales of their nascent SQL Server product. With the addition of BFSs for Lotus, DB2, dBase<i> et al</i> Revelation realised that they were onto a good thing. And what's better than a good thing? Even more of a good thing!<br />
<br />
So deciding that being able to talk to ANY back end was a good thing, they also considered that being able to talk to (or be talked to) by ANY front end must also be a good thing. Ans so was born OE 1.0. The engine.<b> Just</b> the engine. No front end as we know it, linear hash as a back end by default, but any BFS you wanted to use. With hindsight this was genius. Just not commercial genius. The Rev community voted with their feet and refused to use it. The engine as we know it was pretty much the same beast. It could run R/Basic and it could read and write data - but there was no decent IDE. Rev tried to include a simple third party development environment when they released OI 1.0 but it was no AREV.<br />
<br />
So back to the drawing board. Rather than start again reengineering the engine, Rev quickly began development of a separate executable whose job was to ;<br />
<br />
<ul>
<li>Communicate with Windows</li>
<li>Communicate with the engine</li>
<li>Support a more familiar IDE</li>
</ul>
<div>
and this became Oinsight.exe. The executable responsible for all of the Windows interaction - the Presentation Server - was embedded within this. So now if we wanted to launch say a CUSTOMER window with a couple of statics, a couple of edit lines and an OK and Cancel button the scenario would unfold as follows where the protagonists are as follows ;</div>
<div>
<br /></div>
<ul>
<li><span style="color: #6fa8dc;">Windows</span></li>
<li><span style="color: #6aa84f;">Oinsight.exe</span></li>
<li><span style="color: #cc0000;">Oengine.exe</span></li>
</ul>
<div>
<span style="color: black;">Please note this conversation is simplified for explanatory purposes...</span></div>
<ul>
<span style="color: black;"></span></ul>
<span style="color: #6fa8dc;">Please launch window CUSTOMER</span><br />
<span style="color: #6aa84f;">OK</span><br />
<span style="color: #6aa84f;">Oengine - please read the compiled definition of CUSTOMER from SYSREPOSWINEXES</span><br />
<span style="color: #cc0000;">Read it - here you go!</span><br />
<span style="color: #6aa84f;">Windows - please create a window called CUSTOMER sized as follows with the following characteristics</span><br />
<span style="color: #6fa8dc;">OK - I've done that but I don't call it CUSTOMER I call it 12786</span><br />
<span style="color: #6aa84f;">OK - I'll remember that - thanks</span><br />
<span style="color: #6aa84f;">Windows - now please create a static called TXT.CUST_ID</span><br />
<span style="color: #6fa8dc;">OK - done - I call it 12787</span><br />
<span style="color: #6aa84f;">Windows - now please create another static called TXT.CUST_NAME</span><br />
<span style="color: #6fa8dc;">OK - done - I call it 12788</span><br />
<span style="color: #6aa84f;">Windows - now please create an edit line called EDL_CUST_ID</span><br />
<span style="color: #6fa8dc;">OK - done - I call it 12789</span><br />
<span style="color: #6aa84f;">Windows - now please create an edit line called EDL_CUST_NAME</span><br />
<span style="color: #6fa8dc;">OK - done - I call it 12790</span><br />
<span style="color: #6aa84f;">Windows - now please create a push button called BTN_OK</span><br />
<span style="color: #6fa8dc;">OK - done - I call it 12791<br />
<span style="color: #6aa84f;">Windows - now please create a push button called BTN_CANCEL</span><br />
<span style="color: #6fa8dc;">OK - done - I call it 12792</span><br />
<br /><span style="color: black;">
and there we have it - a working Window.<br />
<br />
From hereon in, OI is oblivious to the existence of the Window as it is completely under the control of Windows. Of course, Windows knows who the owner is, so as the user mouses around the screen the following conversation ensues</span><br />
<br />
<span style="color: #6fa8dc;">Hey OI the user just moved the mouse by a pixel in 12786</span><br />
<span style="color: #6aa84f;">Don't care</span><br />
<span style="color: #6fa8dc;">They did it again in 12786</span><br />
<span style="color: #6aa84f;">Still don't care</span><br />
<span style="color: #6fa8dc;">They just right clicked the mouse when over 12789</span><br />
<span style="color: #6aa84f;">Don't care - developer doesn't want to do anything</span><br />
<span style="color: #6fa8dc;">Oh wait - they've clicked on 12791</span><br />
<span style="color: #6aa84f;">Really? The OK button? OK Oengine, see if you can find a script for the OK button for CUSTOMERS</span><br />
<span style="color: #cc0000;">Found it and running it</span><br />
<span style="color: #cc0000;">It's finished running so now I'm going to look for promoted events</span><br />
<span style="color: #cc0000;">Found the system click handler and I'm now running that</span><br />
<span style="color: #cc0000;">Right nothing else to do</span></span><br />
<div>
<span style="color: #6aa84f;">OK let's wait until Windows tells us something we care about</span></div>
<div>
<span style="color: #6fa8dc;"><br /></span></div>
<div>
<span style="color: black;">So there is an ongoing dialog between Windows and OI with OI either ignoring Windows messages it doesn't care about, or asking OE if there's anything it's meant to be doing.</span><br />
<span style="color: black;"><br /></span>
Which leads us on to the question of exactly what happens when the user double clicks the OI icon on the desktop. That sequence is as follows in 9.4 :-<br />
<br />
Oinsight.exe loads<br />
imgMan32.dll is loaded to later display the splash screen<br />
Several other OI dlls are loaded<br />
Supporting Windows dlls are loaded<br />
OI <span style="color: black;">then loads various language support dlls including UTF8 support</span></div>
<span style="color: black;">
OI then loads tool specific dlls<br />
OI then loads the routines to support linear hash<br />
OI then loads the engine dll<br />
OI then loads Lotus Notes support<br />
OI then loads font support<br />
OI then displays the splash screen<br />
TCP/IP support is installed<br />
The SYSPROG.DBT is read<br />
The linear hash client is started<br />
Boot revmedia map is loaded<br />
Communication is opened to the UD service<br />
Files are attached<br />
System routines are loaded<br />
Initialise is run<br />
The login dialog is launched<br />
<br />
For 10.0+ it is<br />
<br />
OpenInsight.exe loads<br />
Supporting Windows dlls are loaded</span><br />
Windows imaging is loaded<br />
OI then loads various language support dlls including UTF8 support<br />
OI then loads various COM objects<br />
OI then checks the .rxi file for startup options<br />
OI then loads font support<br />
OI then loads the splash screen<br />
OI loads communication libraries<br />
TCP/IP support is installed<br />
OI loads the engine dll<br />
OI checks licensing<br />
The SYSPROG.DBT is read<b></b>
The linear hash client is started<br />
Communication is opened to the UD service<br />
Files are attached<br />
System routines are loaded<br />
Initialise is run<br />
The login dialog is launched
Sprezzhttp://www.blogger.com/profile/08866141305592910267noreply@blogger.com0tag:blogger.com,1999:blog-2607884204445547877.post-86124195167743820272020-03-12T14:48:00.000+00:002020-03-12T14:48:27.959+00:00Zero Bites (Hard)<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
We've recently been supporting a venerable app for a long time Revelation Client (put it this way, when working on it recently, we came across some of our code taken from a REVMEDIA article nearly 30 years ago!) whose developer has retired.</div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<br /></div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
Year end had come around and some modifications made in the last decade had finally turned around to bite the client. Think of a Y2K bug and then increase its occurrence by two orders of magnitude.</div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<br /></div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
The system - as part of its year end routine - would calculate the starting row id number for a specific temporary table, by taking the last digit of the year and multiplying it by 10,000. It would then drop this into the row id prompt automatically. So for 2017 the starting number would be 7 * 10,000 = 70,000. For 2019, 9 * 10,000 = 90,000. For 2020? Less good. 0 * 10,000 = 0.</div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<br /></div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
Of course, we could get around that issue if it were not for the fact that this calculation was done on the default row id prompt, which<i> also</i> had a validation of 5N.</div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<br /></div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
So the system calculated a starting number of 0, and OI rejected it as not being a 5 digit number. So the system calculated a starting number of 0, and OI rejected it as not being a 5 digit number. So the system calculated a starting number of 0, and OI rejected it as not being a 5 digit number. So the system calculated a starting number of 0, and OI rejected it as not being a 5 digit number. So the system calculated a starting number of 0, and OI rejected it as not being a 5 digit number. So the system calculated a starting number of 0, and OI rejected it as not being a 5 digit number. So the system calculated a starting number of 0, and OI rejected it as not being a 5 digit number. So the system calculated a starting number of 0, and OI rejected it as not being a 5 digit number..... you get the picture.</div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<br /></div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
That was a relatively easy fix once the business decided what they wanted to use instead.</div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<br /></div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
The bug that REALLY threw us, was that in other parts of the system, we would enter a new starting row id, the system would accept it, look up the row and then reset the row id to a seemingly random number. Initially our suspicion was raised by the default program and we took some time analysing that but couldn't see where the issue lay. This being AREV32 we had lots of potential culprits... was it the
</div>
<ul style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<li> Post-prompt routine</li>
<li> Pre-prompt routine</li>
<li> Pre-read routine</li>
<li> Post-read routine</li>
<li> Post-app initialise routine (This did a LOT of work rearranging prompts and prompt logic)</li>
</ul>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
Whatever it was it wasn't screaming out to be identified, but after a couple of hours of debugging we zoomed in on the fact that the pre-prompt routine used a parameter row called 00 to store the defaults.</div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<br /></div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
We opened the parameter row up in the editor and it existed alright - so we updated the defaults in that row, saved them and went off to see if our fix had worked.
We were taken aback to see that it didn't. Despite putting 100,000 into the correct position in the parameter row, the seemingly random number kept turning up like a bad penny. </div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<br /></div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
So we zoomed in on the section of code that grabbed the default number :- </div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<br /></div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<span style="font-family: "courier new" , "courier" , monospace;">ReadV defaultNum from vTable, 00, 978 else call fsMsg() </span></div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<span style="font-family: "courier new" , "courier" , monospace;"></span><br /></div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
We double-checked, and yes, 100,000 was indeed in column 978 of row 00. We triple-checked. No change. And then, because we now knew where the problem lay, it became obvious. One of those "Well d'uh" moments.</div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<br /></div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
Opening up the editor we looked to see if there was a parameter row with a row id of 0. Of course there was. And in CAPITAL LETTERS across the top of of the first column was "DEPRECATED - DO NOT USE".
And there in column 978 of row 0 was our seemingly random number.</div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<br /></div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
With hindsight this was so obvious - the 00 was not quoted so wasn't treated as a string, it was treated as a number, and 00 === 0 if we're talking numbers. But it just seemed so strange that a developer would deliberately choose to use 00 over 0 if they meant 0. Of course, the strong likelihood is that the developer thought that they<i> meant</i> 00 - hence the comment in column 1 of row 0!</div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
<br /></div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">
We even went back to original AREV on an XP (thanks Carl and Bill) to check the original behaviour, and unsurprisingly nothing has changed.
So mystery solved and problem averted but a salutary lesson.
</div>
<b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><br />Sprezzhttp://www.blogger.com/profile/08866141305592910267noreply@blogger.com0