Wpis z mikrobloga

Jak obiecałem tak robię, zaczynamy krótki kurs łączenia #excel poprzez #vba z #as400 / #iseries / #systemi

Niech będzie pod tagiem #vbas400 oraz #naukaprogramowania

Wersja PDF, lepsza do czytania: LINK DO DROPBOXA

Czym jest AS/400?

Tutaj posiłkuję się opisem na stronie: https://as400iseries.wordpress.com/2013/03/04/what-is-an-as400/
AS/400 (Application System/400) jest rodziną urządzeń wyprodukowanych przez firmę IBM, dla małych i średnich przedsiębiorstw lub działów w wielkich firmach, które potrafią komunikować się z kilkoma użytkownikami równocześnie. Mogą być one wykorzystywane do różnych zadań w świecie zarządzania danymi, np. w magazynach bądź nawet przedsiębiorstwach produkcyjnych. Zaprezentowane zostały przez IBM 21. czerwca 1988 roku, jako następca systemów System/36 oraz System/38 tej samej firmy, zapewniając pełną kompatybilność wsteczną. Jednak nazwa AS/400 jest coraz rzadziej używana, gdyż IBM sukcesywnie przemianowuje swoje produkty, najpierw na eServer iSeries, a potem na System i. System, na którym bazowo pracowały pierwsze maszyny to OS/400 (można szukać także pod późniejszą nazwą i5/OS bądź IBM i). Językami programowania dostępnymi w systemie AS/400 są m. in. RPG, Assembler, C, C++, Java, COBOL czy REXX. Urządzenia posiadają wbudowany system do obsługi baz IBM DB2, a do komunikacji z użytkownikiem wykorzystuje terminal IBM 5250 (popularny green screen).

No, to tyle ogólników! Przejdźmy do tego co chcemy!

Zapewne czytasz to aby się dowiedzieć jak połączyć staruśki i wpalający oczy czarny terminal posiadający zielone literki z nowiusieńkim i uwielbianym we wszystkich korpo Excelem. Jeśli nie, to też możesz dalej czytać, ale pewnie się zanudzisz.
Podstawą naszego kursu będzie ten oto pliczek PDF, a dokładniej strony od 199 do 326: >>KLIK<<

Z emulatorem terminala będziemy się łączyć przy pomocy Host Access Class Library (HACL), który to umożliwia nam dostęp do IBM Personal Communications (PCOMM).
https://i.imgur.com/j7LUGIp.png

Dobra, to są smęty, gdzie jest kod?!

Musimy zacząć od uruchomienia potrzebnych nam bibliotek w kodzie. Aby tego dokonać wchodzimy w edytor kodu VBA, a następnie Tools -> References i zaznaczamy odniesienia do bibliotek PCOMM:
https://i.imgur.com/YXaEXUY.png

Są to biblioteki:
- PCOMM autECLConnList Automation Object
- PCOMM autECLConnMgr Automation Object
- PCOMM autECLOIA Automation Object
- PCOMM autECLPS Automation Object
- PCOMM autECLScreenDesc Automation Object
- PCOMM autECLSession Automation Object

Tutaj chwila na dygresję. Gdy zaczynałem swoją przygodę z tym, ponad pół dnia spędziłem zastanawiając się dlaczego nic mi nie działa, gdy cały internet mówi, że musi działać. Okazało się, że nie miałem aktywowanych bibliotek (super problem xD), ale co gorsza, nie dawały się one aktywować przez złe odniesienia do ścieżek, których nie mogłem zmienić z uwagi na ograniczenia konta na służbowym komputerze. Dopiero pomoc kogoś z większymi uprawnieniami pomogła rozwiązać problem i ruszyć dalej do przodu!

Kiedy już poradzimy sobie z tym trudnym zadaniem dobrze jest zasiąść do pisania kodu. Na początek musimy zdefiniować obiekty, z jakich będziemy korzystać podczas pracy, dlatego na samej górze modułu z kodem umieszczamy to:

Public autECLSession As Object
Public autECLPS As Object
Public autECLOIA As Object
Public autECLConnMgr As Object
Public autECLScreenDesc As Object
Public autECLConnList As Object

