# C Exports

Source: https://docs.interop.io/desktop/capabilities/app-management/c-exports/index.html

## Registering the Main Window

> ℹ️ *See the C++ [MFC example](https://github.com/InteropIO/native-examples/tree/main/glue-c-exports/mfc-example) on GitHub.*

The main window of your app is automatically registered and announced as an io.Connect app when you register it as an io.Connect Window using [`glue_register_main_window()`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#functions-glueregistermainwindow) or [`glue_register_window()`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#functions-glueregisterwindow):

```cpp
// Here `my_app` is a previously defined MFC object from which you can extract the window handle.
const HWND handle = my_app->m_pMainWnd->m_hWnd;

// Callback for handling io.Connect app events.
void app_event_callback (glue_app_command command, const void* callback, const glue_payload* payload, COOKIE cookie) {
    std::cout << "App event for main window: " << command << std::endl;
}

// Callback for handling io.Connect Window events.
void window_event_callback (glue_window_command command, const char* context_name, COOKIE cookie) {
    std::cout << "Window event for main window: " << command << std::endl;
}

// The main window of your app will be registered as an io.Connect Window and as an io.Connect app.
glue_register_main_window(handle, &app_event_calback, &window_event_callback, "Main Window");
```

The `app_event_callback` passed as a second argument is an [`app_callback_function`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#types-appcallbackfunction) which allows you to handle [app events](#events) for the main window.

> ℹ️ *For more details on registering app windows as io.Connect Windows, see the [Window Management](https://docs.interop.io/desktop/capabilities/windows/window-management/c-exports/index.md) section.*

## App Factories

Registering an app factory allows you to register the child windows of your app as io.Connect apps, announce their instances in the io.Connect environment and handle [app events](#events) for them. To register an app factory, use [`glue_app_register_factory()`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#functions-glueappregisterfactory). It accepts as arguments the name of the app to be created, an app event handler as an [`app_callback_function`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#types-appcallbackfunction), an optional JSON representation of the [app definition](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#app_definition), and an optional callback cookie. The app event handler will be invoked with the `create` [`glue_app_command`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#enums-glueappcommand) when an instance of the child app is created.

To announce the created app instance in the io.Connect environment, use [`glue_app_announce_instance()`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#functions-glueappannounceinstance) within the [`app_callback_function`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#types-appcallbackfunction). The [`glue_app_announce_instance()`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#functions-glueappannounceinstance) method accepts as arguments a correlational callback (the same one that is passed as an argument to the [`app_callback_function`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#types-appcallbackfunction)), the window handle, an app event handler as an [`app_callback_function`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#types-appcallbackfunction), a window event handler as a [`glue_window_callback_function`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#types-gluewindowcallbackfunction), and an optional cookie.

The following example demonstrates how to register an app factory and announce the child instances in the io.Connect environment:

```cpp
// Callback for handling app events for each announced child instance. Registered when announcing the child.
void child_app_event_callback(const glue_app_command command, const void* callback, const glue_payload* payload, COOKIE cookie) {
    std::cout << "App event for child window: " << command << std::endl;
}

// Callback for handling window events for each announced child instance. Registered when announcing the child.
void child_window_event_callback (glue_window_command command, const char* context_name, COOKIE cookie) {
    std::cout << "Window event for child window: " << command << std::endl;
}

// Callback that will be invoked with the `create` command when a child instance is created by the app factory.
void app_factory_callback (glue_app_command command, const void* callback, const ::glue_payload* payload, COOKIE cookie) {
    switch (command) {
        case glue_app_command::create: {
            // Here `my_child_window` is a previously defined MFC object from which you can extract the window handle.
            const HWND handle = my_child_window->m_hWnd;

            // Announce the child instance passing the same correlational callback received from the `app_factory_callback`
            // the child window handle, and the app and window event handlers.
            glue_app_announce_instance(callback, handle, &child_app_event_callback, &child_window_event_callback);

            // Alternatively, factories can deny creating instances by pushing failure:
            // glue_push_failure(callback, "Can't create a child instance.")
            break;
        }
        default:
            break;
    }
}

// Register the app factory.
const void* my_app_factory = glue_app_register_factory("Child App", &app_factory_callback);
```

Registering an app factory returns a reference to the created app factory. Use [`glue_destroy_resource()`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#functions-gluedestroyresource) to destroy it:

```cpp
glue_destroy_resource(my_app_factory);
```

## App State

You can save a state for the main and child windows of your app, as well as restore an initial or previously saved state. The initial state of an app can be passed through [app definition](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#app_definition).

### Main Window

To save and restore a state for your main window, use the [`app_callback_function`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#types-appcallbackfunction) passed to [`glue_register_main_window()`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#functions-glueregistermainwindow) when registering your main window. When the [`app_callback_function`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#types-appcallbackfunction) is invoked with the `save` [`glue_app_command`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#enums-glueappcommand), push a state to be saved, and when it's invoked with the `init` command, restore the saved state using the passed payload:

```cpp
// Here `my_app` is a previously defined MFC object from which you can extract the window handle.
const HWND handle = my_app->m_pMainWnd->m_hWnd;

// Callback for handling io.Connect app events.
void app_event_callback (glue_app_command command, const void* callback, const glue_payload* payload, COOKIE cookie) {
    // Check the command with which the app event handler was invoked.
    switch (command) {
        case glue_app_command::save:
            // Use the io.Connect methods prefixed with `glue_push_` to push a save state.
            glue_push_json_payload(callback, "{io: {a: 42, b: \"forty-two\"}}");
            break;
        case glue_app_command::init: {
            // Use the io.Connect methods prefixed with `glue_read_` to extract the initial or restored state.
            const auto restore_state = glue_read_json(payload->reader, nullptr);
            std::cout << "Restored state: " << restore_state << std::endl;
            break;
        }
        default:
            break;
    }
}

// Callback for handling io.Connect Window events.
void window_event_callback (glue_window_command command, const char* context_name, COOKIE cookie) {
    std::cout << "Window event for main window: " << command << std::endl;
}

glue_register_main_window(handle, &app_event_calback, &window_event_callback, "Main Window");
```

If you have registered your main window via [`glue_register_window()`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#functions-glueregisterwindow), which doesn't accept a callback for handling app events, you can use [`glue_set_save_state()`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#functions-gluesetsavestate) to save you app state. It accepts an [`invocation_callback_function`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#types-invocationcallbackfunction) as an argument which you can use to push a state to be saved. The state can then be restored by extracting it from the **io.Connect Desktop** starting context with [`glue_get_starting_context_reader()`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#functions-gluegetstartingcontextreader). Before attempting to extract a saved state from the starting context, you must check whether your app has been started by **io.Connect Desktop** using [`glue_is_launched_by_gd()`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#functions-glueislaunchedbygd):

```cpp
void save_state_callback (const char* endpoint_name, COOKIE cookie, const ::glue_payload* payload, const void* endpoint) {
    glue_push_json_payload(endpoint, "{my_saved_state: {a: 42, b: \"io\"}}");
}

// Set a callback that will be invoked whenever user-specific data
// for this instance is to be persisted by the platform.
glue_set_save_state(&save_state_callback);

// Check whether your app has been started by the platform.
if (glue_is_launched_by_gd()) {
    // Get the starting context reader and extract the initial or restored state.
    const auto starting_context_reader = glue_get_starting_context_reader();
    const auto val = glue_read_glue_value(starting_context_reader, "state");
}

// Here `my_app` is a previously defined MFC object from which you can extract the window handle.
const HWND handle = my_app->m_pMainWnd->m_hWnd;

// Callback for handling io.Connect Window events.
void window_event_callback (glue_window_command command, const char* context_name, COOKIE cookie) {
    std::cout << "Window event for main window: " << command << std::endl;
}

// Register the main window.
glue_register_window(handle, &window_event_callback, "Main Window", nullptr, true);
```

### Child Windows

The save and restore state of child windows is handled in the [`app_callback_function`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#types-appcallbackfunction) passed to [`glue_app_announce_instance()`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#functions-glueappannounceinstance) when announcing a child app instance created by an [app factory](#app_factories). When the [`app_callback_function`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#types-appcallbackfunction) is invoked with the `save` [`glue_app_command`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#enums-glueappcommand), push a state to be saved, and when it's invoked with the `init` command, restore the saved state using the passed payload:

```cpp
// Callback for handling app events for each announced child instance.
// Passed as an argument to `glue_app_announce_instance()`.
void child_app_event_callback(const glue_app_command command, const void* callback, const glue_payload* payload, COOKIE cookie) {
    // Check the command with which the app event handler was invoked.
    switch (command) {
        case glue_app_command::save:
            // Use the io.Connect methods prefixed with `glue_push_` to push a save state.
            glue_push_json_payload(callback, "{io: {a: 42, b: \"forty-two\"}}");
            break;
        case glue_app_command::init: {
            // Use the io.Connect methods prefixed with `glue_read_` to extract the initial or restored state.
            const auto restore_state = glue_read_json(payload->reader, nullptr);
            std::cout << "Restored state: " << restore_state << std::endl;
            break;
        }
        default:
            break;
    }
}
```

> ℹ️ *For a full example of registering an app factory for child windows, see the [App Factories](#app_factories) section.*

## Events

To handle io.Connect app events (creating a child instance, saving and restoring state, shutdown), use the [`app_callback_function`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#types-appcallbackfunction) passed to [`glue_register_main_window()`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#functions-glueregistermainwindow), [`glue_app_register_factory()`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#functions-glueappregisterfactory) or [`glue_app_announce_instance()`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#functions-glueappannounceinstance). It will be invoked with an app command as a [`glue_app_command`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#enums-glueappcommand) indicating the io.Connect app event, a correlational callback that can be passed to other io.Connect methods (e.g., [`glue_app_announce_instance()`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#functions-glueappannounceinstance) when announcing a newly created app instance, or to [`glue_push_payload()`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#functions-gluepushpayload) when saving the app state), a [`glue_payload`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#structs-gluepayload) value holding the initial or restored state, and an optional callback cookie.

The `create` [`glue_app_command`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#enums-glueappcommand) is used only when creating child app instances and therefore this event can be handled only when registering an [app factory](#app_factories):

```cpp
// Callback that will be invoked with the `create` command when a child instance is created by the app factory.
void app_factory_callback (glue_app_command command, const void* callback, const ::glue_payload* payload, COOKIE cookie) {
    switch (command) {
        case glue_app_command::create: {
            // Create and announce a child app instance.
            // Handle the app events related to that instance.
            break;
        }
        default:
            break;
    }
}

// Register the app factory.
const void* my_app_factory = glue_app_register_factory("Child App", &app_factory_callback);
```

All other app events can be handled in the [`app_callback_function`](https://docs.interop.io/desktop/getting-started/how-to/interop-enable-your-apps/c-exports/index.md#types-appcallbackfunction) when registering a main window or announcing a child instance:

```cpp
// Callback for handling io.Connect app events.
void app_event_callback (glue_app_command command, const void* callback, const glue_payload* payload, COOKIE cookie) {
    // Check the command with which the app event handler was invoked.
    switch (command) {
        case glue_app_command::save:
            // Use the io.Connect methods prefixed with `glue_push_` to push a save state.
            glue_push_json_payload(callback, "{io: {a: 42, b: \"forty-two\"}}");
            break;
        case glue_app_command::init: {
            // Use the io.Connect methods prefixed with `glue_read_` to extract the initial or restored state.
            const auto restore_state = glue_read_json(payload->reader, nullptr);
            std::cout << "Restored state: " << restore_state << std::endl;
            break;
        }
        case glue_app_command::shutdown:
            std::cout << "The app will shutdown." << std::endl;
            // Close the window and free resources.
            break;
        default:
            break;
    }
}
```
