# VBA

Source: https://docs.interop.io/desktop/capabilities/data-sharing/interop/vba/index.html

## Method Registration

To expose an io.Connect method that can be invoked by other interop-enabled apps, you need to register the method in io.Connect and provide its implementation.

### Registering Methods

To register an io.Connect method, first create a method instance using [`CreateServerMethod`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-glue42-createservermethod) and then invoke [`Register`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-glueservermethod-register) on the created method instance.

The following example demonstrates a subroutine which registers an io.Connect method named "MyVBAMethod":

```vbnet
Dim WithEvents MyVBAMethod As GlueServerMethod
...
Public Sub RegisterMethod()
    On Error GoTo HandleErrors

    Set MyVBAMethod = Glue.CreateServerMethod("MyVBAMethod", "", "", "")
    MyVBAMethod.Register
    Exit Sub

    HandleErrors:
        ' Handle exceptions.
        ...
End Sub
```

### Method Implementation

The [`GlueServerMethod`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-glueservermethod) class exposes an event called [`HandleInvocationRequest`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-glueservermethod-handleinvocationrequest). Provide a method implementation as its handler which will be executed when the registered method is invoked.

The following example demonstrates a subroutine handling an invocation request for a registered method.

Details about the example:

- the registered method accepts a composite value as an argument with the following structure represented in JSON format:

```json
{
    "operation": "AddSub",
    "operands": [5, 3],
    "metadata": {
        "reason": "testing"
    }
}
```

