Created On:  19 July 2012

Problem:

How can I call a .NET managed code application that uses Windows Presentation Foundation forms from a native code COBOL application?

Resolution:

This can be done by registering the .NET managed class library for COM Interop and then instantiating the class and calling its methods using the COM client support libraries available to Visual COBOL native programs.

An example is attached to this article which demonstrates how to do this.

The calling native program:

*--------------------------------------------------------------------------------------*
*                                  TESTCALLWPF                                         *
*                                                                                      *
* This example program demonstrates how a native console COBOL program can call a man- *
* aged code class which will then display WPF forms.                                   *
*                                                                                      *
* Project testcallWPF is a native code console application compiled into an .EXE.      *
* Project WPFclass is a managed code class library project which has the "Register for *
* COM Interop" setting turned on under Project-->Properties-->COBOL tab-->Advanced.    *
* This causes Visual Studio to register the .DLL as a COM server so that is can be     *
* accessed by a COM client.                                                            *
*                                                                                      *
* Program testcallWPF communicates with the WPFclass program using the COM client class*
* support available in Visual COBOL (inherited from Net Express).                      *
*                                                                                      *
* The method displayWPF is called from the native program, passing a COBOL pic x as a  *
* string. The managed class then instantiates the form and displays the passed string. *
* When the user enters a new string and clicks the close button, the new string will be*
* passed back to native COBOL where it will be displayed on a console.                 *
*                                                                                      *
* The solution is currently setup to debug the managed code project. Look at the       *
* project properties for WPFclass on the Debug tab and you will see that it is set to  *
* start debugging by running the native .EXE. Set a breakpoint in managed code and     *
* press F5 to start debugging the managed code.                                        *
*--------------------------------------------------------------------------------------*

$set ooctrl(+p)
 id division.
 program-id. testcallWPF.
 class-control.
   WPFclassServer is class "$OLE$WPFclass.WPFclass".
 working-storage section.
 01 anInstance object reference.
 01 aString pic x(50) value spaces.
 01 any-key pic x.
 procedure division.
    invoke WPFclassServer "new" returning anInstance
    move "from native COBOL..." to aString
    invoke anInstance "displayWCF" using aString
    display aString
    accept any-key
    stop run.

The managed code class library:

*--------------------------------------------------------------------------------------*
*                                   WPFCLASS                                           *
*                                                                                      *
* This is the class program which contains the method which will be called through COM *
* by the native code COBOL program. An Interface is defined for any methods that will  *
* be called thru COM as these are the methods that are made available thru the COM int-*
* erface.                                                                              *
*                                                                                      *
* The example shows how WPF forms can be displayed when called by a native program.    *
* For that reason the managed code project is created as a Class Library so that a .DLL*
* is created instead of an .EXE which would be created if the project was created as a *
* WPF application. The WPF Form is then added to this project and can be instantiated  *
* within this class which is called by COM.                                            *
*                                                                                      *
* The method displayWPF is called from native, passing a COBOL pic x as a string.      *
* A new thread is created as STA apartment type as this is required when using WPF as  *
* by default MTA apartments are used.                                                  *
* The WPF form is then instantiated and the native string is passed to it to be dis-   *
* played. When the user enters a new string and clicks the close button, the new string*
* will be passed back to native COBOL where it will be displayed on a console.         *
*--------------------------------------------------------------------------------------*
$set ilusing"System.Threading"
 identification division.
 interface-id. InterfaceDef as "IWPFclass".
 environment division.
 repository.
 method-id. displayWCF public.
 local-storage section.
 procedure division using lnkString as string.
 end method.
 end interface InterfaceDef.
 class-id WPFclass.WPFclass implements type IWPFclass.
 working-storage section.
 01 myWindow type WPFclass.Window1.
 01 myThread type Thread.
 01 myString string.
 method-id displayWCF.
 local-storage section.
 procedure division using passedstring as string.
     set myString to passedstring
*> WPF must be run on STA threads.
     set myThread to new Thread(new type ThreadStart(self::WPFThread))
     invoke myThread::SetApartmentState(type ApartmentState::STA)
     invoke myThread::Start
     invoke myThread::Join
     set passedstring to myString *> set string passed back from WPF to return to native COBOL
     goback.
 end method.
 method-id WPFThread public.
 procedure division.
     set myWindow to new WPFclass.Window1
     set myWindow::passedstring to mystring *> set string property in WPF class so that it can be displayed
     invoke myWindow::handleWindow
     set myString to myWindow::passedstring
     goback.
 end method.
 end class.

WPF window class:

 class-id
WPFclass.Window1 is partial
   inherits type System.Windows.Window.
 working-storage section.
 01 passedstring string property.
 method-id NEW.
 procedure division.
    invoke self::InitializeComponent()
    goback.
 end method.
 method-id handleWindow public.
 procedure division.
     set textBox1::Text to passedstring
     invoke self::ShowDialog
     set passedstring to textBox1::Text
     goback.
 end method.
 
 method-id
button1_Click final private.
 procedure division using by value sender as object e as type System.Windows.RoutedEventArgs.
     invoke self::Close
 end method.
 end class.