Using C#.NET with the Kofax KTM Validation Module

My current project has a requirement to do several Oracle EBS validations and lookups from the Kofax KTM validation window. For example, one requirement is to present the validator with a list of Suppliers. Another is to check for a duplicate invoice number in EBS. I can easily add additional methods as needed.

Kofax KTM provides Win Basic scripting language that can accomplish some of this, but it’s difficult to use compared to modern programming languages. After a little research I discovered it was feasible to create and call methods in a COM object from KTM Win Basic. This meant I could expose a C#.NET dll via COM Interop but have all the power of any version of the .NET framework and Microsoft Visual Studio available to do the heavy lifting.

My C# methods return either arrays or booleans back to KTM where I then use the Win Basic language to present results to the validation user. I can debug my C# code by attaching to the KTM Project Builder exe while running validation tests.

Setting up the C# Class

The first step is to create a project in Visual Studio and set up a class to contain the methods you will call in KTM. The prefered method is to use interfaces in case you need to change the methods without breaking the inferface. Here is an example. You need to create your own unique GUIDs and expose the compiled dll to COM. The dll will need to be registered on all Kofax stations doing validation. Client setup will also involve setting up data base client drivers if validation will require lookups.

using System;
using System.Data;
using System.Runtime.InteropServices;
using Oracle.DataAccess.Client;
using System.Collections.Generic;
namespace ImageSource.APInvoice
    public interface IKTMUtils
        string[] LookupVendors(string searchString);
        bool CheckForDuplicateInvoice(string searchString);
    /// Class that implements various Kofax KTM lookups and validations.
    public class KTMUtils : IKTMUtils
        #region declarations and process entry point

        public KTMUtils() { }

        #region execute methods
        /// Retrieves a list of vendor names and id's.
        ///3 characters of Vendor name.
        /// String array containing pipe
        ///delimited vendor id and name.
        public string[] LookupVendors(string searchString)
            List vendorInfo = GetVendorNameAndID(searchString);
            string[] vArray = new string[vendorInfo.Count];
            int x = 0;
            foreach (var vendor in vendorInfo)
                vArray [x] =  vendor.VendorID.ToString() + "|"
                       + vendor.VendorName;
            return vArray;

rest of code truncated…

In the code above, GetVendorNameAndID calls a method that does the actual DB lookup. The calling method uses a Vendors class to type the vendor fields returned from the lookup. Note the creation of a simple array to hold the vendor data. Fields are delimited with a pipe, the array is filled up, then passed back to KTM. The search string is required to be at least 3 characters in KTM and restricts the vendor lookup.

The KTM Code

On the KTM side you need to respond to a button click to do the vendor lookup:

Private Sub ValidationForm_ButtonClicked(ByVal ButtonName As String,
       ByVal pXDoc As CASCADELib.CscXDocument)
   Select Case ButtonName
      Case "btnVendorLookup"
   End Select
End Sub

The Display Vendors code looks like this:

Private Sub DisplayVendors(ByVal pXDoc As CASCADELib.CscXDocument)
   On Error GoTo UhOh
   Dim lookupString$
   lookupString =  pXDoc.Fields.ItemByName("VendorName").Text
   lookupString = Trim$(lookupString)
   'get results from dll...
   Dim o As Object
   Set o=CreateObject("ImageSource.KTMUtils") 'get handle to c# dll
   Dim x() As String 'create local array
  'call the method in the c# dll to fill

   x = o.LookupVendors(lookupString)
   Set o = Nothing
   'if null array bail...
   If IsNull(x) Then
      MsgBox("Error Accessing Vendors",vbCritical, "")
      Exit Sub
   End If
   'if no values returned, bail...
   If UBound(x) = -1 Then
      MsgBox("No Vendor Found",vbInformation, "")
      Exit Sub
   End If
   'display vendor...
   Dim numVendors%
   numVendors = UBound(x) + 1 '0 based array
   Dim VendorID$
   Dim VendorName$

   'populate now if only one vendor...
   If numVendors = 1 Then
      VendorID = Split(x(0), "|") (0)
      VendorName = Split(x(0), "|") (1)     
      pXDoc.Fields.ItemByName("VendorName").Text = VendorName
      pXDoc.Fields.ItemByName("VendorNum").Text = VendorID

      'force vendor name valid...
      pXDoc.Fields.ItemByName("VendorName").Valid = True
 Exit Sub     
   End If
   'show a list box if more than one vendor...
   If numVendors > 1 Then
      'list box
       Dim lists$()
       ReDim lists$(numVendors - 1) '0 based index
       'populate list with vendors - vendorname - vendorsitecode...
       Dim i%
       For i = 0 To numVendors - 1
         lists$(i) = Split(x(i), "|") (0) + " - "
               + Split(x(i), "|") (1)
       Next i
       'display it...
       Begin Dialog Vendors 450,120,"Vendors"
           Text 10,10,180,15,"Please push the OK button"
           DropListBox 10,25,400,60,lists$(),.list1
           OKButton 300,90,60,20
           CancelButton 365,90,60,20
       End Dialog
       Dim dlg As Vendors
       Dialog dlg ' show dialog (wait for ok)

   Dim chosenIndex%
       chosenIndex = dlg.list1
      'assign array values from chosen vendor...
      VendorID = Split(x(chosenIndex), "|") (0) 'first dimension
      VendorName = Split(x(chosenIndex), "|") (1)

      'display values in validation form...
      pXDoc.Fields.ItemByName("VendorName").Text = VendorName
      pXDoc.Fields.ItemByName("VendorNum").Text = VendorID

      'force vendor name valid...
      pXDoc.Fields.ItemByName("VendorName").Valid = True
      pXDoc.Fields.ItemByName("VendorName").ExtractionConfident = True  Exit Sub
    End If
   If Err.Description = "User pressed cancel." Then
      Exit Sub
   End If
   MsgBox("Error Accessing Vendors: " + Err.Description,vbCritical, "")
End Sub

There are a lot of details not discussed here but the above is the jist of it!

Clint Lewis
Senior Systems Engineer
ImageSource Inc.