Windows plugin-based connection management SDK

Updated at:

Integrate and use WYSDK

Requirements

Client requirements

The WYSDK API is part of the Windows installation package for the Elastic Desktop Service (EDS) client application. Install the EDS client application for Windows on the client device. Ensure that WYSDK.dll (for 64-bit machines) exists in the Windows installation folder of the EDS client application.

Server requirements

WYSDK requires completing the login, selecting a cloud computer, and acquiring a ticket between the client and the server. For information on connecting to the EDS server-side open platform, see API overview.

Use the SDK

  • Verify that the WYSDK binary file (WYSDK.dll) is installed on the client.

  • Load WYSDK.dll from the installation path. Here, the client can use the Windows registry key of the EDS client application to retrieve the installation path of the WYSDK binary file.

  • The installation registry path is: HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{D19D277C-E465-4F61-A725-231B7DB9255D}_is1.

  • Use LoadLibrary to load WYSDK.dll.

  • Use GetProcAddress to obtain API function pointers and invoke them accordingly. Note that the SDK must be initialized before using the APIs.

Obtain the path of WYSDK.dll

Retrieve the installation directory of the EDS client through the Windows registry:

std::string getDicOfSDK() {
    HKEY hkey = nullptr;
    std::string sub_key = "SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{D19D277C-E465-4F61-A725-231B7DB9255D}_is1";
    LSTATUS res = ::RegOpenKeyExA(HKEY_LOCAL_MACHINE, sub_key.c_str(), 0, KEY_READ, &hkey);
    if (res != ERROR_SUCCESS) {
        printf("RegOpenKeyExA status:%d failed: %d\n", res, GetLastError());
        return "";
    }
    std::string valueName = std::string("InstallLocation");
    DWORD dwType = REG_SZ;
    DWORD dwSize = 0;
    LSTATUS ret = RegQueryValueExA(hkey, valueName.c_str(), NULL, &dwType, nullptr, &dwSize);
    if (ret != ERROR_SUCCESS || dwSize <= 0) {
        printf("RegQueryValueExA status:%d size:%d valueName:%s failed: %d\n", ret, dwSize, valueName.c_str(), GetLastError());
        RegCloseKey(hkey);
        return "";
    }

    std::vector<BYTE> value_data(dwSize);
    ret = RegQueryValueExA(hkey, valueName.c_str(), NULL, &dwType, value_data.data(), &dwSize);
    if (ret != ERROR_SUCCESS) {
        printf("RegQueryValueExA status:%d valueName:%s failed: %d\n", ret, valueName.c_str(), GetLastError());
        RegCloseKey(hkey);
        return "";
    }

    RegCloseKey(hkey);
    std::string path(value_data.begin(), value_data.end());
    if (path.back() == '\0') {
        path.pop_back();
    }
    path.append(std::string("bin"));

    printf("RegQueryValueExA11 valueName:%s res: %s\n", valueName.c_str(), path.c_str());
    return path;
}

Demo

Sample code: WYSDKDemo.zip

#include <iostream>
#include <windows.h>
#include <string>
#include <vector>
#include <thread>
#include <chrono>

struct WYResponse {
    int code;
    const char* content;
    const char* requestKey;
    const char* requestParams;
};

typedef WYResponse(*WYSyncRequest)(const char* key, const char* params);
typedef void (*WYAsyncRequest)(const char* key, const char* params, void (*callback)(WYResponse));
typedef void (*WYFreeResponse)(WYResponse& response);

WYSyncRequest SyncRequest;
WYAsyncRequest AsyncRequest;
WYFreeResponse FreeResponse;

std::string getConnectParams(const std::string& desktopId, const std::string& desktopName, const std::string& ticket) {
    std::string operationInfo = std::string("\"operation\":\"openDesktop\"");
    std::string bizParams = std::string("\"bizParam\":{\"ticket\":\"") + ticket + std::string("\",\"desktopId\":\"") + desktopId + std::string("\",\"desktopName\":\"") + desktopName + std::string("\"}");
    std::string extInfo = std::string("\"extInfo\":{\"language\":\"zh\",\"fullscreen\":false,\"hideFloatingBall\":false,\"cloudDpi\":150}");
    std::string connectParams = "";
    connectParams.append(std::string("{"));
    connectParams.append(operationInfo);
    connectParams.append(std::string(","));
    connectParams.append(bizParams);
    connectParams.append(std::string(","));
    connectParams.append(extInfo);
    connectParams.append(std::string("}"));
    return connectParams;
}

