Skip to content

Session State & Globals

The legacy app has no dependency injection and no per-request context. Instead, session and configuration state live in module-level global variables declared in INVENTORY/Module/VariablePublic.vb, set once at startup/login, and read directly from anywhere in the codebase.

Understanding these globals is essential: half the code assumes they are already populated.

Startup: Sub Main

Entry point is Sub Main in VariablePublic.vb (MySubMain=true, MainForm=MenuUtama).

flowchart TD
    A["Sub Main"] --> B["Resolve host IP → memIP"]
    B --> C["SystemRegistry.GetRegistry()<br/>read server, db, uid, password, skin<br/>(all obfuscated)"]
    C --> D["License / expiry gate<br/>REF_SYSTEM + license.smartsoft.co.id"]
    D --> E["ConnStr = HAKDAC.GetConnectionString(...)"]
    E --> F["ApplicationVersion.CheckingApplicationVersion()"]
    F --> G["SynchroniseDateTime.SetDeviceTime()<br/>slave PC clock+locale to SQL Server"]
    G --> H["ModiStructure.CheckingFileModiStructure()"]
    H --> I["Show MenuUtama → login"]
    style C fill:#fff3e0,stroke:#fb8c00
    style G fill:#fff3e0,stroke:#fb8c00

Steps in order:

  1. Resolve IPDns.GetHostByName(...)memIP.
  2. Load config from the Windows RegistrySystemRegistry.GetRegistry() reads HKCU\Software\VB and VBA Program Settings\SmartSoft\SystemSetting\<AppName>: ServerName, DataBaseName, UID, Password, DataBaseNameBackup, Skin (plus host-to-host H2H* values). Every value is obfuscated and decoded with PassToChar.
  3. License / expiry gate — for non-POS apps, opens a test connection, reads the "Expired Date" from REF_SYSTEM, and if expired calls the cloud license API https://license.smartsoft.co.id/license?client_id=<KodeCabang>. Connection failure → pops frmSystemSetting.
  4. Build ConnStrHAKDAC.GetConnectionString(server, db, uid, pwd) (SQL auth; credentials sit in the string in cleartext).
  5. Version checkApplicationVersion.CheckingApplicationVersion() (uses the EXE file timestamp as the version).
  6. Clock syncSynchroniseDateTime.SetDeviceTime(...) forces the workstation clock and date/number formats to match the SQL Server (see below).
  7. Schema checkModiStructure.CheckingFileModiStructure(...) behind a splash.

Sub Main runs again from MenuUtama_Load

MenuUtama.vb re-invokes the bootstrap on load — re-reading branch code / IP from the registry, loading parameters, applying skin/logo, and wiring the login panel. Don't be surprised to see startup work happen in two places.

The global singletons

Declared Public … As New at module scope — effectively app-wide singletons.

Global Type Holds
HAKDAC General.DataAccessControl The primary data gateway — runs queries/non-queries, existence checks.
HAKCVT General.Convertion Formatting + the password/registry cipher (PassToChar/CharToPass), numeric/string helpers.
HAKFUNC MyLib.HAKFunction Login, station identity, access-menu building, image helpers, warehouse lookup.
LocFunc MyFunction (app-local) App-specific helper functions.
cPRSH Parameter.PERUSAHAAN Company / branch master. PRSH_KODE = branch code; PRSH_TGLAKTIF = system active date; name/address/PPN/HO/closing/logo.
cPARAM / cPRM Parameter.tbTabel_Parameter / tv_Parameter Config parameters (PRM_CLOSINGHARIAN, PRM_MULTIGUDANG, PRM_MULTICABANG, colours/fonts).
cSTOK BLL.STOCK Stock & costing business logic (GetAvgCost, recompute).
cCOMP Parameter.tbMaster_Computer This workstation's record (keyed by IP + station); printer name, active user.

The session variables

Set at login / post-login and read throughout.

Variable Meaning Set where
ConnStr Active SQL connection string Sub Main
memIP, memStation Machine identity Sub Main / login
memTanggal Business/system date (not always "now") MenuUtama_Load
memUserID, memUserName, memUserNIK Logged-in user On successful login
memUserPassword User's (deciphered) password On login
memUserLevel User level User-admin only
memLokasiGudang Active warehouse/location Post-login via HAKFUNC.LokasiGudang(...)
memServerName, memDataBaseName, memUID, memPassword Raw registry config Sub Main

There is no memKodeCabang

The branch code you'll look for is cPRSH.PRSH_KODE — the company/branch object fills that role. (Some docs/specs abbreviate it as "memKodeCabang" conceptually.)

Business date vs wall-clock

memTanggal is not simply Now(). It is the reference date for every period filter, recap, and closing check:

flowchart TD
    A{"PRM_CLOSINGHARIAN = 'Y'?"} -->|No| B["memTanggal = Now.Date<br/>(wall clock)"]
    A -->|Yes| C["memTanggal = cPRSH.PRSH_TGLAKTIF<br/>(DB system active date)"]
    C --> D{"PC date &lt; system date?"}
    D -->|Yes| E["⚠️ Warn + End() the app"]
    D -->|No| F["Proceed"]
    style C fill:#fff3e0,stroke:#fb8c00
    style E fill:#ffebee,stroke:#c62828
  • If daily closing is enabled (PRM_CLOSINGHARIAN = 'Y'), the business date is the database's active date (PRSH_TGLAKTIF), not the PC clock. This keeps all workstations on the same "today" as the server, even across a closing boundary.
  • If the PC's own date is earlier than the system active date, the app warns and terminates — to stop back-dated transactions from a mis-set clock.
  • SynchroniseDateTime goes further: at startup it runs SELECT GetDate() and forces the Windows local clock and locale (Control Panel\International) to the DB server, so business-date and number formatting stay consistent fleet-wide.

Why this matters for you

Consequences of the globals design

  • State is implicit. A function may depend on memUserID or cPRSH.PRSH_KODE without taking them as parameters. Grep the globals when a value "appears from nowhere."
  • Not thread-safe / not re-entrant. The design assumes a single interactive user per process. Don't add background threads that touch these globals.
  • Startup order is load-bearing. Code assumes Sub Main already ran. Launching a form in isolation without the bootstrap will hit null globals.
  • The app changes machine state at startup (system clock, locale registry keys, and it can remap LPT1 via NET USE for receipt printing). Be aware on shared machines.