本系列描述的是如何使用C++/COM來編寫PowerPoint插件,使用的開發(fā)工具是 Visual Studio 2017紊浩。
功能區(qū)的Tab頁可以定義各式各樣的控件窖铡,比如按鈕、下拉框坊谁、單選框费彼、多選框等。
每個控件都有不同的鉤子用來動態(tài)定義它的屬性呜袁,本文演示的僅僅是按鈕的各種鉤子敌买,其他類型的控件可以以此類推。
Step 1:按鈕的顯示文字 getLabel
-
修改RibbonManifest.xml阶界,將
label=""
刪除,添加getLabel="GetLabel"
<button id="loginButton" screentip="登錄" getLabel="GetLabel" size="large" imageMso="WebPagePreview" onAction="ButtonClicked" />
這表示顯示文字將從GetLabel鉤子中獲取
-
在NativePPTAddin.idl中添加GetLabel的定義
interface IRibbonCallback : IDispatch { [id(0x4000), helpstring("Button Callback")] HRESULT ButtonClicked([in]IDispatch *pControl); [id(0x4001), helpstring("GetLabel Callback")] HRESULT GetLabel([in] IDispatch *pControl, [out, retval] BSTR *pbstrReturnedVal); };
-
在Connect中添加GetLabel鉤子的實現(xiàn)
STDMETHODIMP_(HRESULT __stdcall) CConnect::GetLabel(IDispatch * control, BSTR * returnedVal) { CComQIPtr<IRibbonControl> ribbonCtl(control); CComBSTR idStr; if (ribbonCtl->get_Id(&idStr) != S_OK) return S_FALSE; CComBSTR ret; if (idStr == OLESTR("loginButton")) { ret = OLESTR("登錄"); } else if (idStr == OLESTR("uploadButton")) { ret = OLESTR("上傳"); } *returnedVal = ret.Detach(); return S_OK; }
這個鉤子的定義在這里可以找到聋庵。
Step 2:按鈕的是否可見 getVisible
-
修改RibbonManifest.xml膘融,添加
getVisible="GetVisible"
<tab id="NativePPTAddinTab" label="Native測試"> <group id="userGroup" label="用戶"> <button id="loginButton" screentip="登錄" getLabel="GetLabel" getVisible="GetVisible" size="large" imageMso="WebPagePreview" onAction="ButtonClicked" /> </group> <group id="actionGroup" label="操作"> <button id="uploadButton" screentip="上傳" getLabel="GetLabel" getVisible="GetVisible" size="large" imageMso="WebPagePreview" onAction="ButtonClicked" /> </group> </tab>
-
在NativePPTAddin.idl中添加GetVisible的定義
interface IRibbonCallback : IDispatch { [id(0x4000), helpstring("Button Callback")] HRESULT ButtonClicked([in]IDispatch *pControl); [id(0x4001), helpstring("GetLabel Callback")] HRESULT GetLabel([in] IDispatch *pControl, [out, retval] BSTR *pbstrReturnedVal); [id(0x4002), helpstring("GetVisible Callback")] HRESULT GetVisible([in] IDispatch *pControl, [out, retval] VARIANT_BOOL *pvarReturnedVal); };
-
在Connect中添加GetVisible鉤子的實現(xiàn)
我們將登錄按鈕設(shè)為可見,上傳按鈕設(shè)為不可見
STDMETHODIMP_(HRESULT __stdcall) CConnect::GetVisible(IDispatch * control, VARIANT_BOOL * returnedVal) { CComQIPtr<IRibbonControl> ribbonCtl(control); CComBSTR idStr; if (ribbonCtl->get_Id(&idStr) != S_OK) return S_FALSE; if (idStr == OLESTR("loginButton")) { *returnedVal = VARIANT_TRUE; } else if (idStr == OLESTR("uploadButton")) { *returnedVal = VARIANT_FALSE; } return S_OK; }
啟動調(diào)試祭玉,我們將看到上傳按鈕已經(jīng)不見了氧映。
Step 3:按鈕的圖片 image
-
通常情況下,我們會將圖片添加到資源中
在資源視圖中脱货,右鍵NativePPTAddin.rc節(jié)點岛都,添加資源 ->導(dǎo)入->選擇需要的文件。
導(dǎo)入成功后振峻,資源視圖大概長這樣:
-
修改RibbonManifest.xml臼疫,刪除之前寫的imageMso,添加image="204" (204是在Resource.h中的登錄按鈕的資源ID)
<button id="loginButton" screentip="登錄" getLabel="GetLabel" getVisible="GetVisible" image="204" size="large" onAction="ButtonClicked" />
-
此時扣孟,我們需要實現(xiàn)CustomUI的loadImage鉤子才能正常顯示圖片烫堤。
修改RibbonManifest.xml,添加loadImage鉤子凤价。
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" loadImage="CustomUILoadImage">
-
在NativePPTAddin.idl中的IRibbonCallback接口中添加CustomUILoadImage的定義
[id(0x4004), helpstring("customUI LoadImage Callback")] HRESULT CustomUILoadImage([in] BSTR *pbstrImageId, [out, retval] IPictureDisp ** ppdispImage);
-
然后在Connect中實現(xiàn)它鸽斟,添加一個函數(shù),通過資源ID生成圖片
HRESULT HrGetImageFromResource(int nId, LPCTSTR lpType, IPictureDisp ** ppdispImage) { LPVOID pResourceData = NULL; DWORD len = 0; HRESULT hr = HrGetResource(nId, lpType, &pResourceData, &len); if (FAILED(hr)) { return E_UNEXPECTED; } IStream* pStream = nullptr; HGLOBAL hGlobal = nullptr; // copy image bytes into a real hglobal memory handle hGlobal = ::GlobalAlloc(GHND, len); if (hGlobal) { void* pBuffer = ::GlobalLock(hGlobal); if (pBuffer) { memcpy(pBuffer, reinterpret_cast<BYTE*>(pResourceData), len); HRESULT hr = CreateStreamOnHGlobal(hGlobal, TRUE, &pStream); if (SUCCEEDED(hr)) { // pStream now owns the global handle and will invoke GlobalFree on release hGlobal = nullptr; PICTDESC pic; memset(&pic, 0, sizeof pic); Gdiplus::Bitmap *png = Gdiplus::Bitmap::FromStream(pStream); HBITMAP hMap = NULL; png->GetHBITMAP(Gdiplus::Color(), &hMap); pic.picType = PICTYPE_BITMAP; pic.bmp.hbitmap = hMap; OleCreatePictureIndirect(&pic, IID_IPictureDisp, true, (LPVOID*)ppdispImage); } } } if (pStream) { pStream->Release(); pStream = nullptr; } if (hGlobal) { GlobalFree(hGlobal); hGlobal = nullptr; } return S_OK; }
-
再實現(xiàn)CustomUILoadImage鉤子
STDMETHODIMP_(HRESULT __stdcall) CConnect::CustomUILoadImage(BSTR * imageId, IPictureDisp ** returnedVal) { return HrGetImageFromResource(_wtoi(*imageId), TEXT("PNG"), returnedVal); }
啟動調(diào)試利诺,我們將看到登錄按鈕的圖片已經(jīng)好了富蓄。
Step 4:按鈕的圖片 getImage
-
修改RibbonManifest.xml,上傳按鈕我們使用getImage鉤子
<button id="uploadButton" screentip="上傳" getLabel="GetLabel" getVisible="GetVisible" getImage="GetImage" size="large" onAction="ButtonClicked" />
-
在NativePPTAddin.idl中的IRibbonCallback接口中添加GetImage的定義
[id(0x4003), helpstring("GetImage Callback")] HRESULT GetImage([in] IDispatch *pControl, [out, retval] IPictureDisp ** ppdispImage);
在資源視圖中導(dǎo)入上傳按鈕
-
在Connect類中實現(xiàn)它
STDMETHODIMP_(HRESULT __stdcall) CConnect::GetImage(IDispatch * control, IPictureDisp ** returnedVal) { CComQIPtr<IRibbonControl> ribbonCtl(control); CComBSTR idStr; if (ribbonCtl->get_Id(&idStr) != S_OK) return S_FALSE; if (idStr == OLESTR("loginButton")) { // do nothing // 登錄按鈕使用image屬性定義 } else if (idStr == OLESTR("uploadButton")) { return HrGetImageFromResource(IDB_PNG_UPLOAD, TEXT("PNG"), returnedVal); } return S_OK; }
看看效果
下一篇我們將演示如何集成DuiLib慢逾,點擊按鈕彈出DuiLib對話框立倍。
完整的代碼在這里灭红。
Reference
- https://docs.microsoft.com/en-us/previous-versions/office/developer/office-2010/ee941475(v=office.14)
- https://docs.microsoft.com/en-us/previous-versions/office/developer/office-2010/ee691833(v=office.14)
- https://vimsky.com/zh-tw/examples/detail/cpp-ex---CComBSTR---class.html
- https://stackoverflow.com/questions/66237978/c-gdi-how-to-get-and-load-image-from-resource