# VBA

Source: https://docs.interop.io/desktop/capabilities/windows/window-management/vba/index.html

## io.Connect Windows

In order for windows of VBA apps to become io.Connect Windows, they must be registered as io.Connect Windows after the io.Connect COM library has been initialized.

## Registering VBA UserForms

Registering a VBA `UserForm` as an io.Connect Window will decorate it with a "sticky" frame allowing it to be visually integrated with other interop-enabled apps.

> ⚠️ *Note that registering a VBA `UserForm` as an io.Connect Window imposes some restrictions on it (for more details, see [VBA UserForm Restrictions](#vba_userform_restrictions)). You can still use io.Connect functionality in the `UserForm` without registering it as an io.Connect Window.*

To register a VBA `UserForm` as an io.Connect Window with [default settings](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluewindowsettings), use the [`RegisterGlueWindow`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-glue42-registergluewindow) method:

```vbnet
Dim WithEvents GlueWin As GlueWindow

Private Sub RegisterGlueWindow()
    On Error GoTo HandleErrors

    If Not GlueWin Is Nothing Then
        ' The io.Connect Window has already been registered (or registration is still in progress).
        Exit Sub
    End If

    Set GlueWin = Glue.RegisterGlueWindow(GetFormHwnd(Me), Nothing)
    Exit Sub

    HandleErrors:
    ' Handle exceptions.

End Sub
```

*The example uses the [GetFormHwnd](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#ioconnect_vba_concepts-helper_functions-getformhwnd) helper function in order to retrieve the window handle (HWND) of the VBA `UserForm`.*

You can also initiate the window registration with custom settings by using [`RegisterGlueWindowWithSettings`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-glue42-registergluewindowwithsettings) instead:

```vbnet
' Create default window settings.
Dim WinSettings As GlueWindowSettings
Set WinSettings = Glue.CreateDefaultVBGlueWindowSettings

' Specify custom window settings.

' Must always be set to `True` in VBA.
WinSettings.SynchronousDestroy = True
' Disable io.Connect Channels.
WinSettings.ChannelSupport = False
' Set custom title.
WinSettings.Title = "Custom Title"

Set GlueWin = Glue.RegisterGlueWindowWithSettings(GetFormHwnd(Me), WinSettings, Nothing)
```

## Events

You must provide implementations for the events that will be raised as a result of the interaction with the registered io.Connect Window.

*The events [`HandleChannelChanged`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluewindow-handlechannelchanged) and [`HandleChannelData`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluewindow-handlechanneldata) are described in the [Channels](https://docs.interop.io/desktop/capabilities/data-sharing/channels/vba/index.md) documentation.*

### Window Ready

The [`HandleWindowReady`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluewindow-handlewindowready) event of a [`GlueWindow`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluewindow) instance is raised when the registration of the window has completed. You can use its handler to indicate that the registration has completed and is safe to perform other operations with the io.Connect Window instance (changing the title, visibility, etc.):

```vbnet
Dim FormRegistered As Boolean

Private Sub GlueWin_HandleWindowReady(ByVal window As IGlueWindow)
    ' Indicate that the io.Connect Window registration has completed.
    FormRegistered = True
    ' Perform additional io.Connect Window operations here.
End Sub
```

### Window Destroyed

The [`HandleWindowDestroyed`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluewindow-handlewindowdestroyed) event is raised when the io.Connect Window is being destroyed. The purpose for raising this event is to provide an opportunity for the VBA app to gracefully unload the VBA `UserForm` (see also [VBA UserForm Restrictions](#vba_userform_restrictions)):

```vbnet
Private Sub GlueWin_HandleWindowDestroyed(ByVal window As IGlueWindow)
    ' Unload the VBA `UserForm`.
    Unload Me
End Sub
```

### Additional Window Events

You may optionally implement a handler for [`HandleWindowEvent`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluewindow-handlewindowevent) which will be executed for various events related to the io.Connect Window, e.g. when the window is activated, moved, etc.

```vbnet
Private Sub GlueWin_HandleWindowEvent(ByVal window As IGlueWindow, ByVal eventType As GlueWindowEventType, ByVal eventData As GlueDynamicValue)
    If eventType = GlueWindowEventType_BoundsChanged Then
        ' Window was moved or resized, examine `eventData` for details.
        ...
    End If
End Sub
```

## Window Operations

Once the VBA window has been registered as an io.Connect Window, you can perform different operations on it.

### Title

To get the current window title, use the [`GetTitle`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluewindow-gettitle) method of a window instance:

```vbnet
Dim WinTitle as String

WinTitle = GlueWin.GetTitle()
```

To change the window title, use the [`SetTitle`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluewindow-settitle) method of a window instance:

```vbnet
GlueWin.SetTitle "New Title"
```

### Visibility

To check whether the window is visible, use [`IsVisible`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluewindow-isvisible). To hide or show a window, use [`SetVisible`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluewindow-setvisible) and pass a `Boolean` value as an argument:

```vbnet
If GlueWin.IsVisible() Then
    GlueWin.SetVisible False
Else
    GlueWin.SetVisible True
End If
```

### Activation

To activate the window, use the [`Activate`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluewindow-activate) subroutine:

```vbnet
GlueWin.Activate
```

## VBA UserForm Restrictions

The following restrictions apply to a VBA `UserForm` when it has been registered as an io.Connect Window:

- The app must provide a mandatory implementation of the [`HandleWindowDestroyed`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluewindow-handlewindowdestroyed) event in order to properly unload the VBA `UserForm`. Failing to unload the VBA `UserForm` will lead to deadlocks in the VBA execution thread.
- If implementing a handler for the `UserForm_QueryClose`, the app must not make any blocking calls (e.g., use I/O operations, display close confirmation popups to the user) or prevent the `UserForm` from unloading by setting a non-zero value for the `Cancel` parameter.
- The app shouldn't change directly the VBA `UserForm` visibility or position (e.g., with `Show`, `Hide`, `Move`).
- After a `UserForm` has been closed/unloaded, it can be displayed again by using `Show`. In this case you will need to repeat the io.Connect initialization and io.Connect Window registration for the `UserForm`.
