Call-Out Using activate

The activate ProcScript statement enables you to make use of named operations, parameters, and remote execution.

The details about a function and its parameters are encapsulated in a signature, which is an object in the Uniface Repository that describes a component and its operations. For more information, see Define a Component Signature.

Before activating a 3GL routine, you must create a signature, compile that signature, and, if necessary, update your UAR file. Most of the work in interfacing with existing 3GL code is in the manual creation of the signatures. Unfortunately, there is no command that generates a signature from a given shared library. In fact, this would not be possible, because information about parameters is not included in a shared library.

If a certain legacy function has parameters that have no equivalent in Uniface, you cannot activate it directly via the signature. For example, certain Windows API functions have Windows-specific parameter types. In cases like this, you need an intermediate layer of C code (also known as a ‘wrapper’) to resolve the incompatibility.

The following simple example uses activate to modifying data using these 3GL service functions: The environment is MS Windows, and we assume that your current directory is the top-level Uniface directory. Here are the steps to follow:

  1. Create a new signature with the name CONV
  2. Change the implementation from Modeled Component to C Component
  3. Create a new operation with the name UPCASE
  4. In the Details section of the Define Operation form for this operation, change the literal name from conv_upcase to UPCASE
  5. Add a IN/OUT parameter with name TEXT and data type String
  6. Quit the IDE, then run ide.exe with the following commands to compile the signature.
    ide /sig conv
  7. Create a form containing the following ProcScript in the EXEC operation:
    $1 = "the quick brown fox jumps over the lazy dog"
    ; activate UPCASE
    activate "CONV".UPCASE($1)
    message/info "%%$1"
    
  8. Create the C source acttest.c:
    #include <h3gl.h>
    #include <ctype.h>
    
    EXPORT void UPCASE ( char *buf )
    {
    char *p;
    for ( p=buf; *p; p++ ) /* Uppercase string */
    {
    if ( islower(*p) )
    *p = toupper(*p);
    }
    }
    
  9. Compile the C source with the command:
    cl acttest.c -LD -Felib\acttest.dll -I3gl\include
    
  10. Add the following entry to your assignment file:
    [USER_3GL]
    acttest(UPCASE)
    
  11. Test the form by running ide.exe with the switch /tstFormName. You should see a pop-up form with the string in uppercase.

Notice that the pop-up window does not show the full string in uppercase, but only the first 40 characters of it. To understand this, look at the signature: the STRING parameter we added has the default length of 40 (like all Uniface Character fields for which we have not defined a size). So you always need to think about how long a string can be. This is inherent to the design of activate, because data must have the potential to be wrapped into network packets and transferred to a remote server.

  • With activate, you can call functions in any existing shared library that adheres to the standard C calling convention. For example, you can directly call Windows API functions in the kernel32.dll this way. The only reason we still include h3gl.h is because we would like to use the EXPORT macro to keep the code portable across platforms.
  • Activate on a Remote Machine

    If you activate a component on a remote machine using the Uniface Server, be aware that your compiled signature must be available both on the client and on the server. The reason why the server also needs it is because it can contain machine-specific information (such as the name of a DLL or a shared library). We recommend that you import your 3GL signature on the server, compile it, and update the local UAR file. If you do not, the client-side activate will fail with status -50 (signature descriptor not found).

    Activate using Handles

    You can use handles to component instances as parameters to 3GL callout operations.

    For an IN parameter, use the C datatype UHACT. For OUT and INOUT parameters use UHACT*. In the 3GL code you can call operations on the IN and INOUT handles; for OUT handles you can do uinstnew() to create them in your 3GL code, and afterwards the returned handle can be used by the 4GL to call operations on the handle.

    It is necessary to keep your own instance administration. Any instance created in 3GL is not deleted by Uniface until uinstdel() is called on it in 3GL, or deleteinstance in Proc. You could leak instances if not careful.

    Related Topics