Showing posts with label $ocxhandle. Show all posts
Showing posts with label $ocxhandle. Show all posts

Tuesday, 17 June 2014

What are handles and should I be using them?

The Uniface manuals describes a handle as...
A handle is a reference to an object, such as a component instance, entity, occurrence, or field. Handles can be used to call operations on the referenced object, or to pass these objects as variables and parameters.

If you're used to pointers, you may at first glance think that these are the same, but they're not.  A pointer contains the address of an item in memory and is therefore fixed, whereas a handle is an abstract reference, which means the address can be changed without breaking the reference.  This makes them very useful.

In Uniface you can have "public" or "partner" handles, which allow you to define which types of operations can access them.  They are also datatypes available for local, component and global variables, depending on the scope required.  I'm not going to discuss either of these points in detail, but I think it's handy to know.

As the description in the manual states, you can create a handle that references most Uniface objects, and there are different methods for creating these handles:  Component instances ($instancehandle), entity collections ($colhandle), entity occurrences ($occhandle), fields ($fieldhandle) and also OCX controls ($ocxhandle).  

I'm going to focus on component instances.  More specifically, I'm going to focus on creating new component instances, using newinstance and handles.  

As you might expect, creating a new instance of a form has a little lead time.  Using a handle doesn't stop this lead time, but what it does do, is mean that it only has to happen once.  This means that using a handle for a single form activation is not going to give you any advantage (unless you just love handles!) but when calling operations on the same form multiple times, handles could give you a performance improvement.

This is something like how you could activate a form...

  activate "TEST_FORM".test_oper("Test")


In fact this does an implicit newinstance as well (if it can't already find an instance with the same name as the form) and so explicitly your code could look like this...


  newinstance "TEST_FORM","TEST_FORM"
  activate "TEST_FORM".test_oper("Test")


If you were to replace this with a handle then you may use something like this...


  newinstance "TEST_FORM",theHandle
  theHandle->test_oper("Test")


Notice that in this case we have used a handle instead of an instance name in the newinstance call, and then we can use this handle in place of the activate command.  The -> is referred to by Uniface as the "dereference" operator, and is processed with a precedence of 2 (with only field indirection being higher).

So let's try these two different ways of activating an operation (in this case a very simple operation that simply returns out immediately).  The newinstance command is done before the loop, and the activate (or equivalent handle call) is done inside the loop, 200,000 times...


  • Using activate: 2.56, 2.61, 2.60 (about 2.6 seconds)
  • Using a handle: 2.39, 2.35, 2.39 (about 2.4 seconds)


As you can see, using a handle is marginally quicker, although you'd have to be making a lot of calls before you really noticed the difference.  

I thought that this would be even more useful when the handle references a component instance that is running on another server, such as when a form is mapped to run elsewhere, as the I thought the initial creation of the new instance would take longer here.  So I ran the same operation 20,000 times (after mapping the form)...


  • Using activate: 13.39, 14.35, 12.99 (about 13.5 seconds)
  • Using a handle: 13.56, 13.12, 12.91 (about 13.0 seconds)

Not much difference here either.  Having said that, maybe on a chatty network the difference would be greater.

Please note:  You must return out of the operation that you call, if you exit out then this will destroy the handle and future calls to the operation will fail with a $status of -1.  To clean up a handle you can either set it to 0 or "" (empty string). 


Summary: Handles are abstract references to pretty much any Uniface object.  They can be useful, especially if you want to call the same object multiple times, but they don't seem to have the performance benefits that I was expecting, not when it comes to component instances anyway.

Thursday, 24 May 2012

Copying text from webpage to text file

I warn you now, I think this is the most convoluted solution I've ever come up with.  I'm convinced there must be an easier way to do this, but this was certainly an interesting way of doing it.


I had a table of information in an HTML file which I was rendering in an OcxContainer of type "Shell.Explorer" within the client application.  In fact I was first using lfiledump to create the file, and then rendering it like this...

$OCXHandle$ = $ocxhandle("OCX.DUM1") ;create handle to OcxContainer
$OCXHandle$->NAVIGATE(url,-,-,-,-)   ;navigate to file path
show                                 ;update screen

Which gave me something like this...




I now needed to export this information to a text file, easy for customers to upload to our helpdesk, or even paste straight into their response.  Thinking back, I was creating the HTML myself so it was controlled, I probably could have search and replaced the source code to reformat the results the way I wanted them.  However, I ended up doing it this way...


$OCXHandle$->EXECWB(17,-,-,-) ;select all
$OCXHandle$->EXECWB(12,-,-,-) ;copy
$OCXHandle$->EXECWB(18,-,-,-) ;clear selection
fieldsyntax ocx,"HID"         ;hide OcxContainer
fieldsyntax clipboard,""      ;show EditBox
$prompt = "clipboard.dum1"    ;fire <FieldGetsFocus> trigger


Then in the <FieldGetsFocus> trigger I had the following code...


macro "^INS_SELECT^DETAIL"    ;paste the text and fire <Detail> trigger



Then in the <Detail> trigger I had this code...

fieldsyntax ocx,""            ;showOcxContainer
fieldsyntax clipboard,"HID"   ;hide EditBox
if ( clipboard != "" )        ;process the text
  list = $replace(clipboard,1,"%%^","·;",-1)
  delitem list,1
  cont = ""
  while ( list != "" )
    getitem temp,list,1
    delitem list,1
    if ( temp != "" )
      temp = $replace(temp,1," ","·;",-1)
      getitem name,temp,1
      getitem valu,temp,2
      len = ( $length(name) / 2 )
      if ( len = len[trunc] )
        name = "%%name%%%  . . . . . . . . . . . . . . . . . "
      else
        name = "%%name%%% . . . . . . . . . . . . . . . . . "
      endif
      cont = "%%cont%%name[1:40]%%% '%%valu%%%'.%%^"    
    endif
  endwhile
  filedump/append cont,fnam   ;create the file
endif


This resulted in the following text file...

plugins/javascript/jquery.js  . . . . .  '1.6.1'.
plugins/javascript/jquery-ui.js . . . .  '1.8.13'.
javascript/sits_ajax.js . . . . . . . .  '851.1'.
javascript/dmu.js . . . . . . . . . . .  '850.1'.
javascript/translationajax.js . . . . .  '841.1'.
javascript/pod_bar.js . . . . . . . . .  '841.1'.
javascript/siw_elu.js . . . . . . . . .  '850.1'.
javascript/siw_elu_1.js . . . . . . . .  '850.1'.
javascript/siw_enl.js . . . . . . . . .  '850.1'.


As you can see, the result is exactly what I was after.  Having said that, the method is more than a little bit crazy, you don't need to tell me that!  I think it took me a whole day to come up with this solution, but I think it proves that sometimes you really have to think outside the box.  Hopefully I, nor anyone else, will ever need to use this in the future though!

For anyone using an OcxContainer of type "Shell.Explorer", I've found Microsoft's own MSDN site to be very useful, especially these links...


Summary: Sometimes solving a problem takes a spark of inspiration, sometimes it takes a lot of hard work with trial and error, and sometimes it takes plenty of both!