快速入门
本小节以实现初始化SDK为例,介绍如何使用Windows SDK进行二次集成开发。
开发环境准备
在开发的过程中请满足如下环境要求。
环境和工具名称 |
版本要求 |
说明 |
---|---|---|
操作系统 |
Windows 10/11专业版 |
硬件要求:
|
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%)上面会显示异常(图片模糊、共享时接收端观看画面不全、倾斜等。)
- 解压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下
- 创建工程项目。
- 打开Visual Studio 2017,单击菜单栏的“文件> 新建> 项目”,打开“新建项目”窗口。
图2 打开新建项目
- 在“新建项目”左侧选择“已安装> Visual C++”,然后在右侧模板中选择“MFC 应用程序”,在“名称”输入工程名称“Hello_World”,在“位置”选择工程保存位置,此处选择“E:\”,完成后点击“确定”。
图3 新建项目
- 在“应用程序类型选项”中选择“应用程序类型”为“基于对话框”,其余设置均保持默认值,单击完成。
图4 应用程序类型选项
- 打开Visual Studio 2017,单击菜单栏的“文件> 新建> 项目”,打开“新建项目”窗口。
- 拷贝静态库文件与头文件到项目中。
- 在“Hello_World”工程目录下新建“SDK”目录,与.sln文件同级。
图5 新建“SDK”
- 将“SDK”目录下的“lib”和“include”目录拷贝到“Hello_World\SDK”目录下。
图6 拷贝文件
- 在“Hello_World”工程目录下新建“SDK”目录,与.sln文件同级。
- 修改项目“配置属性”。
以下操作基于项目配置Debug与平台Win32,更改配置和平台时需要重新添加附加包含目录和附加依赖库。
- 在“Hello_World”项目右键单击“属性”。
图7 项目属性
- 在属性页左侧选择“配置属性 > C/C++ > 常规”,将“附加包含目录”的值修改为“..\SDK\include”, 点击“应用”按钮。
图8 配置“附加包含目录”
- 在属性页左侧选择“配置属性 > 链接器> 常规”,将“附加库目录”的值修改为“..\SDK\lib\win32”, 点击“应用”按钮。
图9 配置“附加库目录”
- 在属性页左侧选择“配置属性> 链接器> 输入”,将“附加依赖项”的值修改为“hwm_sdk_agent.lib”,点击“应用”。
图10 添加“附加依赖项”
- 在属性页左侧列表中选择“配置属性 > 常规”,“ 输出目录”值修改为“..\debug\win32”,点击“确定”按钮。
图11 配置“输出目录”
- 在属性页左侧列表中选择“配置属性 > 清单工具 > 输入和输出”,“ DPI识别功能”值修改为“每个监视器高 DPI 识别”,点击“确定”按钮。
- 在“Hello_World”项目右键单击“属性”。
- 添加界面资源控件。
- 在“资源视图 ”中,打开工程对应的Dialog页面。
图13 工程Dialog页面
- 选中页面上原有全部控件,按Delete键删除。
图14 删除原有控件
- 添加初始化按钮。
- 添加初始化按钮控件:打开“工具箱”页面,选中“Button”控件,拖至对话框页面上并调整宽高。
图15 添加初始化按钮
- 修改按钮上面的注释:选中按钮,右击选择“属性。
图16 打开按钮属性
- 在对应的属性页上,找到“Caption”项,将值修改为“Init”。
图17 修改按钮属性
- 在“资源视图 ”中,打开工程对应的Dialog页面。
- 添加按钮点击事件处理。
- 双击“Init”控件,系统会自动在Hello_WorldDlg.cpp中添加初始化按钮事件方法OnBnClickedButton1()。
图18 创建初始化按钮事件方法
- 双击“Init”控件,系统会自动在Hello_WorldDlg.cpp中添加初始化按钮事件方法OnBnClickedButton1()。
- 添加代码文件。
- 添加回调处理类。
- 选中项目右键“添加 > 类”。
图19 添加类
- 在“一般C++类向导”中填写类名“callbackProc”,其他保持默认,点击“完成”,保持现有工程。
图20 添加“callbackProc类”
- 选中项目右键“添加 > 类”。
- 添加通知处理类,类名设置为“notifyProc”。
图21 添加“notifyProc类”
- 添加回调处理类。
- 添加逻辑代码。
- 在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头文件实现完整代码。
- 在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)可能不一样,若有编译错误,以本地默认头文件为准。
- 在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头文件实现完整代码。
- 在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)可能不一样,若有编译错误,以本地默认头文件为准。
- 在Hello_WorldDlg.h文件中包含需要用到的头文件。
1
#include "HwmErrorCodeDef.h"
- 在Hello_WorldDlg.h文件中声明将要使用的函数。
1 2 3 4 5
public: //初始化接口 hwmsdk::HwmErrCode Init(); //退出接口 static hwmsdk::HwmErrCode Exit();
- 在Hello_WorldDlg.cpp文件中包含用到的头文件。
1 2 3 4
#include "notifyProc.h" #include "callBackProc.h" #include "HwmSdkAgent.h" #include <string>
- 在Hello_WorldDlg.cpp定义回调和通知对象。
1 2
static notifyProc *notifyObj = new notifyProc(); static callbackProc *callbackObj = new callbackProc();
- 在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; }
- 在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")); } }
上文代码部分与工程代码重复,注意区分,不要重复添加。
- 在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; }
- 在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; }
上文代码部分与工程代码重复,注意区分,不要重复添加。
- 在callbackProc.h文件中包含SDK回调类头文件HwmAgentCallback.h,使callbackProc类继承于基类HwmAgentCallback,可以只拷贝实现HwmAgentCallback.h文件中需要关注的接口调用回调函数。
- 编译及调试工程。
- 选中工程,右键选择“重新生成”,进行编译。
图22 生成文件
- 观察“Output”窗口,出现信息“全部重新生成: 成功 1 个,失败 0 个,跳过 0 个”,代表编译成功。
图23 生成结果
- 编译成功后,生成的可执行程序Hello_World.exe在输出目录下,当前输出目录路径为${path}\Hello_World\debug\win32。
图24 exe文件
- 拷贝“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内为公共依赖库文件
- 双击Hello_World.exe文件,启动界面。
图30 启动页面
- 点击“Init”按钮登录,初始化结果有弹框提示,0表示成功,其他表示失败,初始化成功后有启动通知弹框。
图31 结果提示
图32 启动通知
- 选中工程,右键选择“重新生成”,进行编译。