Registration-Free Deployment 11 OCX exports | No regsvr32 | No admin rights | XCopy deployment

What this page covers

Every other page on this site documents the grid's COM interface — the methods you call once you have a grid object. This page documents how you get that object without registering anything: the eleven plain DLL exports on the OCX, called from VBA with Declare. They are not reached through IDispatch, so they do not appear in the type library and they have no DISPIDs.

Getting Started

Copy this module into your project once. It handles everything: locating the OCX, activating the side-by-side manifest, creating the grid inside a container, and tearing it down. The rest of the page explains each call.

Before you paste

Put the OCX next to your .xlsm / .accdb and match the bitness of your Office install: LiteGridTurbo_x64.ocx for 64-bit Office, LiteGridTurbo_x86.ocx for 32-bit. The #If Win64 block below picks the right one automatically — but the file has to be there.

Standard Module — modLiteGrid (add once per project)

' ==========================================================================
' LiteGrid Turbo registration-free bootstrap.
' The OCX must sit next to this .xlsm / .accdb.
' No regsvr32. No admin rights. No COM registration.
' ==========================================================================
Option Explicit

#If Win64 Then
    Private Declare PtrSafe Function SetDllDirectory Lib "kernel32" _
        Alias "SetDllDirectoryW" (ByVal lpPathName As LongPtr) As Long
    Private Declare PtrSafe Function LiteGridTurbo_ActivateManifest _
        Lib "LiteGridTurbo_x64.ocx" (ByVal path As LongPtr) As Long
    Private Declare PtrSafe Function LiteGridTurbo_CreateControlInParent _
        Lib "LiteGridTurbo_x64.ocx" (ByVal parentControl As Object, _
                                    ByRef grid As Object) As Long
    Private Declare PtrSafe Function LiteGridTurbo_DestroyControlInstance _
        Lib "LiteGridTurbo_x64.ocx" (ByVal grid As Object) As Long
    Private Declare PtrSafe Function LiteGridTurbo_GetLastError _
        Lib "LiteGridTurbo_x64.ocx" () As Long
#Else
    Private Declare PtrSafe Function SetDllDirectory Lib "kernel32" _
        Alias "SetDllDirectoryW" (ByVal lpPathName As LongPtr) As Long
    Private Declare PtrSafe Function LiteGridTurbo_ActivateManifest _
        Lib "LiteGridTurbo_x86.ocx" (ByVal path As LongPtr) As Long
    Private Declare PtrSafe Function LiteGridTurbo_CreateControlInParent _
        Lib "LiteGridTurbo_x86.ocx" (ByVal parentControl As Object, _
                                    ByRef grid As Object) As Long
    Private Declare PtrSafe Function LiteGridTurbo_DestroyControlInstance _
        Lib "LiteGridTurbo_x86.ocx" (ByVal grid As Object) As Long
    Private Declare PtrSafe Function LiteGridTurbo_GetLastError _
        Lib "LiteGridTurbo_x86.ocx" () As Long
#End If

Private m_Grid As Object

' Edit these two once. Leave LG_KEY empty to use the evaluation window signed into your copy.
Private Const LG_COMPANY As String = "Your Company"
Private Const LG_KEY     As String = ""      ' empty = use the evaluation window signed into your copy

' Creates the grid once, inside hostFrame, and returns it on every later call.
Public Function GetGrid(ByVal hostFrame As Object) As Object
    If m_Grid Is Nothing Then
        Dim p As String, hr As Long

        p = ThisWorkbook.Path              ' Access: CurrentProject.Path
        SetDllDirectory StrPtr(p)          ' tell Windows where the OCX lives

        #If Win64 Then
            LiteGridTurbo_ActivateManifest StrPtr(p & "\LiteGridTurbo_x64.ocx")
        #Else
            LiteGridTurbo_ActivateManifest StrPtr(p & "\LiteGridTurbo_x86.ocx")
        #End If

        hr = LiteGridTurbo_CreateControlInParent(hostFrame, m_Grid)
        If hr <> 0 Then
            MsgBox "LiteGrid Turbo failed to start. HRESULT 0x" & Hex(hr) & _
                   " (last error 0x" & Hex(LiteGridTurbo_GetLastError()) & ")"
            Exit Function
        End If

        ' Never pass a placeholder key: an invalid key raises a run-time error,
        ' which would abandon the rest of GetGrid and leave you with Nothing.
        If Len(LG_KEY) > 0 Then
            On Error Resume Next
            m_Grid.ActivateLicense LG_COMPANY, LG_KEY
            On Error GoTo 0
        End If
    End If
    Set GetGrid = m_Grid
