Highlighted
Absent Member.
Absent Member.
3579 views

.NET events are not detected

Jump to solution

I'm having some trouble with .NET events either not firing, or not being caught by ACUCOBOL. I'm guessing it's something simple, but am stuck, and would appreciate any help.

Environment:

  • Windows 7 (64-bit)
  • ACUCOBOL 9.2.1 (32-bit)
  • .NET framework 4 (from which I'm using the 32-bit version for compatibility with ACUCOBOL)

This example starts with the following files:

  • acucobol.def (from the ACUCOBOL 9.2.1 samples for 32-bit Windows)
  • acugui.def (also from the ACUCOBOL samples)
  • DotNetBrowser.cbl (a COBOL program where the SCREEN SECTION contains a .NET control)
  • MyWebBrowser.cs (a simple C# class derived from System.Windows.Forms.WebBrowser)
  • test.html (an HTML5 document containing a few JavaScript functions)

All of the above files are in the following directory:

    C:\Windows\Temp\DotNetBrowser

The COBOL code in DotNetBrowser.cbl is:

       identification division.
       program-id.  Browser.

      ***************************************************************
       ENVIRONMENT DIVISION.
       CONFIGURATION SECTION.
       SPECIAL-NAMES.
       copy "MyNamespace.MyWebBrowser.def".
       copy "System.Windows.Forms.def".
           .

       data division.
       working-storage section.
       copy "acucobol.def".
       copy "acugui.def".
       
       77  key-status 
                is special-names  crt status    pic 9(4) value 0.
                88  exit-button-pushed          value 27.
       
       01  event-status
                is special-names event status.
           03  event-type                       pic x(4) comp-x.
           03  event-window-handle              usage handle.
           03  event-control-handle             usage handle.       
           03  event-control-id                 pic x(2) comp-x.
           03  event-data-1                     usage signed-short.
           03  event-data-2                     usage signed-long.
           03  event-action                     pic x comp-x.

       78  event-occurred                       value 96.

       01  configuration-data.
         05  ws-lines                       pic s99999V99 value 25.
         05  ws-size                        pic s99999v99 value 80.
       
       01  uri  pic x(254)
                value "file:///C:/Windows/Temp/DotNetBrowser/test.html".

      *****************************************************************
       screen section.
       01  screen-1.
         03  wb-1, "@MyWebBrowser",
             line 1, col 1,
             lines ws-lines cells, size ws-size cells
             namespace is "MyNamespace",
             class-name IS "MyWebBrowser",
             constructor is constructor1(),
             event procedure is usercontrol-events.

      ***************************************************************
       procedure division.
       main-logic.
           display standard window, 
                title "Web Browser Sample - browser.cbl"
                lines ws-lines, size ws-size,
                resizable
                background-low.
        
           display screen-1.

           modify wb-1 "Go"(uri)

           perform until 0 = 1
                accept screen-1
                evaluate key-status
                  when event-occurred
                    if event-type = ntf-resized
      *                 THE ACUCOBOL WINDOW HAS BEEN RESIZED.
      *                 RESIZE THE .NET CONTROL ACCORDINGLY.
                        divide event-data-1 by 100 giving ws-lines
                        divide event-data-2 by 100 giving ws-size
                        modify wb-1
                          lines ws-lines cells
                          size ws-size   cells
                        modify wb-1 "FillParent"()
      *                 THE NEXT STATEMENT CALLS A C# FUNCTION IN THE
      *                 WEB BROWSER CONTROL, WHICH IN TURN CALLS A
      *                 JAVASCRIPT FUNCTION IN THE HTML DOCUMENT.
                        modify wb-1
                          "InvokeScript2"(
                            "jsFunction",
                            "COBOL called JavaScript")
                    end-if
                end-evaluate
           end-perform.

           stop run.

       usercontrol-events.
      *    THIS EVENT PROCEDURE IS NOT GETTING PERFORMED.
           display message box "User control event type: " event-type
           evaluate event-type
               when msg-net-event
                   evaluate event-data-2
                       when @WebBrowser_DocumentTitleChanged
                           display message box "Title changed."
                   end-evaluate
           end-evaluate
           .
       usercontrol-events-exit.
           exit.

The C# code in MyWebBrowser.cs is:

namespace MyNamespace {
    using System;
    using System.Windows.Forms;
    public class MyWebBrowser : WebBrowser
    {
        public MyWebBrowser()
        {
            Anchor = (AnchorStyles.Bottom | AnchorStyles.Right);
            ObjectForScripting = this;
        }
        
        public void Go(String UriString) {
            base.Navigate(UriString);
        }

        public void FillParent() {
            Size = Parent.ClientSize;
            Top = 0;
        }

        public void InvokeScript(String name) {
            Document.InvokeScript(name);
        }

        public void InvokeScript2(String name, string arg) {
            Document.InvokeScript(name, new Object[] { arg });
        }

        public void Test(String message) {
            MessageBox.Show(message);
            Document.Title = "a new title";
        }
    }
}

The HTML and JavasScript in test.html is:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>HTML5 + JavaScript Example</title>
<script type="text/javascript">
    // A function that the .NET ObjectForScripting can call to show a message.
    function jsFunction(message) {
        alert(message);
    }

    // A function that accesses the .NET ObjectForScripting via window.external.
    function callDotNet() {
        window.external.Test("JavaScript called .NET.");
    }

</script>
</head>
<body">
<h1>HTML5 + JavaScript Example</h1>
<button onclick="callDotNet()">Click to call .NET.</button>
<p>Resize the window, and see how ACUCOBOL responds to the NTF-RESIZED event.</p>
</body>
</html>

The steps to set up the example are as follows.

Assumption: All of the files listed above are in C:\Windows\Temp\DotNetBrowser.

To compile the C# class, launch a Windows command prompt, and execute the following two commands:

cd C:\Windows\Temp\DotNetBrowser
csc /target:library MyWebBrowser.cs

Note that a DLL file was generated (MyWebBrowser.dll).

Launch netdefgen.
On the Assembly Location screen, select Other Location, and browse to your 32-bit .NET Framework. (In my case, this is C:\Windows\Microsoft.NET\Framework\v4.0.30319.)
In the Assemblies list, select System.Windows.Forms.dll, and click Next.
In the Namespace Classes list, select the following, and click Next:

  • System.Windows.Forms.Control
  • System.Windows.Forms.WebBrowser
  • System.Windows.Forms.WebBrowserBase

In the Class Members screen, click Next.
In the Copy File Location screen, enter C:\Windows\Temp\DotNetBrowser\System.Windows.Forms.def, and click Next.
In the Stored Objects screen, click Skip.
In the Ready to create the Copy File screen, click Generate.
In the SUCCESS screen, click Again.

Netdefgen returns to the Assembly Location screen.
In the location input, enter C:\Windows\Temp\DotNetBrowser.
In the Assemblies list, select MyWebBrowser.dll, and click Next.
In the Namespace Classes list, select MyWebBrowser, and click Next.
In the Class Members screen, click Next.
In the Copy File Location screen, enter C:\Windows\Temp\DotNetBrowser\MyNamespace.MyWebBrowser.def, and click Next.
In the Ready to create the Copy File screen, click Generate.
In the SUCCESS screen, click Exit.

Note that netdefgen created the following files:

  • MyNamespace.MyWebBrowser.def
  • System.Windows.Forms.Control.dll
  • System.Windows.Forms.def
  • System.Windows.Forms.WebBrowser.dll
  • System.Windows.Forms.WebBrowser.Base.dll

Compile the COBOL program as follows:
ccbl32 DotNetBrowser.cbl

Copy all 4 of the DLLs to the directory containing the wrun32.exe executable.

Run the COBOL program as follows:
wrun32 DotNetBrowser

Several things work as expected:

The graphical ACUCOBOL window appears, with the WebBrowser control.
The HTML page is correctly displayed.

Resize the window.
This triggers an NTF-RESIZED event, which the COBOL program detects.
The COBOL code calls the InvokeScript2 function from the MyWebBrowser class.
The InvokeScript2 function calls the JavaScript function, jsFunction.
As expected, a JavaScript alert appears, saying "COBOL called JavaScript".

Click the "Click to call .NET" button.
This triggers the JavaScript function, callDotNet.
The callDotNet function calls a C# function via the window.external object.
As expected, the Test function from MyWebBrowser pops up a message box.
The message box says: "JavaScript called .NET".

So far so good, but .NET events don't seem to be detected by the COBOL program.

The Test function in MyWebBrowser.cs is defined as follows:

        public void Test(String message) {
            MessageBox.Show(message);
            Document.Title = "a new title";
        }

One thing is broken. Nothing happened when the Document.Title property was changed.
I know that the Test function was called, because the MessageBox did appear.
I would then have expected the following to occur:

  • a .NET WebBrowser.DocumentTitleChanged event would be raised
  • the COBOL program would detect this event and perform USERCONTROL-EVENTS.

In the debugger, I can see that USERCONTROL-EVENTS is never performed. Why not?

0 Likes
1 Solution

Accepted Solutions
Highlighted
Micro Focus Expert
Micro Focus Expert

RE: .NET events are not detected

Jump to solution

It appears you've done everything correctly. Please submit this to Customer Care so Development can assess why the events are not being triggered.

View solution in original post

0 Likes
5 Replies
Highlighted
Micro Focus Expert
Micro Focus Expert

RE: .NET events are not detected

Jump to solution

Create a text file called NetEvents.ini with the directory path of where the runtime and dlls are.. Place NetEvents.ini in the runtime bin directory. See if that helps.

0 Likes
Highlighted
Absent Member.
Absent Member.

RE: .NET events are not detected

Jump to solution

I put the full paths to wrun32.exe and the DLLs, one per line, in a new file called NetEvents.ini. The file is in the same director y as wrun32.exe. Unfortunately the event procedure is still not being performed.

0 Likes
Highlighted
Micro Focus Expert
Micro Focus Expert

RE: .NET events are not detected

Jump to solution

It appears you've done everything correctly. Please submit this to Customer Care so Development can assess why the events are not being triggered.

View solution in original post

0 Likes
Highlighted
Absent Member.
Absent Member.

RE: .NET events are not detected

Jump to solution

Thanks. Will do.

0 Likes
Highlighted
Absent Member.
Absent Member.

RE: .NET events are not detected

Jump to solution

I got this working after all. I was doing some things wrong, which I only found by starting over with the AmortControl example (which is a .NET example) rather than basing my work on browser.cbl (which is an ACUGUI example).

I'm not sure if this helped, but I also changed the NETDEFGEN settings to use the 32-bit .NET 4.0 version of ILASM.EXE.

The HTML file:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>HTML5 + JavaScript Example</title>
<script type="text/javascript">
    // A function that the .NET ObjectForScripting object can call.
    // The function receives and displays a message, and then returns
    // the currently selected client.
    function getSelectedClient(message) {
        alert(message);
        var clients = document.getElementsByName("client");
        var client;
        for (var i = 0; i < clients.length; i++) {
            if (clients.type === "radio" && clients.checked) {
                client = clients.value;
            }
        }
        return client + " is selected";
    }
    function clientSelected(element) {
        var client = element.getAttribute("value");
        window.external.ScriptEvent("selected", client);
    }
</script>
</head>
<body">
<div>
    <fieldset>
        <legend>Select a client, and watch for the response from COBOL.</legend>
        <input type="radio" name="client" value="client A" onclick="clientSelected(this)"/>Client A<br />
        <input type="radio" name="client" value="client B" onclick="clientSelected(this)"/>Client B<br />
        <input type="radio" name="client" value="client C" onclick="clientSelected(this)"/>Client C<br />
    </fieldset>
</div>
</body>
</html>

The C# file:

using System;
using System.Windows.Forms;

namespace MyNamespace
{
    public delegate void EventFired();

    public class MyWebBrowser : WebBrowser
    {
        public event EventFired FireEvent;

        public MyWebBrowser()
        {
            Anchor = (AnchorStyles.Bottom | AnchorStyles.Right);
            ObjectForScripting = this;
        }

        public void Go(String UriString)
        {
            base.Navigate(UriString);
        }

        public void FillParent()
        {
            Size = Parent.ClientSize;
            Top = 0;
        }

        public String InvokeScript(String name, string arg)
        {
            // Call the specified JavaScript function in the HTML document.
            Object obj = Document.InvokeScript(name, new Object[] { arg });

            // Return what JavaScript returned to us.
            String s = obj.ToString();
            return s;
        }

        // The following function is provided as something that
        // JavaScript can call via IE's window.external object.
        public void ScriptEvent(String Name, String Data)
        {
            if (FireEvent != null)
            {
                // This will need to be modified to pass EventArgs.
                FireEvent();
            }
        }

    }
}

The COBOL file:

       IDENTIFICATION DIVISION.
       PROGRAM-ID.  AMORT.
       ENVIRONMENT DIVISION.
       CONFIGURATION SECTION.
       SPECIAL-NAMES.
       COPY "MyNamespace.MyWebBrowser.def".
           .

       DATA DIVISION.
       WORKING-STORAGE SECTION.
       77  SCREEN-1-HANDLE HANDLE OF WINDOW.

       77  KEY-STATUS IS SPECIAL-NAMES CRT STATUS PIC 9(4) VALUE 0.
         88  EXIT-PUSHED            VALUE 27.
         88  MESSAGE-RECEIVED       VALUE 95.
         88  EVENT-OCCURRED         VALUE 96.
         88  SCREEN-NO-INPUT-FIELD  VALUE 97.
         88  SCREEN-TIME-OUT        VALUE 99.

       01  CONFIGURATION-DATA.
         05  WS-LINES  PIC S99999V99 VALUE 40.
         05  WS-SIZE   PIC S99999V99 VALUE 80.

       01  URI  PIC X(256)
                VALUE "C:\Windows\Temp\DotNetBrowser\test.html".
       01  JAVASCRIPT-RETURN-VAL  PIC X(256) VALUE SPACE.

       COPY "acucobol.def".
       COPY "acugui.def".
       COPY "crtvars.def".

       SCREEN SECTION.
       01  SCREEN-1.
           03  WB-HANDLE, "MyWebBrowser",
                 NAMESPACE IS "MyNamespace",
                 CLASS-NAME IS "MyWebBrowser",
                 LINE 1, COL 1,
                 LINES WS-LINES, SIZE WS-SIZE
                 EVENT PROCEDURE IS USERCONTROL-EVENTS.

       PROCEDURE DIVISION.
           ACCEPT SYSTEM-INFORMATION FROM SYSTEM-INFO.
           ACCEPT TERMINAL-ABILITIES FROM TERMINAL-INFO.

           DISPLAY STANDARD GRAPHICAL WINDOW
               TITLE "Pace Scheduler", TITLE-BAR, NO WRAP,
               LINES WS-LINES, SIZE WS-SIZE, 
               AUTO-MINIMIZE, COLOR IS 65793,
               WITH SYSTEM MENU, 
               RESIZABLE,
               HANDLE IS SCREEN-1-HANDLE.

           DISPLAY SCREEN-1 UPON SCREEN-1-HANDLE.
           MODIFY WB-HANDLE "Go"(URI)
           INITIALIZE KEY-STATUS.

           PERFORM UNTIL EXIT-PUSHED
              ACCEPT SCREEN-1
               ON EXCEPTION
                 PERFORM EVAL-SCR-EXCEPTION
                 THRU    EVAL-SCR-EXCEPTION-EXIT
              END-ACCEPT
              IF EVENT-OCCURRED AND EVENT-TYPE = NTF-RESIZED
      *           Resize the .NET control to fill its resized parent.
                  DIVIDE EVENT-DATA-1 BY 100 GIVING WS-LINES
                  DIVIDE EVENT-DATA-2 BY 100 GIVING WS-SIZE
                  MODIFY WB-HANDLE
                    LINES WS-LINES
                    SIZE WS-SIZE
                  MODIFY WB-HANDLE "FillParent"()
              END-IF
           END-PERFORM.

           PERFORM EOJ THRU EOJ-EXIT
           GOBACK.

       EVAL-SCR-EXCEPTION.
           EVALUATE TRUE
              WHEN EVENT-OCCURRED
                 IF EVENT-TYPE = CMD-CLOSE
                    SET EXIT-PUSHED TO TRUE
                 END-IF
           END-EVALUATE
           MOVE 1 TO ACCEPT-CONTROL.
       EVAL-SCR-EXCEPTION-EXIT.
           EXIT.

       USERCONTROL-EVENTS.
           EVALUATE EVENT-TYPE
             WHEN MSG-NET-EVENT
               EVALUATE EVENT-DATA-2
                 WHEN @MyWebBrowser_FireEvent

                   DISPLAY MESSAGE BOX
                     "COBOL detected the .NET event, "
                     "@MyWebBrowser_FireEvent!"

      *            THE NEXT STATEMENT CALLS A C# FUNCTION IN THE
      *            WEB BROWSER CONTROL, WHICH IN TURN CALLS A
      *            JAVASCRIPT FUNCTION IN THE HTML DOCUMENT.
                   modify wb-handle
                     "InvokeScript"(
                       "getSelectedClient",
                       "COBOL called JavaScript via C#")
                     giving javascript-return-val

                      display message box
                        "COBOL received data from C#: "
                        javascript-return-val
               END-EVALUATE
           END-EVALUATE.
       USER-CONTROL-EVENTS-EXIT.
           EXIT.
 
       EOJ.
           DESTROY wb-handle.
           DESTROY screen-1-Handle.
       EOJ-EXIT.
           EXIT.

The end result is:

  • The COBOL program can use the .NET framework's WebBrowser.ObjectForScripting.InvokeScript function to call JavaScript functions in the WebBrowser's HTML document.
  • JavaScript can call a C# function, which in turn raises a .NET event that is detected by ACUCOBOL. (This is the piece that was broken before.)

Tags (1)
0 Likes
The opinions expressed above are the personal opinions of the authors, not of Micro Focus. By using this site, you accept the Terms of Use and Rules of Participation. Certain versions of content ("Material") accessible here may contain branding from Hewlett-Packard Company (now HP Inc.) and Hewlett Packard Enterprise Company. As of September 1, 2017, the Material is now offered by Micro Focus, a separately owned and operated company. Any reference to the HP and Hewlett Packard Enterprise/HPE marks is historical in nature, and the HP and Hewlett Packard Enterprise/HPE marks are the property of their respective owners.