none
VB.NET ArgumentException passing context object RRS feed

  • Question

  • Hi Everyone,
                        I am migrating a VB6 application using Transaction integrator to talk to CICS/MVS (HIS2006) using VB.net  and am hitting problems trying to make the method call to the mainframe.  I cannot paste code from our actual application (not allowed by company policy) so I have simulated what I am trying to do:

    The following is an example of what sort of COBOL layout I would be using:

          01  FUNCTION-OUTPUT-AREA.
            02  SOME-DATA.                                                    INOUT
          * USER DEFINED TYPE
             03  FIELD1                       PIC X(4).                    INOUT
             03  DATE-AND-CODE OCCURS 20 TIMES.                             INOUT
          * USER DEFINED TYPE
              04  DATE1                       PIC X(8).                   INOUT
              04  CODE                        PIC X.                      INOUT
            02  VARIABLE OCCURS 5000 TIMES    PIC X.                        OUTPUT


    The original VB6 code would look like this:

        Dim astrFinalData() As String
        Dim objLU62 As TypelibLU62.LU62
        Set objLU62 = CreateObject("TypelibLU62.LU62")

        Dim objDates As TypelibLU62.DATES
        ReDim objDates.DATE-AND-CODE (20)

        objLU62.GetProcessDate(objDates, astrFinalData, COMTIContext)


    And would result in objDates being populated with data and astrFinalData with zero to 5k bytes of data (it has no fixed layout and has to be parsed by the client).

    To make the same call using vb.net I tried:

    Dim COMTIContext As Object
        Dim ContextObj As New COMTICONTEXTLib.ContextObject
        ContextObj.WriteContext("USERID", "USER0001", COMTIContext)
        ContextObj.WriteContext("PASSWORD", "PASS0001", COMTIContext)
    
        Dim objLU62 As TypelibLU62.LU62
        Dim objDates As new TypelibLU62.DATES
        Dim hol(19) As objDates.DATE-AND-CODE
        objDates.HOLIDAY = hol
    
          Try
    
             objLU62.GetProcessDate(objDates, astrFinalData, COMTIContext)        
    
            Catch NR As NullReferenceException
                Stop
            Catch IC As InvalidCastException
                Stop
            Catch AE As ArgumentException
                Stop
            Finally
                Stop
            End Try

    This results in an argumentException  "The specified record cannot be mapped to a managed value class".  If I remove the context object from the method call I get a security error which is what I would expect.  I am very new to VB.net and I am assuming that the context object is a variant type and .net doesn't know what to do with it.  I am using Host integration server 2006 and the original typelib created for the vb6 application.

    The code I am using seems pretty similar to what I found here: example

    The request to the mainframe is being sent and received ok i.e. I can see all the data in an SNA trace, but VB seems to be having trouble processing the response.

    Any help would be appreciated, I am assuming that the code itself is reasonably correct and that I just need to allow .net runtime/configure the project to be able to translate the response.

    Regards,

    Phil.

         


    • Edited by Phil Gabriel Monday, July 9, 2012 4:09 AM missed word
    Monday, July 9, 2012 4:05 AM

Answers

  • Just to check here, you are using COM-Interop, right? You have not converted your typelibrary to a .NET Assembly? If this is the case, then the problem is on the way back out, when COM interop tries to convert the unmanaged user defined structure to a managed structure. I think you might have to play with TlbImp in order for this to work, a la:

    http://msdn.microsoft.com/en-us/library/aa645736(v=VS.71).aspx

    Could you try converting to an Assembly (using TI Designer in VS, you should be able to create a new TI Assembly and import the typelibrary), then try running against that, instead of against the typelibrary - we put annotations in the Assembly which map the managed/unmanaged structures.

    Rob

    • Marked as answer by Phil Gabriel Thursday, July 12, 2012 1:52 AM
    Tuesday, July 10, 2012 8:18 PM
    Moderator

