C++编写PowerPoint插件(四):集成DuiLib
本系列描述的是如何使用C++/COM来编写PowerPoint插件,使用的开发工具是 Visual Studio 2017。
Step 1:工程中引入DuiLib
- 将编译好的duilib(包括头文件、lib、dll)拷贝到工程所在目录下 
- 右键NativePPTAddin工程节点,属性->VC++目录->包含目录和库目录中加入duilib所在目录,加入后大概长这样:  
- 由于Duilib的头文件中包含了StdAfx.h,如果工程中没有这个文件,需要新建一个,留空白即可 
- 在 - pch.h中引入DuiLib- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 using namespace DuiLib;
Step 2:添加DuiLib的XML界面到资源
- 我们以登录框为例,添加一个XML到当前工程,取名叫LoginDialog.xml 
- 将LoginDialog.xml导入到资源中,资源类型为DUILIB - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 <Window size="400,320" caption="0,0,0,60" bktrans="true">
 <VerticalLayout>
 <HorizontalLayout height="52" bkcolor="#FF0288D1">
 <Label text="登录测试框" textcolor="0xFFFFFFFF" padding="20,0,0,0" font="1" />
 <Control />
 <Button name="minBtn" width="10" height="10" padding="0,21,20,0" normalimage="images\minimize.png" />
 <Button name="closeBtn" width="10" height="10" padding="0,21,20,0" normalimage="images\close.png" />
 </HorizontalLayout>
 <VerticalLayout bkcolor="0xFFFFFFFF">
 <Edit name="usernameEdit" height="48" font="3" padding="20,30,20,0" bordercolor="0xFF808080" bottombordersize="1" />
 <Edit name="passwordEdit" height="48" password="true" font="3" padding="20,20,20,0" bordercolor="0xFF808080" bottombordersize="1" />
 <Button name="loginBtn" text="登 录" height="50" bkcolor="#FF0277BD" textcolor="0xFFFFFFFF" font="2" padding="20,40,20,0" />
 </VerticalLayout>
 </VerticalLayout>
 </Window>
- 添加资源后,资源列表大概长这样:  
Step 3:C++实现LoginDialog
- 在NativePPTAddin工程节点,添加->新建项,选择”C++类”  
- 修改LoginDialog类,让它继承自WindowImplBase - 1 - class LoginDialog : public WindowImplBase 
- 实现基类WindowImplBase的几个虚函数 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11- DuiLib::CDuiString LoginDialog::GetSkinType() 
 {
 return _T("DUILIB");
 }
 CDuiString LoginDialog::GetSkinFile()
 {
 DuiLib::CDuiString dsResID;
 dsResID.Format(_T("%d"), IDR_DUILIB_LOGIN);
 return dsResID;
 }- 这表示LoginDialog将从资源中获取界面,资源类型为DUILIB,资源ID为IDR_DUILIB_LOGIN。 
- 再简单实现最小化、关闭、登录按钮的事件处理 - 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- DUI_BEGIN_MESSAGE_MAP(LoginDialog, WindowImplBase) 
 DUI_ON_MSGTYPE_CTRNAME(DUI_MSGTYPE_CLICK, _T("closeBtn"), onCloseBtnClick)
 DUI_ON_MSGTYPE_CTRNAME(DUI_MSGTYPE_CLICK, _T("minBtn"), onMinBtnClick)
 DUI_ON_MSGTYPE_CTRNAME(DUI_MSGTYPE_CLICK, _T("loginBtn"), onLoginBtnClick)
 DUI_END_MESSAGE_MAP()
 
 void LoginDialog::onCloseBtnClick(TNotifyUI & msg)
 {
 CWindowWnd::SendMessage(WM_CLOSE);
 }
 void LoginDialog::onMinBtnClick(TNotifyUI & msg)
 {
 CWindowWnd::SendMessage(WM_SYSCOMMAND, SC_MINIMIZE, 0);
 }
 void LoginDialog::onLoginBtnClick(TNotifyUI & msg)
 {
 CEditUI *usernameEdit = static_cast<CEditUI *>(m_pm.FindControl(_T("usernameEdit")));
 CEditUI *passwordEdit = static_cast<CEditUI *>(m_pm.FindControl(_T("passwordEdit")));
 if (usernameEdit == nullptr || passwordEdit == nullptr)
 return;
 TCHAR tmp[1024] = { 0 };
 swprintf_s(tmp, _T("您输入的用户名是 %s, 密码是 %s"), usernameEdit->GetText().GetData(), passwordEdit->GetText().GetData());
 ::MessageBox(m_hWnd, tmp, _T("提示"), MB_OK);
 }
Step 4:添加获取应用实例的全局变量
- 在dllmain.cpp中定义全局变量 - 1 - HINSTANCE g_hInstance; 
- 在pch.h中添加一个extern声明 - 1 - extern HINSTANCE g_hInstance; 
- 修改DllMain入口函数,给g_hInstance赋值 - 1 
 2
 3
 4
 5- extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) 
 {
 g_hInstance = hInstance;
 return _AtlModule.DllMain(dwReason, lpReserved);
 }
Step 5:在Connect中添加弹出对话框的处理
- 将Connect.cpp中原登录按钮的代码删除 
- 添加弹出登录对话框的函数 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12- void ShowLoginDialog() 
 {
 DuiLib::CPaintManagerUI::SetInstance(g_hInstance);
 TCHAR szPath[MAX_PATH] = { 0 };
 GetModuleFileName(g_hInstance, szPath, _countof(szPath));
 *_tcsrchr(szPath, _T('\\')) = 0;
 DuiLib::CPaintManagerUI::SetResourcePath(szPath);
 LoginDialog dialog;
 dialog.Create(::GetActiveWindow(), _T("登录"), UI_WNDSTYLE_FRAME, WS_EX_WINDOWEDGE);
 dialog.CenterWindow();
 dialog.ShowModal();
 }
- 重新实现Connect的ButtonClicked - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15- STDMETHODIMP_(HRESULT __stdcall) CConnect::ButtonClicked(IDispatch * control) 
 {
 CComQIPtr<IRibbonControl> ribbonCtl(control);
 CComBSTR idStr;
 if (ribbonCtl->get_Id(&idStr) != S_OK)
 return S_FALSE;
 if (idStr == OLESTR("loginButton")) {
 ShowLoginDialog();
 } else if (idStr == OLESTR("uploadButton")) {
 WCHAR msg[64];
 swprintf_s(msg, L"I am uploadButton");
 MessageBoxW(NULL, msg, L"NativePPTAddin", MB_OK);
 }
 return S_OK;
 }
- 启动调试,点击登录后,大概长这样:  
下一篇我们将介绍如何部署。
完整的代码在这里。