std::string getCloudAppConnectParams(const std::string& desktopId, const std::string& desktopName, const std::string& ticket) {
    std::string operationInfo = std::string("\"operation\":\"openApp\"");
    std::string bizParams = std::string("\"bizParam\":{\"ticket\":\"") + ticket + std::string("\",\"appInstanceGroupId\":\"") + desktopId + std::string("\",\"appName\":\"") + desktopName + std::string("\",") + std::string("\"osType\":\"Windows\"}");
    std::string connectParams = "";
    connectParams.append(std::string("{"));
    connectParams.append(operationInfo);
    connectParams.append(std::string(","));
    connectParams.append(bizParams);
    connectParams.append(std::string("}"));
    return connectParams;
}

void connectDesktop(bool isCloudApp, const std::string& desktopId, const std::string& desktopName, const std::string& ticket) {
    std::string listenerParams = std::string("{\"tag\": \"onStatusChange\", \"connectId\":\"");
    listenerParams.append(desktopId);
    listenerParams.append("\"}");
    AsyncRequest("WYRegisterListener", listenerParams.c_str(), [](WYResponse value) {
        printf("Listener callback value %s\n", value.content);
    });

    std::string connectParams = isCloudApp ? getCloudAppConnectParams(desktopId, desktopName, ticket) : getConnectParams(desktopId, desktopName, ticket);
    WYResponse createConnectValue = SyncRequest("WYCreateConnect", connectParams.c_str());
    FreeResponse(createConnectValue);
}

void disconnectDesktop(const std::string& desktopId) {
    std::string disparams = std::string("{\"connectId\":\"");
    disparams.append(desktopId);
    disparams.append("\"}");
    WYResponse disConnectValue = SyncRequest("WYDisconnect", disparams.c_str());
    FreeResponse(disConnectValue);

    std::string unListenerParams = std::string("{\"tag\": \"onStatusChange\", \"connectId\":\"");
    unListenerParams.append(desktopId);
    unListenerParams.append("\"}");
    WYResponse unStatusValue = SyncRequest("WYUnregisterListener", unListenerParams.c_str());
    FreeResponse(unStatusValue);
}

void toEnumerateConnectInfo() {
    WYResponse infoListValue = SyncRequest("enumConnections", NULL);
    printf("WYEnumerateConnectInfo info %s\n", infoListValue.content);
    FreeResponse(infoListValue);
}

void toGetUUID() {
    WYResponse uuidValue = SyncRequest("uuid", NULL);
    printf("uuid is %s\n", uuidValue.content);
    FreeResponse(uuidValue);
}

int runSDK(const std::string& directory) {
    // Initialize the SDK
    std::string config = std::string("{\"partnerInfo\":{\"partner\":\"wuyingPartnerTest\",\"partnerApp\":\"WuyingPartnerTestApp\"}, \"launcherPath\":\"");
    config.append(directory);
    config.append(std::string("\\stream_launcher.exe"));
    config.append(std::string("\"}"));
    WYResponse initValue = SyncRequest("WYInitialize", config.c_str());
    FreeResponse(initValue);
    // Listen to SDK log output callback
    AsyncRequest("WYRegisterListener", "{\"tag\": \"onOutputLog\"}", [](WYResponse value) {
        printf("%s\n", value.content);
    });
    // Listen to SDK error callback
    AsyncRequest("WYRegisterListener", "{\"tag\": \"onErrorCode\"}", [](WYResponse value) {
        int code = value.code;
        if (code == 200 || code == 201 || code == 202) {
            // Recommendation: Restart the process. Alternatively, reload WYSDK.dll, though residual static instances may remain in the process.
        }
        printf("Listener callback tag %s value %d\n", value.requestParams, code);
    });
    // Run the SDK
    WYResponse runValue = SyncRequest("WYRun", NULL);
    int runCode = runValue.code;
    FreeResponse(runValue);
    printf("sdk run %s\n", runCode == 0 ? "ok" : "fail");
    if (runCode == 0) {
        toGetUUID();
        // Invoke issue feedback panel
        //WYResponse feedbackValue = WYSyncRequest("feedback", NULL);
        //FreeResponse(feedbackValue);
        // Invoke version upgrade panel
        //WYResponse upgradeValue = WYSyncRequest("upgrade", NULL);
        //FreeResponse(upgradeValue);

        std::string desktopId = std::string("ecd-iolwxthr1vcpoefhp");
        std::string desktopName = std::string("wenzhang-20220927");
        std::string desktopTicket = std::string("*****");
        
        std::string appInstanceGroupId = std::string("ca-6p9vj2m79tlwcsl8z");
        std::string appName = std::string("Chrome");
        std::string appTicket = std::string("****");

        for (int i = 0; i < 1; i++) {
            // Connect to cloud computer or cloud application
            connectDesktop(false, desktopId, desktopName, desktopTicket);
            //connectDesktop(true, appInstanceGroupId, appName, appTicket);
            std::this_thread::sleep_for(std::chrono::seconds(5));

            toEnumerateConnectInfo();

            // Disconnect cloud computer or cloud application
            disconnectDesktop(desktopId);
            //std::this_thread::sleep_for(std::chrono::seconds(2));
            //disconnectDesktop(appInstanceGroupId);
        }
    }
    // Unregister SDK error callback listener
    WYResponse unErrorValue = SyncRequest("WYUnregisterListener", "{\"tag\": \"onErrorCode\"}");
    FreeResponse(unErrorValue);
    // Unregister SDK log output callback listener
    WYResponse unLogValue = SyncRequest("WYUnregisterListener", "{\"tag\": \"onOutputLog\"}");
    FreeResponse(unLogValue);
    // Uninitialize the SDK
    WYResponse unInitValue = SyncRequest("WYUninitialize", NULL);
    FreeResponse(unInitValue);
    printf("\n\n\n\n\n");
    return 0;
}