Tym samym uzyskujemy dostęp do tych obiektów w całym arkuszu. Nazwy są dowolne, ale na start polecam takie, gdyż pod takimi nazwami możemy szukać pomocy w dokumentacji. Jak już mamy to gotowe to czas zacząć łączyć się z naszym emulatorem terminala, ale najpierw musimy jeszcze do tych zmiennych przypisać odpowiednie obiekty:

Sub AS400DefineVariables()
Set autECLSession = CreateObject("pcomm.auteclsession")
Set autECLPS = CreateObject("Pcomm.auteclps")
Set autECLOIA = CreateObject("Pcomm.autecloia")
Set autECLConnMgr = CreateObject("PCOMM.autECLConnMgr")
Set autECLScreenDesc = CreateObject("PCOMM.autECLScreenDesc")
Set autECLConnList = CreateObject("PCOMM.autECLConnList")
autECLConnMgr.RegisterStartEvent
End Sub

Nazwa Suba jest dowolna, tak samo jak nazwa zmiennych, ważne tylko, żeby ich nazwy pokrywały się z definicjami z poprzedniego kodu. Co do ostatniej linii, to jeszcze nie do końca ogarnąłem jak porządnie korzystać z RegisterStartEvent, ale lepiej mieć niż nie ;)

To teraz chwila na spojrzenie na okno terminala (chyba będę korzystał z ogólnodostępnych obrazków):
http://media.techtarget.com/digitalguide/images/Misc/johnson_ptb_1.jpg

Każde okno ma swój unikalny znak, który je definiuje. Jest to wielka lub mała litera alfabetu, widoczna na belce programu. Okno przedstawione na Rys. 4. posiada identyfikator „A”. Jest to bardzo istotne, ponieważ w następnym kroku musimy określić z jakiego okna będziemy korzystać i MUSI być ono już otwarte (później pokażę jak uruchamiać nowe okno, gdy nie jest ono uruchomione bądź okno emulatora pod dostarczoną literą nie istnieje). Aby połączyć się z istniejącym oknem terminala wykorzystamy kod:

Sub AS400DefineConnection(strName As String)
autECLSession.SetConnectionByName (strName)
autECLPS.SetConnectionByName (strName)
autECLOIA.SetConnectionByName (strName)
If autECLSession.CommStarted = False Then
Set autECLSession = Nothing
Set autECLPS = Nothing
Set autECLOIA = Nothing
Set autECLConnMgr = Nothing
Set autECLConnList = Nothing
Set autECLScreenDesc = Nothing
End
End If
End Sub

Definiujemy tutaj połączenie się bilbliotek Session, PS oraz OIA z konkretnym oknem terminala, które definiujemy poprzez, w tym przypadku, zmienną strName. Równie dobrze możemy to zastąpić literą („A”) bądź wartością z komórki arkusza (Cells(1,1).Value). Jeżeli kod nie zdoła się połączyć z wymaganym oknem przypisuje wszystkim zmiennym wartość „Nothing" i kończy pracę.

Jeśli tylko wszystko dobrze poszło i Excel nie przywitał nas żadnymi błędami, właśnie zostałeś połączony z oknem terminala i możesz robić cuda. Jednocześnie nic nie stoi na przeszkodzie, abyś w tym samym czasie korzystał z tego terminala w dowolny sposób ręcznie.

To przed końcem tej części poruszę jeszcze na szybko cztery podstawowe funkcje, które pozwolą Ci już ruszyć z pisaniem własnych rzeczy, a które potem zostaną omówione szerzej lub przedstawione zostaną ich rozbudowane wersje. Są to funkcje (na zielono strony w dokumentacji):

- autECLSession.autECLPS.SendKeys ‘243
- autECLSession.autECLPS.GetText ‘244
- autECLSession.autECLOIA.WaitForAppAvailable ‘231
- autECLSession.autECLOIA.WaitForInputReady ‘230

Pierwsza z nich pozwala na wysyłanie znaków bądź komend do okna terminala. Przykładowy kod wygląda tak:

