全部產品
Search
文件中心

Elastic Desktop Service:Windows外掛程式化串連管理SDK

更新時間:Feb 28, 2025

一、無影開放SDK整合與使用

1、要求

用戶端要求

WYSDK API是無影雲電腦應用程式的Windows安裝包的一部分。在用戶端裝置上安裝適用於Windows的無影雲電腦應用程式。確保WYSDK.dll(適用於64位機器)存在於無影雲電腦應用程式的Windows安裝資料夾中。

伺服器端要求

WYSDK要求在用戶端和伺服器之間完成登入、選擇雲電腦和擷取Ticket。無影服務端開放平台對接請參考API概覽

2、使用SDK的步驟

  • 驗證WYSDK二進位檔案是否安裝在用戶端上(WYSDK.dll)。

  • 從安裝路徑載入WYSDK.DLL。在這裡,用戶端可以使用無影雲電腦應用程式登錄機碼來擷取WYSDK二進位檔案的安裝路徑。

  • HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{D19D277C-E465-4F61-A725-231B7DB9255D}_is1是安裝的註冊表路徑。

  • 使用LoadLibrary載入WYSDK.DLL。

  • 使用GetProcAddress擷取API並相應使用,但要使用API,需要初始化SDK。

3、擷取WYSDK.DLL路徑

通過註冊擷取到無影雲電腦的安裝目錄

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;
}

4、Demo

範例程式碼

#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) {
    //初始化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);
    //監聽SDK日誌輸出回調
    AsyncRequest("WYRegisterListener", "{\"tag\": \"onOutputLog\"}", [](WYResponse value) {
        printf("%s\n", value.content);
    });
    //監聽SDK錯誤回調
    AsyncRequest("WYRegisterListener", "{\"tag\": \"onErrorCode\"}", [](WYResponse value) {
        int code = value.code;
        if (code == 200 || code == 201 || code == 202) {
            //建議: 最好去重啟進程, 如果不想重啟進程,可以去重新載入WYSDK.dll,但進程裡會存留一些垃圾靜態執行個體
        }
        printf("Listener callback tag %s value %d\n", value.requestParams, code);
    });
    //運行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();
        // 喚出問題反饋
        //WYResponse feedbackValue = WYSyncRequest("feedback", NULL);
        //FreeResponse(feedbackValue);
        // 喚出版本升級
        //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++) {
            //串連雲電腦/雲應用
            connectDesktop(false, desktopId, desktopName, desktopTicket);
            //connectDesktop(true, appInstanceGroupId, appName, appTicket);
            std::this_thread::sleep_for(std::chrono::seconds(5));

            toEnumerateConnectInfo();

            //斷開雲電腦/雲應用
            disconnectDesktop(desktopId);
            //std::this_thread::sleep_for(std::chrono::seconds(2));
            //disconnectDesktop(appInstanceGroupId);
        }
    }
    //取消監聽SDK錯誤回調
    WYResponse unErrorValue = SyncRequest("WYUnregisterListener", "{\"tag\": \"onErrorCode\"}");
    FreeResponse(unErrorValue);
    //取消監聽SDK日誌輸出回調
    WYResponse unLogValue = SyncRequest("WYUnregisterListener", "{\"tag\": \"onOutputLog\"}");
    FreeResponse(unLogValue);
    //銷毀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);
    //載入動態庫,動態庫的生命週期需要跟著進程生命週期走
    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");
    // 擷取函數指標
    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);
    }
    //不建議 卸載動態連結程式庫
    //FreeLibrary(hModule);
    //printf("finished to free SDK dll\n");
    return 0;
}

二、支援功能列表

功能

說明

開啟雲電腦

支援

斷開雲電腦

支援

開啟雲應用

支援

斷開雲應用

支援

設定語言(中文/英文)

支援 串連雲電腦配置

設定縮放比

支援 串連雲電腦配置

隱藏懸浮球

支援 串連雲電腦配置

是否全屏

支援 串連雲電腦配置

擷取裝置uuid

支援

擷取SDK版本號碼

支援

擷取所有雲電腦資訊

支援

監聽SDK錯誤回調

支援

監聽雲電腦/雲應用串連狀態

支援

喚出問題反饋介面

支援

喚出版本升級介面

支援

三、WYSDK的API

1、API簡介

WYSyncRequest

同步執行請求

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

key: 請求唯一標識

params:請求參數

  • 傳回值:

請求結構,結構如下

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

code為0,表示請求成功,content為請求到的資料,requestKey和requestParams為請求入參的key和params。

重要

注意:傳回值在使用完成的時候,調用WYFreeResponse去釋放WYResponse記憶體。

WYAsyncRequest

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

非同步執行請求,(備忘:非同步請求介面支援所有同步執行的key)

  • 參數:

key: 請求唯一標識

params:請求參數

callback:異常執行的回調

WYFreeResponse

void WYFreeResponse(WYResponse& response); 

釋放請求到的reponse對象

2、API使用

初始化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);

調用WYSyncRequest介面,參數為"WYInitialize"和配置資訊。

配置資訊,格式為JSON,其中必現包含partnerInfo和launcherPath相關資訊

partnerInfo:調用無影服務的合作方的資訊

○ partner:合作方公司名稱

○ partnerApp:合作方應用的名稱

launcherPath:為stream_launcher.exe的絕對路徑

傳回值:value.code 0-成功 其他值-失敗

釋放SDK

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

調用WYSyncRequest介面,參數為"WYUninitialize"。

傳回值:value.code 0-成功 其他值-失敗

運行SDK

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

調用WYSyncRequest介面,參數為"WYRun"。

傳回值:value.code 0-成功 其他值-失敗

