C++編寫PowerPoint插件(三):按鈕的各種鉤子

本系列描述的是如何使用C++/COM來編寫PowerPoint插件,使用的開發(fā)工具是 Visual Studio 2017紊浩。

功能區(qū)的Tab頁可以定義各式各樣的控件窖铡,比如按鈕、下拉框坊谁、單選框费彼、多選框等。

每個控件都有不同的鉤子用來動態(tài)定義它的屬性呜袁,本文演示的僅僅是按鈕的各種鉤子敌买,其他類型的控件可以以此類推。

Step 1:按鈕的顯示文字 getLabel

  1. 修改RibbonManifest.xml阶界,將label=""刪除,添加getLabel="GetLabel"

    <button id="loginButton" screentip="登錄" getLabel="GetLabel" size="large" imageMso="WebPagePreview" onAction="ButtonClicked" />
    

    這表示顯示文字將從GetLabel鉤子中獲取

  2. 在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);
    };
    
  3. 在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

  1. 修改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>
    
  2. 在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);
    };
    
  3. 在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;
    }
    
  4. 啟動調(diào)試祭玉,我們將看到上傳按鈕已經(jīng)不見了氧映。

build-cplusplus-addin-for-ppt-13.png

Step 3:按鈕的圖片 image

  1. 通常情況下,我們會將圖片添加到資源中

    在資源視圖中脱货,右鍵NativePPTAddin.rc節(jié)點岛都,添加資源 ->導(dǎo)入->選擇需要的文件。

    導(dǎo)入成功后振峻,資源視圖大概長這樣:

build-cplusplus-addin-for-ppt-14.png
  1. 修改RibbonManifest.xml臼疫,刪除之前寫的imageMso,添加image="204" (204是在Resource.h中的登錄按鈕的資源ID)

    <button id="loginButton" screentip="登錄" getLabel="GetLabel" getVisible="GetVisible" image="204" size="large" onAction="ButtonClicked" />
    
  2. 此時扣孟,我們需要實現(xiàn)CustomUI的loadImage鉤子才能正常顯示圖片烫堤。

    修改RibbonManifest.xml,添加loadImage鉤子凤价。

    <customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" loadImage="CustomUILoadImage">
    
  3. 在NativePPTAddin.idl中的IRibbonCallback接口中添加CustomUILoadImage的定義

    [id(0x4004), helpstring("customUI LoadImage Callback")] HRESULT CustomUILoadImage([in] BSTR *pbstrImageId, [out, retval] IPictureDisp ** ppdispImage);
    
  4. 然后在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;
    }
    
  5. 再實現(xiàn)CustomUILoadImage鉤子

    STDMETHODIMP_(HRESULT __stdcall) CConnect::CustomUILoadImage(BSTR * imageId, IPictureDisp ** returnedVal)
    {
        return HrGetImageFromResource(_wtoi(*imageId), TEXT("PNG"), returnedVal);
    }
    
  6. 啟動調(diào)試利诺,我們將看到登錄按鈕的圖片已經(jīng)好了富蓄。

build-cplusplus-addin-for-ppt-15.png

Step 4:按鈕的圖片 getImage

  1. 修改RibbonManifest.xml,上傳按鈕我們使用getImage鉤子

    <button id="uploadButton" screentip="上傳" getLabel="GetLabel" getVisible="GetVisible" getImage="GetImage" size="large" onAction="ButtonClicked" />
    
  2. 在NativePPTAddin.idl中的IRibbonCallback接口中添加GetImage的定義

    [id(0x4003), helpstring("GetImage Callback")] HRESULT GetImage([in] IDispatch *pControl, [out, retval] IPictureDisp ** ppdispImage);
    
  3. 在資源視圖中導(dǎo)入上傳按鈕

build-cplusplus-addin-for-ppt-16.png
  1. 在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;
    }
    
  2. 看看效果

build-cplusplus-addin-for-ppt-17.png

下一篇我們將演示如何集成DuiLib慢逾,點擊按鈕彈出DuiLib對話框立倍。

完整的代碼在這里灭红。

Reference

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市帐萎,隨后出現(xiàn)的幾起案子比伏,更是在濱河造成了極大的恐慌,老刑警劉巖疆导,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赁项,死亡現(xiàn)場離奇詭異,居然都是意外死亡澈段,警方通過查閱死者的電腦和手機悠菜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來败富,“玉大人悔醋,你說我怎么就攤上這事∈薅#” “怎么了芬骄?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鹦聪。 經(jīng)常有香客問我账阻,道長,這世上最難降的妖魔是什么泽本? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任淘太,我火速辦了婚禮,結(jié)果婚禮上规丽,老公的妹妹穿的比我還像新娘蒲牧。我一直安慰自己,他們只是感情好赌莺,可當(dāng)我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布冰抢。 她就那樣靜靜地躺著,像睡著了一般雄嚣。 火紅的嫁衣襯著肌膚如雪晒屎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天缓升,我揣著相機與錄音鼓鲁,去河邊找鬼。 笑死港谊,一個胖子當(dāng)著我的面吹牛骇吭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播歧寺,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼燥狰,長吁一口氣:“原來是場噩夢啊……” “哼棘脐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起龙致,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蛀缝,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后目代,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體屈梁,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年榛了,在試婚紗的時候發(fā)現(xiàn)自己被綠了在讶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡霜大,死狀恐怖构哺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情战坤,我是刑警寧澤曙强,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站途茫,受9級特大地震影響旗扑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜慈省,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望眠菇。 院中可真熱鬧边败,春花似錦、人聲如沸捎废。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽登疗。三九已至排截,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間辐益,已是汗流浹背断傲。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留智政,地道東北人认罩。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像续捂,于是被迫代替她去往敵國和親垦垂。 傳聞我的和親對象是個殘疾皇子宦搬,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容