Sub ASInput()
autECLSession.autECLPS.SendKeys(„TEST”, 2, 5)
End Sub

Powyższy kod wyśle do terminala tekst “TEST”, umieszczając pierwszy znak na pozycji [2,5]. Teminal AS400 z reguły ma wymiary [24 x 80], czyli 24 wierszy i 80 kolumn. Jeden znak zajmuje jedną pozycję, czyli słowo „TEST” zajmie cztery pozycje, opierając się na kodzie: [2,5], [2,6], [2,7] i [2,8]. Należy też pamiętać, aby miejsce, w które chcemy wysłać znaki było edytowalne oraz wystarczająco długie.

W powyższej funkcji jedynie pierwszy argument jest konieczny, pozostałe dwa są opcjonalne, ale gdy się zdefiniuje jeden z nich trzeba też zdefiniować drugi. Bez definicji pozycji tekst zostanie wklejony w miejsce, w którym aktualnie znajduje się kursor w terminalu.

Aby wysłać komendy takie jak Enter lub Tab (przeskakiwanie pól), umieszczamy ich nazwy w nawiasach kwadratowych, np. „[enter]” lub „[tab]”. Pełną rozpiskę dostępnych komend znajdziesz w dokumentacji na stronie 397 (polecam zainteresować się komendą [eraseeof]).

Druga funkcja pozwala na odczytanie kodu z okna terminala. Przykładowy kod:

Function ASGet() as String
ASGet = autECLSession.autECLPS.GetText(2, 2, 5)
End Function

Powyższa funkcja sczytuje 5 znaków z okna terminala, zaczynając od pozycji [2,2] i zwraca to w postaci Stringa. Funkcja ta pozwala sczytywać znaki tylko z jednego wiersza, do odczytywania znaków z kliku kolumn i wierszy na raz dojdziemy potem, albo szybciej sam/sama się dowiesz ;)

Ostatnie dwie funkcje potraktujemy jako jedną wspólną. Przykładowy kod:

Sub ASWait()
autECLSession.autECLOIA.WaitForAppAvailable
autECLSession.autECLOIA.WaitForInputReady
End Sub

Krótko mówiąc, powyższa funkcja czeka aż okno terminala zrobi wszystko co miało zrobić i będzie ponownie gotowe na przyjmowanie komend. Dzięki odpowiedniemu umieszczeniu tych linii w kodzie możemy zabezpieczyć się przed wysyłaniem poleceń do terminala zanim zdąży on wykonać poprzednie polecenie.

UWAGA! Ta funkcja nie posiada czasu oczekiwania, po prostu czeka w nieskończoność na wolny terminal, więc jeśli przez przypadek zablokujemy input np. wysyłając błędne klawisze, nasz program zatnie się na tych dwóch liniach (konkretniej na drugiej) i będzie czekał w nieskończoność na odblokowany terminal. Możemy go odblokować wtedy ręcznie i program powinien dalej ruszyć (chociaż jeśli coś tak sknociliśmy, że terminal sypnął błędem, to dalszy kod raczej jeszcze bardziej się wywali na głupi ryj). W dalszej części kursu pokażę jak w inny sposób można z tym sobie poradzić, unikając zawieszenia programu, a nawet wprowadzając odpowiedź na błędy, których się spodziewamy.
  • 21
@Polinik nie "Session A" tylko samo "A"
Jak chcesz wysyłać rzeczy do terminala to w tym samym bloku musi być też połączenie z oknem, czy wcześniej musisz napisać:
AS400DefineVariables
AS400DefineConnection "A"

Teoretycznie definicja zmiennych jeśli raz to zrobiłeś nie jest konieczna, ale warto zrobić
autECLSession.autECLPS.SendKeys(„TEST”, 2, 5)


@DarkAlchemy:
Tu masz errora -- jak dasz w nawiasie -- nie będzie działać wersja z pozycją.
Albo dajesz:

autECLSession.autECLPS.SetCursorPos 2, 5
autECLSession.autECLPS.SendKeys ("TEST")

albo
autECLSession.autECLPS.SendKeys "TEST", 2, 5

( ͡ ͜ʖ ͡)