int main() {
    printf("begin to load SDK dll \n");
    std::string directory = "D:\\Code\\20230731\\output\\windows_amd64_release\\target\\bin";// getDicOfSDK();
    std::wstring wideDirectory(directory.begin(), directory.end());
    LPCWSTR widePath = wideDirectory.c_str();
    SetDllDirectory(widePath);
    // Load the dynamic link library. The lifecycle of the DLL must follow the process lifecycle.
    HMODULE hModule = LoadLibrary(L"WYSDK.dll");
    if (hModule == NULL) {
        std::cout << "Failed to load DLL" << GetLastError() << std::endl;
        return 1;
    }
    printf("load SDK dll success \n");
    printf("begin to load function \n");
    // Obtain function pointers
    SyncRequest = (WYSyncRequest)GetProcAddress(hModule, "WYSyncRequest");
    AsyncRequest = (WYAsyncRequest)GetProcAddress(hModule, "WYAsyncRequest");
    FreeResponse = (WYFreeResponse)GetProcAddress(hModule, "WYFreeResponse");
    if (!SyncRequest || !AsyncRequest || !FreeResponse) {
        printf("load function fail \n");
        return 1;
    }
    printf("load function success \n");
    for (int  i = 0; i < 1; i++)
    {
        runSDK(directory);
    }
    // Unloading the dynamic link library is not recommended.
    //FreeLibrary(hModule);
    //printf("finished to free SDK dll\n");
    return 0;
}

Supported features

Feature

Description

Open cloud computer

Supported

Disconnect cloud computer

Supported

Open cloud application

Supported

Disconnect cloud application

Supported

Set language (Chinese/English)

Supported (configured upon connecting to cloud computer)

Set display scale

Supported (configured upon connecting to cloud computer)

Hide floating ball

Supported (configured upon connecting to cloud computer)

Fullscreen mode

Supported (configured upon connecting to cloud computer)

Get device UUID

Supported

Get SDK version

Supported

Get all cloud computer information

Supported

Listen to SDK error callbacks

Supported

Listen to cloud computer/cloud application connection status

Supported

Open issue feedback panel

Supported

Open version upgrade panel

Supported

WYSDK API

API overview

WYSyncRequest

Executes a request synchronously.

WYResponse WYSyncRequest(constchar* key, constchar* params); 
  • Parameters:

key: The unique request identifier.

params: The request parameters.

  • Return value:

The response structure is as follows:

struct WYResponse {
    int code;
    const char* content;
    const char* requestKey;
    const char* requestParams;
};

A code of 0 indicates that the request was successful. content contains the returned data. requestKey and requestParams are the input key and params passed in the request.

Important

When you finish using the return value, make sure to call WYFreeResponse to release the memory of WYResponse.

WYAsyncRequest

void WYAsyncRequest(constchar* key, constchar* params, void (*callback)(WYResponse)); 

Executes a request asynchronously. The asynchronous request interface supports all keys used for synchronous execution.

  • Parameters:

key: The unique request identifier.

params: The request parameters.

callback: The callback function for asynchronous execution.