End Function

' Call from UserForm_Terminate / Form_Close. Optional but tidy.
Public Sub ReleaseGrid()
    On Error Resume Next
    If Not m_Grid Is Nothing Then LiteGridTurbo_DestroyControlInstance m_Grid
    Set m_Grid = Nothing
    On Error GoTo 0
End Sub

Canonical per-form template

Drop a Frame control named fraGrid on the form — that is where the grid will live — and paste this into the form's code module. It is the reg-free equivalent of the registered-mode template: same structure, different creation and event wiring.

Option Explicit

Private m_Grid As Object

' ---- setup ----------------------------------------------------------------
Private Sub UserForm_Initialize()
    On Error GoTo Fail

    Set m_Grid = modLiteGrid.GetGrid(Me.fraGrid)
    If m_Grid Is Nothing Then
        MsgBox "LiteGrid Turbo did not start. Is the OCX next to this file?", vbCritical
        Exit Sub
    End If

    ' Reg-free has no WithEvents — attach this form as the callback target.
    ' 1 is a caller-chosen id echoed back on every callback.
    m_Grid.SetEventCallback Me, 1

    m_Grid.AddColumn "Name", 150
    m_Grid.AddColumn "Department", 150
    m_Grid.AddColumn "Salary", 100

    m_Grid.AddRow Array("John Smith", "Engineering", 95000)
    m_Grid.AddRow Array("Jane Doe", "Marketing", 87000)
    m_Grid.AddRow Array("Bob Wilson", "Finance", 102000)
    Exit Sub

Fail:
    ' An invalid licence key surfaces here. Without this handler the rest
    ' of Initialize would be abandoned silently.
    MsgBox "LiteGrid Turbo init failed: " & Err.Number & " " & Err.Description, vbCritical
End Sub

' ---- events ---------------------------------------------------------------
' ONE handler for every event. Must be Public and named exactly OnGridEvent —
' the grid resolves it by name when SetEventCallback is called.
Public Sub OnGridEvent(ByVal gridId As Long, ByVal eventId As Long, _
                        ByVal a1 As Variant, ByVal a2 As Variant, _
                        ByVal a3 As Variant, ByVal a4 As Variant, _
                        ByVal a5 As Variant, ByVal a6 As Variant, _
                        ByRef Cancel As Boolean)

    Select Case eventId
        Case 2                        ' ItemClick — a1 = row, a2 = column
            Debug.Print "clicked row " & a1 & ", col " & a2

        Case 25                       ' CellValueChanged
            Debug.Print "cell changed: " & CStr(a3) & " -> " & CStr(a4)

        Case 12                       ' BeforeRowDelete — cancellable
            If MsgBox("Delete this row?", vbYesNo + vbQuestion) = vbNo Then
                Cancel = True
            End If
    End Select
End Sub

' ---- teardown ------------------------------------------------------------
Private Sub UserForm_Terminate()
    On Error Resume Next
    modLiteGrid.ReleaseGrid
End Sub
Which eventId is which?

The number in eventId identifies the event — 2 is ItemClick, 12 is BeforeRowDelete, and so on. Every event's id and its a1…a6 arguments are listed on the Events page.

The Three Rules Most Developers Get Wrong

Nearly every "it doesn't work" report comes down to one of these three.

1. CreateGrid gives you an invisible grid

There are two creation exports and they are not interchangeable. LiteGridTurbo_CreateGrid returns a grid with no window — correct for JSON work and exports, but it will never appear on a form no matter what you do to it.

✗ Wrong — grid is created but nothing shows
Set m_Grid = LiteGridTurbo_CreateGrid()      ' unparented: no window, ever
m_Grid.AddColumn "Name", 150          ' succeeds — and stays invisible
✓ Correct — pass the container you want it inside
LiteGridTurbo_CreateControlInParent Me.fraGrid, m_Grid
m_Grid.AddColumn "Name", 150

2. Pass the container, not the form