監聽日誌輸出Listener

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

調用WYAsyncRequest介面,參數為"WYRegisterListener"、Listener參數(JSON結構)和執行回調。

Listener參數:tag唯一標識,狀態回調唯一標識為:onOutputLog。

監聽錯誤回調Listener

AsyncRequest("WYRegisterListener", "{\"tag\": \"onErrorCode\"}", [](WYResponse value) {
     int code = value.code;
     if (code == 200 || code == 201 || code == 202) {
         //建議: 最好去重啟進程, 如果不想重啟進程,可以去重新載入WYSDK.dll,但進程裡會存留一些垃圾靜態執行個體
     }
     printf("Listener callback tag %s value %d\n", value.requestParams, code);
});

調用WYAsyncRequest介面,參數為"WYRegisterListener"、Listener參數(JSON結構)和執行回調。

Listener參數:tag唯一標識,狀態回調唯一標識為:"onErrorCode"。

監聽雲電腦/雲應用狀態回調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);
});

調用WYAsyncRequest介面,參數為"WYRegisterListener"、Listener參數(JSON結構)和執行回調。

Listener參數:tag唯一標識,狀態回調唯一標識為:onStatusChange,connectId雲電腦/雲應用的ID

取消監聽Listener

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

調用WYAsyncRequest介面,參數為"WYUnregisterListener"、unlistener參數(JSON結構)。unlistener參數與listener對應。

建立串連雲電腦/雲應用

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

調用WYSyncRequest介面,參數為"WYCreateConnect"和串連參數。

串連參數:是一個JSON結構,格式如下

名稱

類型

必填

描述

樣本

operation

String

操作名稱

openDesktop-開啟雲電腦

openApp-開啟雲應用

  • bizParam

object

透傳從無影服務端擷取到的串連資訊

-- ticket

String

ticket為調用無影開放平台GetConnectionTicket - 擷取串連憑證介面返回的ticket資訊

-- desktopId

String

雲電腦Id

GetConnectionTicket - 擷取串連憑證 返回

ecd-7nvbz4ccjly95xxxx

-- desktopName

String

雲電腦名稱

GetConnectionTicket - 擷取串連憑證 返回

xx的雲電腦

-- osType

String

系統類別型

GetConnectionTicket - 擷取串連憑證 返回

windows

  • partnerInfo

object

調用無影服務的合作方的資訊

-- partner

String

合作方公司名稱

xxx公司

-- partnerApp

String

合作方應用的名稱

xxx應用

  • extInfo

object

擴充欄位,外部配置參數

-- language

String

設定一次後所有開啟的視窗UI都會顯示設定的語言(未設定時預設為中文)

“zh” --- 中文

“en” --- 英文

-- cloudDpi

int

雲電腦啟動時的預設dpi縮放比例

  • 僅限啟動Windows系統雲電腦時設定。若非有特殊需求,本參數無需設定

  • 參數為100-200之間的整數,例如150代表縮放比例150%

100

-- fullscreen

bool

是否在全屏視窗狀態開啟雲資源

  • 僅限雲資源開啟請求時設定。若非有特殊需求,本參數無需設定

true

-- isVpc

bool

是否走vpc網路

  • 僅限雲資源開啟請求時設定。若非有特殊需求,本參數無需設定

false

-- hideFloatingBall

bool

是否隱藏雲資源視窗內的懸浮球

  • 僅限雲資源開啟請求時設定。若非有特殊需求,本參數無需設定

false

  • proxy

object

網路代理程式配置

-- type

String

代理類型

目前支援系統代理程式、socket代理、HTTP代理3種方式

system - 系統代理程式

socket - socket代理

HTTP - HTTP代理

-- host

String

代理的host

127.x.x.x

-- port

int

代理連接埠號碼

50550

-- account

String

代理帳號

-- password

String

代理密碼

樣本

JSON格式

{
  "operation": "openDesktop",
  "bizParam": {
    "ticket": "xxxxxxxxxxxxxxxxxxxxxxx",
    "desktopId": "ecd-7nvbz4ccjly95xxxx",
    "desktopName": "xx的雲電腦",
    "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"
    }
  }

中斷連線雲電腦/雲應用

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

調用WYSyncRequest介面,參數為"WYDisconnect"和斷連參數。

斷連參數:是一個JSON結構,包含connectId

connectId: 使用雲電腦Id或雲應用id

遍曆擷取所有的雲電腦/雲應用資訊

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

調用WYSyncRequest介面,參數為“enumConnections”。

擷取結果value.content是一個JSON結構,

{
        "connection" : "***",
        "connectionPid" : 27324, //雲電腦的進程
        "partner" : "***",
        "partnerApp" : "***",
        "processId" : 8696,
        "status" : "start" //狀態值包含start和exit
}

擷取裝置的UUID

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

調用WYSyncRequest介面,參數為“uuid”。

擷取SDK版本號碼

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

調用WYSyncRequest介面,參數為"sdkVersion"。

喚出問題反饋面板

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

調用WYSyncRequest介面,參數為"feedback"。

喚出版本升級面板

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

調用WYSyncRequest介面,參數為"upgrade"。

四、錯誤碼列表

錯誤碼

說明

1

SDK初始化失敗

2

SDK配置沒有無影服務的合作方的資訊

100

開啟Launcher失敗

101

Launcher初始化失敗

200

擷取通訊service失敗(需要殺進程/卸載SDK,重新載入)

201

通訊service中斷(需要殺進程/卸載SDK,重新載入)

202

建立通訊service失敗(需要殺進程/卸載SDK,重新載入)

300

串連雲電腦/雲應用參數無效

301

串連雲電腦/雲應用失敗