WYFreeResponse

void WYFreeResponse(WYResponse& response); 

Releases the returned WYResponse object.

API usage

Initialize the SDK

std::string directory = getDicOfSDK();
std::string config = std::string("{\"partnerInfo\":{\"partner\":\"***\",\"partnerApp\":\"***\"}, \"launcherPath\":\"");
config.append(directory);
config.append(std::string("\\stream_launcher.exe"));
config.append(std::string("\"}"));
WYResponse value = SyncRequest("WYInitialize", config.c_str());
FreeResponse(value);

Call WYSyncRequest with WYInitialize and configuration parameters.

The configuration parameter is a JSON string that must include partnerInfo and launcherPath:

partnerInfo: Information of the partner calling the EDS service

○ partner: The partner company name.

○ partnerApp: The partner application name.

launcherPath: The absolute path to stream_launcher.exe.

Return value: value.code == 0 indicates success; other values indicate failure.

Release the SDK

WYResponse value = SyncRequest("WYUninitialize", NULL);
FreeResponse(value);

Call WYSyncRequest with WYUninitialize.

Return value: value.code == 0 indicates success; other values indicate failure.

Run the SDK

WYResponse value = SyncRequest("WYRun", NULL);
FreeResponse(value);

Call WYSyncRequest with WYRun

Return value: value.code == 0 indicates success; other values indicate failure.

Register log output listener

AsyncRequest("WYRegisterListener", "{\"tag\": \"onOutputLog\"}", [](WYResponse value) {
     printf("%s\n", value.content);
});

Call WYAsyncRequest with WYRegisterListener, listener parameters (JSON structure), and the callback function.

Listener parameters: tag is the unique identifier; the tag for log output callback is onOutputLog.

Register error callback listener

AsyncRequest("WYRegisterListener", "{\"tag\": \"onErrorCode\"}", [](WYResponse value) {
     int code = value.code;
     if (code == 200 || code == 201 || code == 202) {
         // Recommendation: Restart the process. Alternatively, reload WYSDK.dll, though residual static instances may remain in the process.
     }
     printf("Listener callback tag %s value %d\n", value.requestParams, code);
});

Call WYAsyncRequest with WYRegisterListener, listener parameters (JSON structure), and the callback function.

Listener parameters: tag is the unique identifier; the tag for error status callback is onErrorCode.

Register cloud computer/cloud app status listener

std::string listenerParams = std::string("{\"tag\": \"onStatusChange\", \"connectId\":\"");
listenerParams.append(desktopId);
listenerParams.append("\"}");
AsyncRequest("WYRegisterListener", listenerParams.c_str(), [](WYResponse value) {
    printf("Listener callback value %s\n", value.content);
});

Call WYAsyncRequest with WYRegisterListener, listener parameters (JSON structure), and the callback function.

Listener parameters: tag is the unique identifier (onStatusChange), and connectId is the ID of the cloud computer or cloud app.

Unregister listener

std::string unListenerParams = std::string("{\"tag\": \"onStatusChange\", \"connectId\":\"");
unListenerParams.append(desktopId);
unListenerParams.append("\"}");
WYResponse unStatusValue = SyncRequest("WYUnregisterListener", unListenerParams.c_str());
FreeResponse(unStatusValue);

Call WYAsyncRequest with WYUnregisterListener and unlistener parameters (JSON structure). The unlistener parameters correspond to the registered listener.

Connect to cloud computer/cloud app

std::string connectParams = “{***}”;
WYResponse createConnectValue = SyncRequest("WYCreateConnect", connectParams.c_str());
FreeResponse(createConnectValue);

Call WYSyncRequest with WYCreateConnect and the connection parameters.

Connection parameters: A JSON structure in the following format:

Field

Type

Required

Description

Example

operation

String

Yes

Operation name.

openDesktop: Open cloud computer

openApp: Open cloud app

  • bizParam

object

Yes

Transparently passes the connection information obtained from the EDS server.

-- ticket

String

Yes

Ticket information returned by calling the EDS Open Platform GetConnectionTicket API.

-- desktopId

String

Yes

Cloud computer ID returned by GetConnectionTicket

ecd-7nvbz4ccjly95xxxx

-- desktopName

String

Yes

Cloud computer name returned by

GetConnectionTicket

my computer

-- osType

String

Yes

Operating system type returned by GetConnectionTicket

windows

  • partnerInfo

object

Yes

Information of the partner calling EDS services.

-- partner

String

Yes

Partner company name.