The grid becomes a child window of whatever you hand it. Give it the form and it fills the entire form, painting over every button and label you put there — which reads as "my controls disappeared".

✗ Wrong — grid covers the whole form
LiteGridTurbo_CreateControlInParent Me, m_Grid
✓ Correct — grid confined to the Frame
LiteGridTurbo_CreateControlInParent Me.fraGrid, m_Grid

3. Reg-free mode has no WithEvents — use the callback bridge

WithEvents needs early binding against a registered type library, which is exactly what reg-free deployment does without. Declaring it will not compile. Events still work, through a different door — see Events Without WithEvents.

✗ Wrong — will not compile in reg-free mode
Private WithEvents lgGrid As LiteGridTurboCtrl
✓ Correct — attach a callback object
m_Grid.SetEventCallback Me, 1   ' Me exposes Public Sub OnGridEvent(...)

Registered vs Registration-Free

Both modes run the same control with the same API. What changes is how the object is created and what the development experience feels like.

 Registration-FreeRegistered (regsvr32)
Admin rights to installNot neededRequired
Registry entriesNoneCLSID + TypeLib + ProgID
DeploymentXCopy / USB / network shareInstaller or script per machine
Versions side by sideYes — per folderOne per machine
Design-time toolbox insertionNoYes
IntelliSense / early bindingNo — As ObjectYes
WithEventsNoYes
Events available32 of 33, via callback bridgeAll 33
Custom cell painting (BeforeCellPaint)No — permanent exception, see belowYes

Practical advice: develop against a registered build so you get IntelliSense and WithEvents while writing code, then ship reg-free. The API is identical, so only the object-creation lines and the event wiring differ.

Bootstrap Lifecycle

What happens, in order, the first time GetGrid runs:

t0 SetDllDirectory(path) → Windows will now look in path when resolving LiteGridTurbo_x64.ocx t1 LiteGridTurbo_ActivateManifest(path\LiteGridTurbo_x64.ocx) → reads the manifest embedded in the OCX (RT_MANIFEST, resource id 2) → CreateActCtx + ActivateActCtx → the CLSID is now resolvable without any registry entry → idempotent: returns S_FALSE if already active t2 LiteGridTurbo_CreateControlInParent(fraGrid, grid) → auto-activates the manifest if you skipped t1 → ATL class factory creates the control (no COM SCM, no ProgID lookup) → resolves the container's window handle → creates an ATL host window inside it → DoVerb(OLEIVERB_SHOW) — the grid is now visible → returns IDispatch to VBA t3 grid.ActivateLicense / AddColumn / AddRow / … → ordinary COM calls, identical to registered mode tN LiteGridTurbo_DestroyControlInstance(grid) / Set grid = Nothing → releases the control; its window goes with it
You can skip t1

Every creation export auto-activates the manifest if it is not active yet, locating the OCX from its own module path. Calling LiteGridTurbo_ActivateManifest explicitly is still recommended: it fails early and loudly, at a line you control, instead of surfacing later as a creation failure.

▶ Activation Context 4 exports

The side-by-side activation context is what lets Windows resolve LiteGrid Turbo's CLSID with no registry entry. These four exports manage it.

ExportParametersReturnsDescription
LiteGridTurbo_ActivateManifestpath As LongPtr (StrPtr)LongActivate the context from the OCX's embedded manifest. Pass the full path to the OCX. Idempotent — returns S_FALSE (1) if already active.
LiteGridTurbo_DeactivateManifestLongDeactivate the context. Optional — process exit does this anyway. Idempotent.
LiteGridTurbo_ResetManifestLongForce the context back to a clean state so the next creation call re-activates it. For recovery after an abnormal teardown.
LiteGridTurbo_IsManifestActiveLong (BOOL)Non-zero if the context is currently active. Useful in a diagnostic message.

On return values: these are HRESULTs, not VBA booleans. 0 is success (S_OK); 1 is S_FALSE, which the idempotent calls return to mean "nothing to do, already in that state" — not a failure. Anything with the high bit set (0x8…) is a real error.

Per-Export Usage

' LiteGridTurbo_ActivateManifest — call once, before creating anything
Dim p As String: p = ThisWorkbook.Path
SetDllDirectory StrPtr(p)
Dim hr As Long
hr = LiteGridTurbo_ActivateManifest(StrPtr(p & "\LiteGridTurbo_x64.ocx"))
If hr < 0 Then MsgBox "Activation failed: 0x" & Hex(hr)

