Pavel Matras
Pavel Matras

Reputation: 349

How to pass array from Cobol to C# COM object

I need to pass array from MicroFocus Cobol to C# COM object. When I am passing only string or number it's working. But with array I got error message: **Exception 65537 not trapped by the class oleexceptionmanager. Description: "Server defined OLE exception"
(80070057): The parameter is incorrect.
** Cobol code:

C     $SET DIRECTIVES (SBODBC.DIR) NSYMBOL"NATIONAL"
  $set ooctrl(+p)

   identification division.
   program-id. pokus444.

   special-names.
       environment-name  is environment-name
       environment-value is environment-value
       decimal-point is comma.

   class-control.
     ChkAccNum is class "$OLE$CheckAccountNumber.AccountNumbers".

   working-storage section.
   01 ChkAccNumObj object reference.
   01 accA.
     05 acc pic x(34) occurs 100.
   01 accR pic x(34).

   procedure division.
   main section.
       display "Zacatek programu"
       initialize accA accR
       move '1234567890' to acc(1)
       move '0987654321' to acc(2)
       invoke ChkAccNum "new" returning ChkAccNumObj
       invoke ChkAccNumObj "CheckAccount" using accA returning accR
       display accR
       exit
       .

C# Code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace CheckAccountNumber
{
    [Guid("A80930D1-080F-4B04-A2C3-B637428556D6")]
    public interface IAccountNumbers
    {
        [DispId(1)]
        string CheckAccount(string[] accounts);
    }

    [Guid("65A771A0-0DDE-440D-9A4F-C71CEAEE3DF6"),
    ClassInterface(ClassInterfaceType.None)]
    public class AccountNumbers : IAccountNumbers
    {
        public AccountNumbers()
        {
        }

        public string CheckAccount(string[] accounts)
        {
            return accounts[1];
        }
    }
}

Upvotes: 2

Views: 473

Answers (1)

anok4u2
anok4u2

Reputation: 56

If you check out the typelib for the registered C# class you will see that it expects a SafeArray of type BSTR(string):

]
interface IAccountNumbers : IDispatch {
    [id(0x00000001)]
    HRESULT CheckAccount(
                    [in] SAFEARRAY(BSTR) accounts, 
                    [out, retval] BSTR* pRetVal);
};

Micro Focus COBOL (Net Express and Visual COBOL) support safe arrays so you can use code such as:

      $set ooctrl(+p)
       identification division.
       program-id. pokus444.

       special-names.
           environment-name  is environment-name
           environment-value is environment-value
           decimal-point is comma.

       class-control.
mftech     CharacterArray     is class "chararry"
mftech     OLESafeArray       is class "olesafea"
           ChkAccNum is class "$OLE$CheckAccountNumber.AccountNumbers".

       working-storage section.
mftech copy mfole.
mftech copy olesafea.
       01  ChkAccNumObj                 object reference.
       01  accA.
           05  acc                      pic x(34) occurs 100.
       01  accR                         pic x(34).
mftech 01  ws-stringArray               object reference.
mftech 01  ws-vartype                   pic 9(4) comp-5.
mftech 01  ws-dimension                 pic 9(4) comp-5.
mftech 01  ws-saBound                   SAFEARRAYBOUND occurs 1.
mftech 01  ws-iIndex                    pic 9(9) comp-5.
mftech 01  ws-len                       pic 9(9) comp-5.
mftech 01  ws-hresult                   pic 9(9) comp-5.

       procedure division.
       main section.
           display "Zacatek programu"
           initialize accA accR
           move '1234567890' to acc(1)
           move '0987654321' to acc(2)

      ***** Create a 1 Dimension OLESAFEARRAY to pass string array
           move VT-BSTR to ws-vartype
           move 1       to ws-dimension
           move 2 to cElements of ws-saBound(1) 
           move 0 to llBound of ws-saBound(1)
           invoke OLESafeArray "new" using by value ws-vartype
                                                    ws-dimension
                                           by reference ws-saBound(1)
               returning ws-stringArray
           end-invoke

      ***** Populate 2 Elements in OLESAFEARRAY
           move 0  to ws-iIndex
           move 10 to ws-len
           invoke ws-stringArray "putString"
                   using by reference ws-iIndex
                         by value     ws-len
                         by reference acc(1)
               returning ws-hresult
           end-invoke
           if ws-hresult not = 0
               display "Die Gracefully"
               stop run
           end-if
           move 1 to ws-iIndex
           move 10 to ws-len
           invoke ws-stringArray "putString"
                   using by reference ws-iIndex
                         by value ws-len
                         by reference acc(1)
               returning ws-hresult
           end-invoke
           if ws-hresult not = 0
               display "Die Gracefully"
               stop run
           end-if

           invoke ChkAccNum "new" returning ChkAccNumObj
      ***** Pass across the OLESAFEARRAY
           invoke ChkAccNumObj "CheckAccount" using ws-stringArray
                                          returning accR
           display accR
           stop run.

Upvotes: 3

Related Questions