company

-- partnerApp

String

Yes

Partner application name.

application

  • extInfo

object

No

Extended fields for external configuration parameters.

-- language

String

No

Once set, the UI of all opened windows will display in the specified language (defaults to Chinese if not set).

zh: Chinese

en: English

-- cloudDpi

int

No

Default DPI scaling factor when starting the cloud computer.

  • Applicable only when starting a Windows cloud computer. Do not set this parameter unless required.

  • An integer from 100 to 200. For example, 150 indicates a 150% scaling ratio.

100

-- fullscreen

bool

No

Specifies whether to open cloud resources in full-screen mode.

  • Applicable only during cloud resource opening requests. Do not set this parameter unless required.

true

-- isVpc

bool

No

Specifies whether to connect via a VPC network.

  • Applicable only during cloud resource opening requests. Do not set this parameter unless required.

false

-- hideFloatingBall

bool

No

Specifies whether to hide the floating ball inside the cloud resource window.

  • Applicable only during cloud resource opening requests. Do not set this parameter unless required.

false

  • proxy

object

No

Network proxy configuration.

-- type

String

No

Proxy type. Supports three types: system proxy, socket proxy, and HTTP proxy.

system: system proxy

socket: socket proxy

HTTP: HTTP proxy

-- host

String

No

Proxy host.

127.x.x.x

-- port

int

No

Proxy port number.

50550

-- account

String

No

Proxy account username.

-- password

String

No

Proxy password.

Example

JSON format

{
  "operation": "openDesktop",
  "bizParam": {
    "ticket": "xxxxxxxxxxxxxxxxxxxxxxx",
    "desktopId": "ecd-7nvbz4ccjly95xxxx",
    "desktopName": "xxxxxx",
    "osType": "windows"
  },
  "partnerInfo": {
    "partner": "wuyingPartnerTest",
    "partnerApp": "WuyingPartnerTestApp"
  },
  "extInfo": {
    "language": "zh",
    "cloudDpi": 150,
    "fullscreen": true,
    "isVpc": true,
    "hideFloatingBall": true,
    "proxy": {
      "type": "system",
      "host": "xxxxxx",
      "port": 1111,
      "account": "xxxx",
      "password": "xxx"
    }
  }

Disconnect from cloud computer/cloud app

WYResponse disConnectValue = SyncRequest("WYDisconnect", "{\"connectId\":\"***\"}");
FreeResponse(disConnectValue);

Call the WYSyncRequest interface with the parameter WYDisconnect and the disconnection parameters.

Disconnection parameters: A JSON structure containing connectId.

connectId: The ID of the cloud computer or cloud app.

Enumerate information of all cloud computers/cloud apps

WYResponse value = SyncRequest("enumConnections", NULL);
printf("WYEnumerateConnectInfo info %s\n", value.content);
FreeResponse(value);

Call the WYSyncRequest interface with the parameter enumConnections.

Returned result: value.content is a JSON structure:

{
        "connection" : "***",
        "connectionPid" : 27324, // Cloud computer process
        "partner" : "***",
        "partnerApp" : "***",
        "processId" : 8696,
        "status" : "start" // Status values include start and exit
}

Get Device UUID

WYResponse value = SyncRequest("uuid", NULL);
printf("uuid is %s\n", value.content);
FreeResponse(value);

Call the WYSyncRequest interface with the parameter uuid.

Get SDK version

WYResponse value = SyncRequest("sdkVersion", NULL);
printf("version is %s\n", value.content);
FreeResponse(value);

Call the WYSyncRequest interface with the parameter sdkVersion.

Open feedback panel

WYResponse value = WYSyncRequest("feedback", NULL);
FreeResponse(value);

Call the WYSyncRequest interface with the parameter feedback.

Open version upgrade panel

WYResponse value = WYSyncRequest("upgrade", NULL);
FreeResponse(value);

Call the WYSyncRequest interface with the parameter upgrade.

Error codes

Error code

Description

1

Failed to initialize the SDK.

2

The SDK configuration does not contain information about the EDS partner.

100

Failed to open Launcher.

101

Failed to initialize Launcher.

200

Failed to get the communication service (you need to kill the process/uninstall the SDK and reload it).

201

The communication service was interrupted (you need to kill the process/uninstall the SDK and reload it).

202

Failed to create the communication service (you need to kill the process/uninstall the SDK and reload it).

300

Invalid parameters for connecting to the cloud computer/cloud app.

301

Failed to connect to the cloud computer/cloud app.