- the example demonstrates how to extract elementary fields from a composite value (see [Accessing Composite Value Fields](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#ioconnect_vba_concepts-composite_values-accessing_composite_value_fields)) and how to build a composite return value (see [Building Composite Values](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#ioconnect_vba_concepts-composite_values-building_composite_values));

- the example demonstrates how to send a response to the caller by using [`SendResult`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-glueinvocationrequest-sendresult) to send the return value to the caller and [`SendFailure`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-glueinvocationrequest-sendfailure) to indicate failure and send an error message and an empty result value to the caller.

```vbnet
Private Sub MyVBAMethod_HandleInvocationRequest(ByVal request As IGlueInvocationRequest)
    On Error GoTo HandleErrors

    Dim Operation As String
    Dim Operand_1, Operand_2 As Integer
    Dim Reason As String

    ' Get the root of the composite argument.
    Dim Args
    Set Args = request.GetReflectData("")

    ' Extract the elementary fields from the composite argument.
    Operation = Args("operation")
    Operand1 = Args("operands")(0)
    Operand2 = Args("operands")(1)
    Reason = Args("metadata")("reason")

    ' Prepare the result as a composite value.
    Dim Result
    Set Result = Glue.CreateGlueValues

    If Operation = "AddSub" Then
        Dim ResultArray(0 To 1) As Integer
        ResultArray(0) = Operand_1 + Operand_2
        ResultArray(1) = Operand_1 - Operand_2

        ' Build the result as a composite value.
        Result("resultArray") = ResultArray
        Result("metadata")("info") = "Handled in VBA."
        ' Send the result back to the caller.
        request.SendResult Result
        Exit Sub
    End If

    HandleErrors:
        ' If an error occurs or "Operation" isn't recognised,
        ' send an error message and an empty result value.
        request.SendFailure "Invalid argument(s) provided.", Glue.CreateGlueValues
End Sub
```

## Method Invocation

To invoke an io.Connect method, you need to obtain an instance of [`GlueMethodInvocator`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluemethodinvocator) (proxy), build the argument values, initiate the invocation and provide a callback subroutine to handle the invocation result(s).

### Invoking Methods

The following examples demonstrate the steps you need to follow to invoke an io.Connect method. At the end of the section you can see a full method invocation example.

#### Method Invocator (Proxy)

Create a method proxy using [`CreateMethodInvocator`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-glue42-createmethodinvocator). You can invoke a method multiple times reusing the same method invocator:

```vbnet
Dim WithEvents MyMethodProxy As GlueMethodInvocator

Public Sub InvokeMethod()
    ...
    ' Obtain a method invocator and reuse it for subsequent invocations.
    If MyMethodProxy Is Nothing Then
        Set MyMethodProxy = Glue.CreateMethodInvocator
    End If
    ...
End Sub
```

#### Building the Argument Values

Build the arguments as a composite value (see [Building Composite Values](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#ioconnect_vba_concepts-composite_values-building_composite_values) for details):

```vbnet
Public Sub InvokeMethod()
    ...
    ' Create an empty root value.
    Dim Args
    Set Args = Glue.CreateGlueValues

    ' Add the arguments.
    Args("operation") = "AddSub"

    Dim OperandsArray(0 To 1) As Integer
    OperandsArray(0) = 5
    OperandsArray(1) = 3
    Args("operands") = OperandsArray

    Args("metadata")("reason") = "testing"
    ...
End Sub
```

#### Invoking the Method

Use [`InvokeAsync`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluemethodinvocator-invokeasync) or [`InvokeSync`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluemethodinvocator-invokesync) to initiate the method invocation.

The following example demonstrates how to use `InvokeAsync` to invoke the registered io.Connect method (for details about the provided arguments, see [`InvokeAsync`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluemethodinvocator-invokeasync)):

```vbnet
Public Sub InvokeMethod()
    ...
    MyMethodProxy.InvokeAsync "MyVBAMethod", "", Args, False, "", 3000
    ...
End Sub
```

The following is a full invocation example:

```vbnet
Dim WithEvents MyMethodProxy As GlueMethodInvocator

Public Sub InvokeMethod()
    On Error GoTo HandleErrors

    ' Obtaining a method invocator.
    If MyMethodProxy Is Nothing Then
        Set MyMethodProxy = Glue.CreateMethodInvocator
    End If

    ' Building the argument values.
    Dim Args
    Set Args = Glue.CreateGlueValues

    Args("operation") = "AddSub"

    Dim OperandsArray(0 To 1) As Integer
    OperandsArray(0) = 5
    OperandsArray(1) = 3
    Args("operands") = OperandsArray

    Args("metadata")("reason") = "testing"

    ' Invoking the method.
    MyMethodProxy.InvokeAsync "MyVBAMethod", "", Args, False, "", 3000
    Exit Sub

    HandleErrors:
    ' Handle exceptions.

End Sub
```

### Targeting

When invoking io.Connect methods, you can target a specific app (server) that has registered the method, a group of servers or the server that has registered the method first. Use the `targetRegex` and `all` parameters of [`InvokeAsync`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluemethodinvocator-invokeasync) or [`InvokeSync`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluemethodinvocator-invokesync) to specify which servers to target:

- `targetRegex` - optional regular expression pattern which allows selecting the target apps which will service the method invocation. If provided, only targets with app name matching the regular expression will be considered. An empty string or `Nothing` will match all app names;

- `all` - a `Boolean` value indicating whether the method invocation request should be sent to all available app targets or to one target only (the first that has registered the method);

You can use a combination of both parameters to filter the method servers you are interested in. The following example demonstrates how to invoke a registered method by targeting all apps with names that start with "clients":

```vbnet
Public Sub InvokeMethod()
    ...
    MyMethodProxy.InvokeAsync "MyVBAMethod", "clients.*", Args, True, "", 3000
    ...
End Sub
```

### Handling Invocation Results

- [`InvokeSync`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluemethodinvocator-invokesync) returns the invocation results synchronously as а [`VBGlueInvocationResult`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-vbglueinvocationresult).

- [`InvokeAsync`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluemethodinvocator-invokeasync) handles the invocation results with the [`HandleInvocationResult`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluemethodinvocator-handleinvocationresult) event of the [`GlueMethodInvocator`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluemethodinvocator) instance. Its handler is executed when the associated method invocation has completed (successfully or otherwise).

*If you aren't interested in the invocation result, you still need to provide an empty implementation for the `HandleInvocationResult` event or, alternatively, declare the `GlueMethodInvocator` instance without `WithEvents`.*

The following example demonstrates a subroutine handling an invocation result and demonstrating how to check the method invocation status and extract the return values:

- The instance of [`IGlueInvocationResult`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-vbglueinvocationresult) passed to the event handler has a `Results` property which is an array of [`VBGlueResult`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#types-vbglueresult) containing details about the invocation results. An array is used because the invocation request can be sent to multiple target apps at once. The `Results` array always contains at least one element.
- In the full invocation example the invocation request is sent to only one target app, therefore only one result is expected and extracted.
- The `Status` property of a `VBGlueResult` is a [`GlueMethodInvocationStatus`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#enums-gluemethodinvocationstatus) enumeration value.
- For details on how to extract data from composite values, see [Accessing Composite Value Fields](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#ioconnect_vba_concepts-composite_values-accessing_composite_value_fields).

```vbnet
Private Sub MyMethodProxy_HandleInvocationResult(ByVal result As IGlueInvocationResult)
    On Error GoTo HandleErrors

    Dim ResultArr() As VBGlueResult
    Dim FirstResult As VBGlueResult

    ' Get the first result.
    ResultArr = result.Results
    FirstResult = ResultArr(0)

    If Not FirstResult.Status = GlueMethodInvocationStatus_Succeeded Then
        ' Handle unsuccessful invocation.
        ...
        Exit Sub
    End If

    ' Extract the result fields from the composite value.
    Dim ResultArray
    ResultArray = FirstResult.GlueData.GetReflectData("resultArray")

    Dim AdditionResult, SubtractionResult As Integer
    AdditionResult = ResultArray(0)
    SubtractionResult = ResultArray(1)

    ' Do something with the result.
    ...

    Exit Sub

    HandleErrors:
    ' Handle exceptions.
    ...

End Sub
```

## Discovery

Your app can discover registered Interop methods and streams and other apps (Interop servers) which offer them.

### Listing All Methods & Streams

To find all registered io.Connect methods/streams, use the [`GetMethodNamesForTarget`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-glue42-getmethodnamesfortarget) method and pass an empty string or `Nothing` as an argument:

```vbnet
Dim AllMethodNames() as String

AllMethodNames = Glue.GetMethodNamesForTarget("")
```

### Listing Methods & Streams for Target

To target a specific server or a group of servers for which to get all registered methods/streams, pass a regex value as an argument to [`GetMethodNamesForTarget`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-glue42-getmethodnamesfortarget):

```vbnet
Dim AllMethodNamesForTarget() as String

AllMethodNamesForTarget = Glue.GetMethodNamesForTarget("client.*")
```

### Listing All Interop Servers

To get a list of the names of all apps offering Interop methods/streams, use the [`GetTargets`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-glue42-gettargets) method:

```vbnet
Dim AllInteropServers() as String

AllInteropServers = Glue.GetTargets()
```

## Streaming

### Overview

Your app can publish events that can be observed by other apps, or it can provide real-time data (e.g., market data, news alerts, notifications, etc.) to other apps by publishing an Interop stream. Your app can also receive and react to these events and data by creating an Interop stream subscription.

Apps that create and publish to Interop Streams are called "publishers", and apps that subscribe to Interop Streams are called "subscribers". An app can be both.

![](https://docs.interop.io/desktop/images/interop/interop-streaming.mp4)

## Publishing Stream Data

To expose a data stream to which other apps can subscribe, you need to register a stream and provide implementations for handling the server side streaming events (subscription requests, added/removed subscribers). Once a stream has been successfully registered, the publishing app can start pushing data to it.

### Creating Streams

Create a streaming method instance using [`CreateServerStream`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-glue42-createserverstream) and invoke its [`Register`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-glueserverstream-register) method:

```vbnet
Dim WithEvents MyVBAStream As GlueServerStream

Public Sub RegisterStream()
    On Error GoTo HandleErrors

    If MyVBAStream Is Nothing Then
        ' The only required argument when creating a stream is a stream name.
        Set MyVBAStream = Glue.CreateServerStream("MyVBAStream", "", "", "")
        MyVBAStream.Register
    End If
    Exit Sub

    HandleErrors:
    ' Handle exceptions.
    ...

End Sub
```

### Accepting or Rejecting Subscription Requests

[`GlueServerStream`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-glueserverstream) exposes an event called [`HandleSubscriptionRequest`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-glueserverstream-handlesubscriptionrequest). Its handler is executed when an app attempts to subscribe to the stream. The handler receives a [`GlueSubscriptionRequest`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluesubscriptionrequest) instance as an argument. You can use its `GetReflectData` method to extract the request arguments passed as a composite value by the subscriber. Use the [`Accept`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluesubscriptionrequest-accept) method of the request instance to accept the subscription on the default (unnamed) or a specific branch.

The following example demonstrates a subroutine handling a subscription request. The request is accepted or rejected based on the value of an argument that the subscriber has specified when sending the subscription request:

```vbnet
Private Sub MyVBAStream_HandleSubscriptionRequest(ByVal request As IGlueSubscriptionRequest)
    On Error GoTo HandleErrors

    ' Extract the subscriber-defined `subscriptionCode` field from the request arguments.
    Dim SubscriptionCode As String
    SubscriptionCode = request.GetReflectData("subscriptionCode")

    If SubscriptionCode = "rejectme" Then
        ' Reject the subscription request with a message.
        request.Reject "Invalid subscription code."
        Exit Sub
    End If

    ' Accept the request on the default branch.
    request.Accept "", Nothing
    Exit Sub

    HandleErrors:
    ' Handle exceptions.
    ...

End Sub
```

### Added or Removed Subscriptions

#### Handling New Subscriptions

[`GlueServerStream`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-glueserverstream) exposes an event called [`HandleSubscriber`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-glueserverstream-handlesubscriber). Its handler is executed when a new subscriber is added. The handler accepts two arguments - a [`VBGlueStreamSubscriber`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-vbgluestreamsubscriber) instance and a [`GlueData`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluedata) instance. The `VBGlueStreamSubscriber` instance contains information about the subscriber instance and you can use its [`Push`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-vbgluestreamsubscriber-push) method to send private data directly to it. The `GlueData` instance is a composite value that contains the subscription request arguments as specified by the subscriber.

```vbnet
Private Sub MyVbaStream_HandleSubscriber(ByVal subscriber As IVBGlueStreamSubscriber, ByVal requestData As IGlueData))
    On Error GoTo HandleErrors

    ' Create a root composite value and add data to it.
    Dim Data
    Set Data = Glue.CreateGlueValues
    Data("info") = "welcome"
    ' Push the data to the new subscriber.
    subscriber.Push Data
    Exit Sub

    HandleErrors:
    ' Handle exceptions.
    ...
End Sub
```

> ⚠️ *Note that new subscribers won't automatically get the data that has been previously published to the stream. This handler is the place where you can send private updates to the new subscriber, if necessary.*

#### Handling Removed Subscriptions

[`GlueServerStream`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-glueserverstream) exposes an event called [`HandleSubscriberLost`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-glueserverstream-handlesubscriberlost). Its handler is executed when an existing subscriber unsubscribes from the stream.

The following example demonstrates an empty handler subroutine:

```vbnet
Private Sub MyVBAStream_HandleSubscriberLost(ByVal subscriber As IGlueStreamSubscriber)
    ' Possibly handle the lost subscriber here.
End Sub
```

Canceling a subscription can be initiated either by the subscriber app or the stream publisher app. This handler is invoked in both cases. Handling this event can be useful if you want to record or propagate it. If this event isn't significant for the app, you must provide an empty handler subroutine.

#### Default Event Handlers

You may declare the [`GlueServerStream`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-glueserverstream) instance without `WithEvents`. In this case the io.Connect COM library will use the following default internal implementations:

- `HandleSubscriptionRequest` - all subscription requests will be accepted on the default (unnamed) branch;
- `HandleSubscriber` - no operation;
- `HandleSubscriberLost` - no operation;

### Pushing Data

You can push data to a stream by using the [`PushVariantData`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-glueserverstream-pushvariantdata) method of a [`GlueServerStream`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-glueserverstream) instance. Data can be sent to all subscribers on the stream, or to a group of subscribers on a specific stream branch.

The following example demonstrates how to push data to all subscribers on a stream:

```vbnet
' Create a composite value and add data to it.
Dim Data
Set Data = Glue.CreateGlueValues
Data("info") = "Data broadcast to all subscribers."

' Push data to all subscribers.
MyVBAStream.PushVariantData Data, ""
```

You can also push data directly to a subscriber by using the [`Push`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-vbgluestreamsubscriber-push) method of a [`VBGlueStreamSubscriber`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-vbgluestreamsubscriber) instance (see [Handling New Subscriptions](#publishing_stream_data-added_or_removed_subscriptions-handling_new_subscriptions)).

### Using Stream Branches

Using stream branches allows you to group subscribers by any criterion and target stream data at specific groups of subscribers. Branches are distinguished by their name (key). Each io.Connect stream has a default (unnamed) branch on which it accepts subscribers and to which it pushes data if no branch is specified.

To accept a subscription on a branch, specify the branch name when accepting the subscription. If the branch doesn't exist, it will be automatically created:

```vbnet
request.Accept "branch_01", Nothing
```

> ℹ️ *See also [Accepting or Rejecting Subscription Requests](#publishing_stream_data-accepting_or_rejecting_subscription_requests).*

To push data to a specific branch, specify a branch name when pushing data to the stream:

```vbnet
Dim Data
Set Data = Glue.CreateGlueValues
Data("info") = "Data targeted at subscribers on branch `branch_01`."

MyVBAStream.PushVariantData Data, "branch_01"
```

## Consuming Stream Data

To receive data published on an io.Connect stream, an app has to create an instance of a [`GlueStreamConsumer`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluestreamconsumer), subscribe to a stream and provide the subroutines necessary for handling the incoming data and changes in the stream status.

### Subscribing to Streams

Obtain a [`GlueStreamConsumer`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluestreamconsumer) instance using [`CreateStreamConsumer`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-glue42-createstreamconsumer), provide subscription arguments and send a subscription request using the [`Subscribe`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluestreamconsumer-subscribe) method of the `GlueStreamConsumer` instance. When the subscription request has been resolved or times out, the corresponding event handlers will be executed.

```vbnet
Dim WithEvents StreamConsumer As GlueStreamConsumer
...
Public Sub SubscribeToStream()
    On Error GoTo HandleErrors

    ' Obtain a stream consumer instance.
    If StreamConsumer Is Nothing Then
        Set StreamConsumer = Glue.CreateStreamConsumer
    End If

    ' Build the arguments to send with the subscription request.
    Dim Args
    Set Args = Glue.CreateGlueValues
    Args("subscriptionCode") = "hello"

    ' Send the subscription request.
    StreamConsumer.Subscribe "MyVBAStream", "", Args, False, "", 3000
    Exit Sub

    HandleErrors:
    ' Handle exceptions.
    ...

End Sub
```

As with invoking Interop methods, you can target specific servers providing the stream. See [Targeting](#method_invocation-targeting) for more details.

### Handling Subscriptions Client Side

#### Receiving Data

[`GlueStreamConsumer`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluestreamconsumer) exposes an event called [`HandleStreamData`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluestreamconsumer-handlestreamdata). Its handler is executed when a stream publishing app pushes data to the stream. The handler accepts two arguments - a [`GlueMethodInfo`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluemethodinfo) instance containing information about the stream, and a [`GlueData`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluedata) instance containing the data pushed to the stream.

The following example demonstrates a subroutine handling incoming data from a stream:

```vbnet
Private Sub StreamConsumer_HandleStreamData(ByVal stream As IGlueMethodInfo, ByVal data As IGlueData)
    On Error GoTo HandleErrors

    ' Extract information about the data publisher.
    Dim StreamName as String
    Dim ApplicationName as String
    StreamName = stream.method.Name
    ApplicationName = stream.method.Instance.ApplicationName

    ' Extract data from the composite value.
    Dim Info As String
    Info = Data.GetReflectData("info")

    ' Do something with the data.
    ...
    Exit Sub

    HandleErrors:
    ' Handle exceptions.

End Sub
```

#### Subscription Activated Handler

[`GlueStreamConsumer`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluestreamconsumer) exposes an event called [`HandleSubscriptionActivated`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluestreamconsumer-handlesubscriptionactivated). Its handler is executed when a subscription request has been dispatched to io.Connect. The main purpose for handling this event is to provide an instance of the [`GlueStreamSubscription`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluestreamsubscription) which the app may later use to unsubscribe from the stream. To unsubscribe from the stream, use the `Close` method of the subscription instance.

The following example demonstrates a subroutine handling the event:

```vbnet
Dim StreamSubscription As IGlueStreamSubscription

Private Sub StreamConsumer_HandleSubscriptionActivated(ByVal subscription As IGlueStreamSubscription)
  ' Keep a reference to the subscription instance.
  Set StreamSubscription = subscription
End Sub
```

#### Stream Status Handler

[`GlueStreamConsumer`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluestreamconsumer) exposes an event called [`HandleStreamStatus`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluestreamconsumer-handlestreamstatus). Its handler is executed when the [`GlueStreamState`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#enums-gluestreamstate) of the associated stream subscription changes.

The following example demonstrates a subroutine handling the event:

```vbnet
Private Sub StreamConsumer_HandleStreamStatus(ByVal stream As IGlueMethodInfo, ByVal state As GlueStreamState, ByVal Message As String, ByVal dateTime As Double)
    On Error GoTo HandleErrors

    Select Case state
    Case GlueStreamState_Pending
        ' Subscription request is pending.
        ...
    Case GlueStreamState_Opened
        ' Subscription request has been accepted.
        ...
    Case GlueStreamState_Closed
        ' Subscription has been closed.
        ...
    End Select

    Exit Sub

    HandleErrors:
    ' Handle exceptions.

End Sub
```

You may provide an empty implementation if you aren't interested in performing any actions when the stream subscription status changes.

#### Stream Closed Handler

[`GlueStreamConsumer`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluestreamconsumer) exposes an event called [`HandleStreamClosed`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/vba/index.md#classes-gluestreamconsumer-handlestreamclosed). Its handler is executed when the stream is closed and the associated stream subscription has been terminated.

Here is an example of a subroutine handling the event:

```vbnet
Private Sub StreamConsumer_HandleStreamClosed(ByVal stream As IGlueMethodInfo)
  ' Perform actions when the stream is closed.
  ...
End Sub
```
You may provide an empty implementation if you aren't interested in performing any actions when the subscription has been terminated.
