Как передать массив из Cobol в C # COM-объект - PullRequest
2 голосов
/ 16 мая 2019

Мне нужно передать массив из MicroFocus Cobol в C # COM-объект. Когда я передаю только строку или число, это работает. Но с массивом я получил сообщение об ошибке: ** Исключение 65537 не захвачено классом oleexceptionmanager. Описание: "определенное сервером исключение OLE"
(80070057): неверный параметр.
** Код Кобола:

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

1 Ответ

3 голосов
/ 16 мая 2019

Если вы проверите библиотеку типов для зарегистрированного класса C #, вы увидите, что он ожидает SafeArray типа BSTR (строка):

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