更新时间:2024-07-30 GMT+08:00

快速入门

本小节以实现初始化SDK为例,介绍如何使用Windows SDK进行二次集成开发。

开发环境准备

在开发的过程中请满足如下环境要求。

表1 环境要求

环境和工具名称

版本要求

说明

操作系统

Windows 10/11专业版

硬件要求:

  • CPU:i5-2400四核 3.1GHz及以上。
  • 内存:4GB及以上。

Microsoft Visual Studio

Visual Studio 2017

安装时需要勾选“使用 C++ 的桌面开发”,“用于 x86 和 x64 的 Visual C++ MFC”,“Windows 10 SDK (10.0.15063.0)”

测试资源及App ID申请

-

请参见“开发前准备”。

SDK快速集成

集成SDK的exe需要打开每个监视器高dpi识别开关、否则在高dpi的电脑(缩放比例大于100%)上面会显示异常(图片模糊、共享时接收端观看画面不全、倾斜等。)

示例:图12 配置“DPI识别功能”

  1. 解压SDK压缩包到本地。

    图1 解压SDK压缩包到本地
    表2 SDK目录介绍

    文件夹

    用途

    include

    该文件夹下放置编译所需头文件

    lib

    该文件夹下有win32和x64两个子文件夹,分别放置对应平台编译所依赖的.lib文件

    dll

    该文件夹下有win32和x64两个子文件夹,分别放置对应平台运行所依赖的.dll和SDK可执行.exe文件

    HwmSdk

    该文件夹下放置win32和x64公共使用的依赖库

    demo

    该文件夹下放置demo代码文件与资源文件

    Meeting-Workspace-Plugin路径下的是云桌面插件相关的库文件。如果需要集成云桌面插件功能,需要拷贝到HwmSdk\sdkResources下

  2. 创建工程项目。

    1. 打开Visual Studio 2017,单击菜单栏的“文件> 新建> 项目”,打开“新建项目”窗口。
      图2 打开新建项目
    2. 在“新建项目”左侧选择“已安装> Visual C++”,然后在右侧模板中选择“MFC 应用程序”,在“名称”输入工程名称“Hello_World”,在“位置”选择工程保存位置,此处选择“E:\”,完成后点击“确定”。
      图3 新建项目
    3. 在“应用程序类型选项”中选择“应用程序类型”为“基于对话框”,其余设置均保持默认值,单击完成。
      图4 应用程序类型选项

  3. 拷贝静态库文件与头文件到项目中。

    1. 在“Hello_World”工程目录下新建“SDK”目录,与.sln文件同级。
      图5 新建“SDK”

    2. 将“SDK”目录下的“lib”和“include”目录拷贝到“Hello_World\SDK”目录下。
      图6 拷贝文件

  4. 修改项目“配置属性”。

    以下操作基于项目配置Debug与平台Win32,更改配置和平台时需要重新添加附加包含目录和附加依赖库。

    1. 在“Hello_World”项目右键单击“属性”。
      图7 项目属性
    2. 在属性页左侧选择“配置属性 > C/C++ > 常规”,将“附加包含目录”的值修改为“..\SDK\include”, 点击“应用”按钮。
      图8 配置“附加包含目录”
    3. 在属性页左侧选择“配置属性 > 链接器> 常规”,将“附加库目录”的值修改为“..\SDK\lib\win32”, 点击“应用”按钮。
      图9 配置“附加库目录”
    4. 在属性页左侧选择“配置属性> 链接器> 输入”,将“附加依赖项”的值修改为“hwm_sdk_agent.lib”,点击“应用”。
      图10 添加“附加依赖项”
    5. 在属性页左侧列表中选择“配置属性 > 常规”,“ 输出目录”值修改为“..\debug\win32”,点击“确定”按钮。
      图11 配置“输出目录”
    6. 在属性页左侧列表中选择“配置属性 > 清单工具 > 输入和输出”,“ DPI识别功能”值修改为“每个监视器高 DPI 识别”,点击“确定”按钮。
      图12 配置“DPI识别功能”

  5. 添加界面资源控件。

    1. 在“资源视图 ”中,打开工程对应的Dialog页面。
      图13 工程Dialog页面
    2. 选中页面上原有全部控件,按Delete键删除。
      图14 删除原有控件
    3. 添加初始化按钮。
      1. 添加初始化按钮控件:打开“工具箱”页面,选中“Button”控件,拖至对话框页面上并调整宽高。
      图15 添加初始化按钮
      1. 修改按钮上面的注释:选中按钮,右击选择“属性。
        图16 打开按钮属性
      2. 在对应的属性页上,找到“Caption”项,将值修改为“Init”。
        图17 修改按钮属性

  6. 添加按钮点击事件处理。

    1. 双击“Init”控件,系统会自动在Hello_WorldDlg.cpp中添加初始化按钮事件方法OnBnClickedButton1()。
      图18 创建初始化按钮事件方法

  7. 添加代码文件。

    1. 添加回调处理类。
      1. 选中项目右键“添加 > 类”。
        图19 添加类
      2. 在“一般C++类向导”中填写类名“callbackProc”,其他保持默认,点击“完成”,保持现有工程。
        图20 添加“callbackProc类”
    2. 添加通知处理类,类名设置为“notifyProc”。
      图21 添加“notifyProc类”

  8. 添加逻辑代码。

    1. 在callbackProc.h文件中包含SDK回调类头文件HwmAgentCallback.h,使callbackProc类继承于基类HwmAgentCallback,可以只拷贝实现HwmAgentCallback.h文件中需要关注的接口调用回调函数。
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      #pragma once
      #include "HwmAgentCallback.h"
       
      class callbackProc : public hwmsdkagent::HwmAgentCallback
      {
      public:
          callbackProc();
          ~callbackProc();
          /**
               * @brief [en] Callback of Init interface.
               *
               * @param [in] hwmsdk::HwmErrCode ret    [en] Return code
               * @param [in] const char* reason        [en] Fail reason
               * @attention [en] NA
               **/
          void OnInitResult(hwmsdk::HwmErrCode ret, const char* reason, HwmSdkInfo *sdkInfo);
       
          /**
           * @brief [en] Callback of Exit interface.
           *
           * @param [in] hwmsdk::HwmErrCode ret    [en] Return code
           * @param [in] const char* reason        [en] Fail reason
           * @attention [en] NA
           **/
          void OnExitResult(hwmsdk::HwmErrCode ret, const char* reason);
          
          //为节省篇幅,此处省略其他若干回调接口,实际操作时请注意拷贝完整关注的回调函数。
      }
      

      为节省篇幅,上文代码中有部分省略,请根据SDK头文件实现完整代码。

    2. 在callbackProc.cpp文件中定义接口。
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      #include "stdafx.h"
      #include "callbackProc.h"
      
      callbackProc::callbackProc()
      {
       
      }
      callbackProc::~callbackProc()
      {
       
      }
       
      /**
      * 初始化回调
      */
      void callbackProc::OnInitResult(hwmsdk::HwmErrCode ret, const char* reason, HwmSdkInfo *sdkInfo)
      {
          CString retStr;
          retStr.Format(_T("%d"), ret);
          CString tips = _T("OnInitResult code:") + retStr;
          AfxMessageBox(tips);
      }
      
      /**
      * 退出回调*/
      void callbackProc::OnExitResult(hwmsdk::HwmErrCode ret, const char* reason)
      {
          CString retStr;
          retStr.Format(_T("%d"), ret);
          CString tips = _T("OnExitResult code:") + retStr;
          AfxMessageBox(tips);
      }
      
      //为节省篇幅,此处省略若干代码,实际操作时请注意定义实现关注的回调函数接口。
      

      为节省篇幅,上文代码中有部分省略,请根据SDK头文件实现完整代码。不同版本使用预编译头文件的头文件(stdafx.h或pch.h)可能不一样,若有编译错误,以本地默认头文件为准。

    3. 在notifyProc.h文件中包含SDK回调类头文件HwmAgentNotify.h,使callbackProc类继承于基类HwmAgentNotify,可以只拷贝实现HwmAgentNotify.h文件中需要关注的接口调用回调函数。
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      #pragma once
      #include "HwmAgentNotify.h"
       
       
      class notifyProc : public hwmsdkagent::HwmAgentNotify
      {
      public:
          notifyProc();
          ~notifyProc();
       
          /**
           * @brief [en] Notify of sdk disconnected.
           *
           * @attention [en] NA
           **/
          void OnSdkDisconnected();
      
          //为节省篇幅,此处省略其他若干回调接口,实际操作时请注意拷贝完整关注的回调函数。
      }
      

      为节省篇幅,上文代码中有部分省略,请根据SDK头文件实现完整代码。

    4. 在notifyProc.cpp文件中定义接口。
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      #include "stdafx.h"
      #include "notifyProc.h"
       
      notifyProc::notifyProc()
      {
       
      }
      notifyProc::~notifyProc()
      {
       
      }
       
      //SDK连接断开通知
      void notifyProc::OnSdkDisconnected()
      {
          CString tips = _T("OnSdkDisconnected");
          AfxMessageBox(tips);
      }
      
      //为节省篇幅,此处省略其他若干回调接口,实际操作时请注意拷贝完整关注的回调函数。 
      

      为节省篇幅,上文代码中有部分省略,请根据SDK头文件实现完整代码。不同版本使用预编译头文件的头文件(stdafx.h或pch.h)可能不一样,若有编译错误,以本地默认头文件为准。

    5. 在Hello_WorldDlg.h文件中包含需要用到的头文件。
      1
      #include "HwmErrorCodeDef.h"
      
    6. 在Hello_WorldDlg.h文件中声明将要使用的函数。
      1
      2
      3
      4
      5
      public:
          //初始化接口
          hwmsdk::HwmErrCode Init();
          //退出接口
          static hwmsdk::HwmErrCode Exit();
      
    7. 在Hello_WorldDlg.cpp文件中包含用到的头文件。
      1
      2
      3
      4
      #include "notifyProc.h"
      #include "callBackProc.h"
      #include "HwmSdkAgent.h"
      #include <string>
      
    8. 在Hello_WorldDlg.cpp定义回调和通知对象。
      1
      2
      static notifyProc *notifyObj = new notifyProc();
      static callbackProc *callbackObj = new callbackProc();
      
    9. 在Hello_WorldDlg.cpp文件中定义初始化接口。
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      /**
      *初始化接口
      */
      hwmsdk::HwmErrCode CHello_WorldDlg::Init()
      {
          //组装入参结构体
          hwmsdkagent::HwmInitInfo initParam;
          memset(&initParam, 0, sizeof(hwmsdkagent::HwmInitInfo));
       
          //(win32平台不需要)x64平台需要设置sdk路径,即exe文件路径,对exe文件重命名后,需要对应修改
          //将path路径转换为UTF8格式后拷贝给initParam,此处省略转换代码
          strcpy_s(initParam.exePath, HWM_MAX_FILE_PATH_LEN, GetHwmSdkExePath().c_str());
          //指定日志路径,将路径转换为UTF8格式后拷贝给initParam,此处省略转换代码
          strcpy_s(initParam.logPath, HWM_MAX_FILE_PATH_LEN, GetLogPath().c_str());
          //指定数据路径,将路径转换为UTF8格式后拷贝给initParam,此处省略转换代码
          strcpy_s(initParam.userDataPath, HWM_MAX_FILE_PATH_LEN, GetUserDataPath().c_str());
          strncpy_s(initParam.appId, GetAppId.c_str(), HWM_MAX_APPID_LEN);
       
          initParam.notify = notifyObj;
          initParam.callback = callbackObj;
          hwmsdk::HwmErrCode ret = hwmsdkagent::Init(&initParam);
       
          return ret;
      }
      
    10. 在Hello_WorldDlg.cpp文件中实现初始化按钮点击事件处理。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      void CHello_WorldDlg::OnBnClickedButton1()
      {
          // TODO: 在此添加控件通知处理程序代码
          hwmsdk::HwmErrCode ret = Init();
          if (hwmsdk::HWM_COMMON_SUCCESS != ret)
          {
              AfxMessageBox(_T("Init error"));
          }
      }
      

      上文代码部分与工程代码重复,注意区分,不要重复添加。

    11. 在Hello_WorldDlg.cpp定义退出接口
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      /**
      *退出接口
      */
      hwmsdk::HwmErrCode CHello_WorldDlg::Exit()
      {
          hwmsdk::HwmErrCode ret = hwmsdkagent::Exit();
          if (hwmsdk::HWM_COMMON_SUCCESS != ret)
          {
              AfxMessageBox(_T("Exit error"));
          }
          return ret;
      }
      
    12. 在Hello_World.cpp文件中找到InitInstance接口,在窗口退出时调用Exit接口。
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      // CHello_WorldApp 初始化
       
      BOOL CHello_WorldApp::InitInstance()
      {
          // 如果一个运行在 Windows XP 上的应用程序清单指定要
          // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,
          //则需要 InitCommonControlsEx()。  否则,将无法创建窗口。
          INITCOMMONCONTROLSEX InitCtrls;
          InitCtrls.dwSize = sizeof(InitCtrls);
          // 将它设置为包括所有要在应用程序中使用的
          // 公共控件类。
          InitCtrls.dwICC = ICC_WIN95_CLASSES;
          InitCommonControlsEx(&InitCtrls);
       
          CWinApp::InitInstance();
       
       
          AfxEnableControlContainer();
       
          // 创建 shell 管理器,以防对话框包含
          // 任何 shell 树视图控件或 shell 列表视图控件。
          CShellManager *pShellManager = new CShellManager;
       
          // 激活“Windows Native”视觉管理器,以便在 MFC 控件中启用主题
          CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
       
          // 标准初始化
          // 如果未使用这些功能并希望减小
          // 最终可执行文件的大小,则应移除下列
          // 不需要的特定初始化例程
          // 更改用于存储设置的注册表项
          // TODO: 应适当修改该字符串,
          // 例如修改为公司或组织名
          SetRegistryKey(_T("应用程序向导生成的本地应用程序"));
       
          CHello_WorldDlg dlg;
          m_pMainWnd = &dlg;
          INT_PTR nResponse = dlg.DoModal();
          if (nResponse == IDOK)
          {
              // TODO: 在此放置处理何时用
              //  “确定”来关闭对话框的代码
              CHello_WorldDlg::Exit();
          }
          else if (nResponse == IDCANCEL)
          {
              // TODO: 在此放置处理何时用
              //  “取消”来关闭对话框的代码
              CHello_WorldDlg::Exit();
       
          }
          else if (nResponse == -1)
          {
              TRACE(traceAppMsg, 0, "警告: 对话框创建失败,应用程序将意外终止。\n");
              TRACE(traceAppMsg, 0, "警告: 如果您在对话框上使用 MFC 控件,则无法 #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS。\n");
          }
       
          // 删除上面创建的 shell 管理器。
          if (pShellManager != nullptr)
          {
              delete pShellManager;
          }
       
      #if !defined(_AFXDLL) && !defined(_AFX_NO_MFC_CONTROLS_IN_DIALOGS)
          ControlBarCleanUp();
      #endif
       
          // 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序,
          //  而不是启动应用程序的消息泵。
          return FALSE;
      }
      

      上文代码部分与工程代码重复,注意区分,不要重复添加。

  9. 编译及调试工程。

    1. 选中工程,右键选择“重新生成”,进行编译。
      图22 生成文件
    2. 观察“Output”窗口,出现信息“全部重新生成: 成功 1 个,失败 0 个,跳过 0 个”,代表编译成功。
      图23 生成结果
    3. 编译成功后,生成的可执行程序Hello_World.exe在输出目录下,当前输出目录路径为${path}\Hello_World\debug\win32。
      图24 exe文件
    4. 拷贝“SDK\dll”目录和“SDK\HwmSdk”目录下对应文件到输出目录。

      如果配置为win32平台时,拷贝SDK\dll\win32内dll到输出目录,拷贝SDK\HwmSdk内所有文件到输出目录

      图25 拷贝SDK\dll\win32内dll到输出目录:

      图26 拷贝SDK\HwmSdk内所有文件到输出目录

      如果配置为x64平台时,拷贝SDK\dll\x64内dll到输出目录,拷贝SDK\HwmSdk整个文件夹到输出目录,拷贝SDK\dll\x64内HwmSdk.exe到输出目录HwmSdk文件夹下。

      图27 拷贝SDK\dll\x64内dll到输出目录

      图28 拷贝SDK\HwmSdk整个文件夹到输出目录

      图29 拷贝SDK\dll\x64内HwmSdk.exe到输出目录HwmSdk文件夹下

      配置为Win32平台时,目录地址为SDK\dll\win32,配置为x64平台时,目录地址为SDK\dll\x64。HwmSdk内为公共依赖库文件

    5. 双击Hello_World.exe文件,启动界面。
      图30 启动页面
    6. 点击“Init”按钮登录,初始化结果有弹框提示,0表示成功,其他表示失败,初始化成功后有启动通知弹框。
      图31 结果提示
      图32 启动通知