' LiteGridTurbo_IsManifestActive — include in any error message you show
Debug.Print "manifest active: " & CBool(LiteGridTurbo_IsManifestActive())

' LiteGridTurbo_ResetManifest — recover, then let creation re-activate
LiteGridTurbo_ResetManifest
Set m_Grid = Nothing

' LiteGridTurbo_DeactivateManifest — rarely needed; process exit handles it
LiteGridTurbo_DeactivateManifest
▶ Creating a Grid 3 exports

Three ways to get a grid object. The one you want depends on a single question: does the grid need to be visible?

ExportParametersReturnsDescription
LiteGridTurbo_CreateControlInParentparentControl As Object, ByRef grid As ObjectLongVisible grid. Creates the control, hosts it inside parentControl, and activates it for display. This is what you want on a form.
LiteGridTurbo_CreateGridObjectInvisible grid. Returns an unparented control with no window — for JSON, exports and calculations. Returns Nothing on failure; check LiteGridTurbo_GetLastError.
LiteGridTurbo_CreateControlByRef grid As ObjectLongSame unparented control as CreateGrid, but with an HRESULT return and an out-parameter instead. Prefer CreateGrid from VBA.
The single most common support question

"The grid isn't showing." In almost every case the code called LiteGridTurbo_CreateGrid. That export is working exactly as designed — it creates a grid with no window. Switch to LiteGridTurbo_CreateControlInParent and pass a Frame.

Per-Export Usage

' LiteGridTurbo_CreateControlInParent — a visible grid inside a Frame
Dim g As Object, hr As Long
hr = LiteGridTurbo_CreateControlInParent(Me.fraGrid, g)
If hr <> 0 Then MsgBox "Embed failed: 0x" & Hex(hr): Exit Sub
g.AddColumn "Product", 200

' LiteGridTurbo_CreateGrid — no form needed: JSON / export / calculation work
Dim calc As Object
Set calc = LiteGridTurbo_CreateGrid()
If calc Is Nothing Then
    MsgBox "Create failed: 0x" & Hex(LiteGridTurbo_GetLastError())
Else
    calc.LoadFromJson jsonText
    Dim csv As String: csv = calc.ExportToCSV()
End If

' LiteGridTurbo_CreateControl — HRESULT + out-param form of the same thing
Dim g2 As Object
If LiteGridTurbo_CreateControl(g2) = 0 Then g2.AddColumn "A", 80

Container Support

LiteGridTurbo_CreateControlInParent needs a real window to make the grid a child of. Not every VBA container has one, so it tries several strategies in order and uses the first that works.

ContainerWorksNotes
Frame on an Excel or Access UserFormYesThe recommended host. Size and position the Frame in the designer; the grid fills it.
Access subform controlYesHas a real window handle of its own.
The UserForm / Form itselfYesWorks, but the grid fills the whole client area and covers your other controls. Use a Frame instead.
Controls nested in an Access tab pageYesTab pages are windowless; the parent chain is walked upward until a real window is found.
Worksheet cells / rangesNoNot a container. Put the grid on a UserForm.

How the parent window is resolved — useful when a custom container fails: (1) ask the control for IOleWindow; (2) then IOleInPlaceObject; (3) then read its hWnd property late-bound; (4) if it is windowless, use its accessibility location for size and position and walk .Parent upward (up to eight levels) until an ancestor with a real window turns up. If all four fail the call returns E_FAIL (0x80004005).

▶ Teardown 2 exports

Teardown is optional. Clearing your VBA reference releases the control and destroys its window; these exports exist for code that wants to be explicit about when that happens.

ExportParametersReturnsDescription
LiteGridTurbo_DestroyControlInstancegrid As ObjectLongRelease one specific grid. Safe to call even if the parent window is already gone.
LiteGridTurbo_DestroyControlLongDeprecated. Does nothing and returns S_OK. Each grid now owns its own window, so a process-wide teardown call has nothing to do. Kept so older code keeps compiling.

Per-Export Usage

' The tidy pattern: On Error Resume Next, because by the time a form is
' closing its Frame may already have taken the grid's window with it.
Private Sub UserForm_Terminate()
    On Error Resume Next
    If Not m_Grid Is Nothing Then LiteGridTurbo_DestroyControlInstance m_Grid
    Set m_Grid = Nothing
