Registration-Free Deployment 11 OCX exports | No regsvr32 | No admin rights | XCopy deployment
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.
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
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.
Set m_Grid = LiteGridTurbo_CreateGrid() ' unparented: no window, ever
m_Grid.AddColumn "Name", 150 ' succeeds — and stays invisible
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".
LiteGridTurbo_CreateControlInParent Me, m_Grid
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.
Private WithEvents lgGrid As LiteGridTurboCtrl
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-Free | Registered (regsvr32) | |
|---|---|---|
| Admin rights to install | Not needed | Required |
| Registry entries | None | CLSID + TypeLib + ProgID |
| Deployment | XCopy / USB / network share | Installer or script per machine |
| Versions side by side | Yes — per folder | One per machine |
| Design-time toolbox insertion | No | Yes |
| IntelliSense / early binding | No — As Object | Yes |
WithEvents | No | Yes |
| Events available | 32 of 33, via callback bridge | All 33 |
Custom cell painting (BeforeCellPaint) | No — permanent exception, see below | Yes |
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:
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.
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.
| Container | Works | Notes |
|---|---|---|
| Frame on an Excel or Access UserForm | Yes | The recommended host. Size and position the Frame in the designer; the grid fills it. |
| Access subform control | Yes | Has a real window handle of its own. |
| The UserForm / Form itself | Yes | Works, but the grid fills the whole client area and covers your other controls. Use a Frame instead. |
| Controls nested in an Access tab page | Yes | Tab pages are windowless; the parent chain is walked upward until a real window is found. |
| Worksheet cells / ranges | No | Not 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 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.
| Export | Parameters | Returns | Description |
|---|---|---|---|
| LiteGridTurbo_DestroyControlInstance | grid As Object | Long | Release one specific grid. Safe to call even if the parent window is already gone. |
| LiteGridTurbo_DestroyControl | Long | Deprecated. 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
| Export | Parameters | Returns | Description |
|---|---|---|---|
| LiteGridTurbo_GetLastError | Long | The 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())
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.
| Export | Parameters | Returns | Description |
|---|---|---|---|
| LiteGridTurbo_CreateHelper | ByRef helper As Object | Long | Create 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
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
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.
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
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
| Symptom | Most likely cause | Fix |
|---|---|---|
| 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.