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?
#Events
#System.Windows.Forms.WebBrowser
#.net
#ACUCOBOL9.2.1