End Sub

' Equally valid — releasing the reference does the same work
Set m_Grid = Nothing
▶ Diagnostics 1 export
ExportParametersReturnsDescription
LiteGridTurbo_GetLastErrorLongThe HRESULT from the most recent bootstrap failure. The only way to find out why LiteGridTurbo_CreateGrid returned Nothing, since it has no HRESULT of its own.

A diagnostic line worth keeping

If you report a problem, this one line answers most of the first round of questions:

Debug.Print "ocx=" & ThisWorkbook.Path & "\LiteGridTurbo_x64.ocx" & _
            "  exists=" & (Dir(ThisWorkbook.Path & "\LiteGridTurbo_x64.ocx") <> "") & _
            "  manifestActive=" & CBool(LiteGridTurbo_IsManifestActive()) & _
            "  lastErr=0x" & Hex(LiteGridTurbo_GetLastError())
▶ JSON Helper 1 export

LiteGrid Turbo ships a second, non-visual coclass that provides the JSON methods on their own, with no grid involved. This export is its reg-free factory.

ExportParametersReturnsDescription
LiteGridTurbo_CreateHelperByRef helper As ObjectLongCreate a standalone LiteGridTurboHelper. Same activation-context requirement as the grid exports; auto-activates if needed.
' Declare alongside the others
Private Declare PtrSafe Function LiteGridTurbo_CreateHelper _
    Lib "LiteGridTurbo_x64.ocx" (ByRef helper As Object) As Long

' 18 JSON methods, no grid required
Dim jh As Object
If LiteGridTurbo_CreateHelper(jh) = 0 Then
    Dim name As Variant
    name = jh.GetValue(json, "user.name")
End If
See also: ILiteGridTurboHelper reference — all 18 methods.

Events Without WithEvents

WithEvents requires early binding against a registered type library, so it is unavailable in reg-free mode. Instead you hand the grid an object with a OnGridEvent method and it calls you back. 32 of the 33 events arrive this way, cancellable ones included.

Wiring it up

' In the UserForm (or any class) that should receive events
Private Sub UserForm_Initialize()
    Set m_Grid = modLiteGrid.GetGrid(Me.fraGrid)

    ' Me exposes OnGridEvent below. 1 is a caller-chosen id echoed back on
    ' every callback — handy when one handler serves several grids.
    m_Grid.SetEventCallback Me, 1
End Sub

' ONE signature serves every event. Always 9 parameters, Cancel always ByRef.
' The name must be exactly OnGridEvent and it must be Public — the grid
' looks it up by name when you call SetEventCallback.
Public Sub OnGridEvent(ByVal gridId As Long, ByVal eventId As Long, _
                        ByVal a1 As Variant, ByVal a2 As Variant, _
                        ByVal a3 As Variant, ByVal a4 As Variant, _
                        ByVal a5 As Variant, ByVal a6 As Variant, _
                        ByRef Cancel As Boolean)

    Select Case eventId
        Case 1                       ' ColumnClick — a1 = column index
            Debug.Print "header clicked: " & a1

        Case 12                      ' BeforeRowDelete — cancellable
            If MsgBox("Delete this row?", vbYesNo) = vbNo Then
                Cancel = True       ' veto it
            End If
    End Select
End Sub
Two things to know

Six high-frequency events are off by default — SelectionChanged, ScrollChanged, CellHover, CellMouseEnter, CellMouseLeave and LoadProgress. They fire often enough to matter for performance, so you opt in per event: SetEventCallbackEnabled 4, True.

BeforeCellPaint (event 26) can never be delivered this way. It hands the handler a live drawing context that is only valid inside the paint loop. Data-driven appearance is covered by SetCellColor, SetCellFontStyle, SetCellIcon and AddFormatRule; genuine custom painting needs registered mode.

See also: Events reference — all 33 events, their arguments, which are cancellable, and the full bridge API.

Licensing in Reg-Free Mode

Licensing works identically in both modes. An evaluation copy needs no call: its evaluation window is signed into the OCX. After purchase, call ActivateLicense right after creating the grid, on every launch — activation lasts for the current process only.