All replies

  • I'm not a TI expert, but based off our sample code (C:\Program Files\Microsoft Host Integration Server 2010\SDK\Samples\ApplicationIntegration\WindowsInitiated\BasicScenarios\VBNetClient), and you have the copybook similar to C:\Program Files\Microsoft Host Integration Server 2010\SDK\Samples\ApplicationIntegration\WindowsInitiated\BasicScenarios\TIHostApplicationDef\CICSGetAcctsLink.cbl, you would do this:

        Sub GetAccounts()
            Dim accounts As TINetBasic.Accounts
            Dim name As String = "Kim Akers"
            Dim pin As String = "0123456789"
            Dim accountInfoArray(6) As AcctInfo
            Dim ai As AcctInfo
    
            accounts = New TINetBasic.Accounts
            accountInfoArray = Accounts.GetAccounts(name, pin)
            Console.WriteLine("Account name={0}, pin={1}", name, pin)
            Console.WriteLine("Elements={0}", accountInfoArray.Length.ToString(System.Globalization.CultureInfo.InvariantCulture))
    
            For Each ai In accountInfoArray
                Console.WriteLine("Account number: {0}", ai.Number)
                Console.WriteLine(ControlChars.Tab + "Type:" + ControlChars.Tab + "{0}", ai.Type)
                Console.WriteLine(ControlChars.Tab + "Balance:" + ControlChars.Tab + "{0,18:C2}", ai.CurrentBalance)
                Console.WriteLine(ControlChars.Tab + "Interest Bearing:" + ControlChars.Tab + "{0}", ai.InterestBearing.ToString(System.Globalization.CultureInfo.InvariantCulture))
                Console.WriteLine(ControlChars.Tab + "Interest Rate:" + ControlChars.Tab + "{0}", ai.InterestRate.ToString(System.Globalization.CultureInfo.InvariantCulture))
                Console.WriteLine(ControlChars.Tab + "Monthly Service Charge:" + ControlChars.Tab + "{0,5:C2}" + ControlChars.NewLine, ai.MonthlySvcChg)
            Next
    
        End Sub

    Hope that helps!!

    Charles Ezzell - MSFT

    Monday, July 9, 2012 5:12 PM
  • Hi Charles,
              That must be a newer version of the sample than the one that came with HIS2006.  The problem that I have is that when my program goes to execute the line that is equivalent to:

    Accounts.GetAccounts(name, pin)

    in the example you provided, it throws an exception.  I think that it is because my project is not setup correctly somehow so that VB is not able to handle the user defined types from the typelib.  I know that the typelib is valid and matches the COBOL definition because I can use it with VB6 ok.  My plan for today is to create another copybook that  simply passes one long string as input and output to try and narrow down whether it is the COMTI security object the is generating the argument exception.

    I got the following sample from:
    C:\Program Files\Microsoft Host Integration Server 2006\SDK\Samples\ApplicationIntegration\WindowsInitiated\BasicScenarios\VBNetClient

        Sub Main()
            Dim MyObj As TINetBasic.Accounts
            Dim AccBal As Decimal
    
            AccBal = 0
    
            MyObj = New TINetBasic.Accounts
            MyObj.GetBalance("Kim Akers", "123456", AccBal)
            Console.WriteLine("VBNet Basics: Account Balance = {0,9:C2}", AccBal)
    
            Console.WriteLine("Press any key to continue...")
            Console.Read()
        End Sub

    It is similar to what I am doing, but with no security object.  I am working with much more complex layouts with hundreds of fields, which unfortunately can't be altered to a layout that is easier to deal with.

    Regards,

    Phil.



    Monday, July 9, 2012 8:36 PM
  • UPDATE:  It turns out that the context object is not the problem.  I can now get data back by making the entire request one big string.  However, in VB.net the string is truncated because there are binary zeroes in the transmission.  In VB6 the entire string is accessible.  So I am back to my original problem of needing to pass a structure that matches the COBOL copybook layout so that I can access each field individually.

    Any suggestions appreciated.

    Regards,

    Phil.

    Tuesday, July 10, 2012 2:24 AM
  • Do you know what parameter the error is occurring on? If you can narrow it down to a particular parameter that might help get to the cause of the problem. It may be that you have to alter some of the parameter data types for the new .NET environment.

    Thanks...


    Stephen Jackson - MSFT

    Tuesday, July 10, 2012 7:35 PM
  • Sounds as if the data is coming back as Unicode data, so you will need to use the appropriate data type.

    Charles Ezzell - MSFT

    Tuesday, July 10, 2012 7:42 PM
  • Just to check here, you are using COM-Interop, right? You have not converted your typelibrary to a .NET Assembly? If this is the case, then the problem is on the way back out, when COM interop tries to convert the unmanaged user defined structure to a managed structure. I think you might have to play with TlbImp in order for this to work, a la:

    http://msdn.microsoft.com/en-us/library/aa645736(v=VS.71).aspx

    Could you try converting to an Assembly (using TI Designer in VS, you should be able to create a new TI Assembly and import the typelibrary), then try running against that, instead of against the typelibrary - we put annotations in the Assembly which map the managed/unmanaged structures.

    Rob

    • Marked as answer by Phil Gabriel Thursday, July 12, 2012 1:52 AM
    Tuesday, July 10, 2012 8:18 PM
    Moderator
  • Just to check here, you are using COM-Interop, right? You have not converted your typelibrary to a .NET Assembly? If this is the case, then the problem is on the way back out, when COM interop tries to convert the unmanaged user defined structure to a managed structure. I think you might have to play with TlbImp in order for this to work, a la:

    http://msdn.microsoft.com/en-us/library/aa645736(v=VS.71).aspx

    Could you try converting to an Assembly (using TI Designer in VS, you should be able to create a new TI Assembly and import the typelibrary), then try running against that, instead of against the typelibrary - we put annotations in the Assembly which map the managed/unmanaged structures.

    Rob

    Hi Rob,
           You are correct that I am COM-Interop and I was able to complete the host transaction by redefining the layout so that it only used simple types (string or array of string). I will try importing the original typelib as an assembly and report back.

    Regards,
    Phil.

             

    Tuesday, July 10, 2012 9:10 PM
  • Do you know what parameter the error is occurring on? If you can narrow it down to a particular parameter that might help get to the cause of the problem. It may be that you have to alter some of the parameter data types for the new .NET environment.

    Thanks...


    Stephen Jackson - MSFT

    Hi Stephen,
                      I am going to try importing the typelib as an assembly as suggested by Rob.  I could get around this problem, by redefining the array as one big string and try and parse it, but the problem I would face is that where they return binary zeroes the string truncates and I would not be able to access all of the data.  I have another solution, which is more or a last resort and that is to define every request/response as an array of bytes and manually process the response, but that is a lot of work especially translating the packed fields.  

    Regards,
    Phil.

    Tuesday, July 10, 2012 9:17 PM
  • I tried using 'TlbImp', and created an assembly, but still seemed to have the same problem.  So I exported the original Typelib to a COBOL copybook and then imported it back as an assembly and now it works.

    Thank you to all who contibuted.

    Regards,
    Phil.
    Thursday, July 12, 2012 2:06 AM