Windows plugin-based connection management SDK
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.dllfrom 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
LoadLibraryto loadWYSDK.dll.Use
GetProcAddressto 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.
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 |
| 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 | my computer |
-- osType | String | Yes | Operating system type returned by GetConnectionTicket | windows |
| object | Yes | Information of the partner calling EDS services. | |
-- partner | String | Yes | Partner company name. | company |
-- partnerApp | String | Yes | Partner application name. | application |
| 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.
| 100 |
-- fullscreen | bool | No | Specifies whether to open cloud resources in full-screen mode.
| true |
-- isVpc | bool | No | Specifies whether to connect via a VPC network.
| false |
-- hideFloatingBall | bool | No | Specifies whether to hide the floating ball inside the cloud resource window.
| false |
| 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. |