' Right after creation, before any data work
If Len(LG_KEY) > 0 Then m_Grid.ActivateLicense LG_COMPANY, LG_KEY

' Check state at any time
Debug.Print m_Grid.LicenseStatus        ' TRIAL / EXPIRED / EVAL / PRO / ENTERPRISE
Debug.Print m_Grid.TrialDaysRemaining
Never pass a placeholder key

An invalid key returns a failure HRESULT, which VBA raises as a run-time error. Without an error handler that abandons the rest of your routine — so the grid appears but nothing after the activation line runs, which looks like the code silently stopped. Either pass a real key or leave the call out entirely.

When the evaluation window closes (or the copy carries no valid evaluation and no key is activated), the grid keeps displaying its data, but typing and clicking in the grid are blocked, data export and copying data out are refused, and printed, PDF and HTML output carries an evaluation notice. A Buy a License button appears on the grid. Everything returns as soon as ActivateLicense succeeds with a valid key. Read LicenseStatus or TrialDaysRemaining if you want to prompt the user yourself.

Troubleshooting

SymptomMost likely causeFix
Run-time error 53 "File not found" on the first LiteGrid Turbo call The OCX is not where Windows is looking, or SetDllDirectory was never called Put the OCX next to the .xlsm/.accdb and call SetDllDirectory StrPtr(path) before anything else
Run-time error 48 "Error in loading DLL" Bitness mismatch — 64-bit Office loading the x86 OCX or vice versa 64-bit Office needs LiteGridTurbo_x64.ocx; 32-bit needs LiteGridTurbo_x86.ocx. Keep the #If Win64 block
Grid object is created, but nothing appears LiteGridTurbo_CreateGrid was used — it creates an unparented, windowless grid by design Use LiteGridTurbo_CreateControlInParent and pass a Frame
Grid appears but covers all the other controls The form was passed as the parent instead of a container on it Pass Me.fraGrid, not Me
CreateControlInParent returns 0x80004005 (E_FAIL) No usable window could be found for the container you passed Use a Frame or Access subform. Print LiteGridTurbo_IsManifestActive and LiteGridTurbo_GetLastError to confirm the bootstrap itself succeeded
Error 429 "ActiveX component can't create object" The activation context is not active, so the CLSID cannot be resolved Call LiteGridTurbo_ActivateManifest with the full OCX path and check its return value
Everything after SetEventCallback silently stops running An invalid or placeholder key was passed — activation returns a failure HRESULT and the unhandled error abandoned the routine Add On Error, or leave the call out entirely until you have a real key
An evaluation notice covers the grid and typing is blocked The evaluation window signed into this copy has closed, or the copy carries no evaluation, and no key was activated in this process ActivateLicense with a valid key on every launch; the notice clears on the next paint
WithEvents will not compile, or no events arrive WithEvents needs early binding, which reg-free mode cannot provide Use SetEventCallback with a public OnGridEvent — see Events
One specific event never fires, others do It is one of the six opt-in high-frequency events, or it is BeforeCellPaint SetEventCallbackEnabled id, True. Event 26 cannot be bridged at all
Works on your machine, fails on a colleague's The OCX was not copied along with the workbook Ship the OCX beside the file. Nothing else needs to travel — that is the point of reg-free

Copy-Paste Checklist

Run through this before reporting a reg-free problem — it resolves most of them, and the answers are exactly what a support reply would ask for first.

☐ The OCX sits in the SAME folder as the .xlsm / .accdb ☐ Its bitness matches Office (x64 Office → LiteGridTurbo_x64.ocx) ☐ SetDllDirectory is called with the project path, before any other call ☐ LiteGridTurbo_ActivateManifest is passed the FULL path, including the filename ☐ Its return value is checked (0 = OK, 1 = already active, 0x8… = error) ☐ The grid is created with CreateControlInParent, not CreateGrid ☐ The parent passed in is a Frame, not the form itself ☐ The Frame is big enough to see, and Visible = True ☐ ActivateLicense is either given a REAL key or omitted entirely ☐ LicenseStatus does not report EXPIRED ☐ The routine has On Error, so a licence failure does not vanish silently ☐ Events go through SetEventCallback + Public OnGridEvent, not WithEvents ☐ The one-line diagnostic from the Diagnostics section has been captured
Explore more: Core API · Events · JSON Helper · Enums · Overview