如何将数组从 Cobol 传递到 C# COM 对象

How to pass array from Cobol to C# COM object

我需要将数组从 MicroFocus Cobol 传递到 C# COM 对象。当我只传递字符串或数字时,它正在工作。但是使用数组我收到错误消息: **异常 65537 未被 class oleexceptionmanager 捕获。 说明:"Server defined OLE exception"
(80070057): 参数不正确。
** Cobol代码:

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#代码:

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];
        }
    }
}

如果您查看已注册 C# 的类型库 class,您会发现它需要一个 BSTR(string) 类型的 SafeArray:

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

Micro Focus COBOL(Net Express 和 Visual COBOL)支持安全数组,因此您可以使用如下代码:

      $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.