在MFC的应用程序中使用插件DLL中的Toolbar

本文原发表于www.hellocpp.net 请大家给与支持。

http://www.hellocpp.net/Articles/Article/715.aspx

 

   本文要介绍的并非是如何使用dll中的toolbar。而是如何通过插件dll给主程序扩展Toolbar。
首先我要说的是要使用dll中的toolbar其实挺简单的。只要在主程序里new一个CMFCToolbar对象,然后Load(IDS_DLL_TOOLBAR)就可以。同时为这个Toolbar的所有CAMMNND定义OnXXXX和OnUpdateXXXXUI函数。
不过这样做显然不合适的。因为首先你的主程序必须知道这个Toolbar ID。并且把它New出来。而且还需要知道这个Toolbar上的所有Command ID。这样严重的不符合插件的精神。
   那么接下来很容易想到把插件也做成MFC程序,把Toolbar在插件里new。然后你自己把Toolbar停靠到MainFrame上。然后还是需要映射的OnCommand和OnUpdateaXXXXUI. 这样的方式我没有深加分析。但是首先一个很大的问题就是,你必须要求插件开发人员使用跟主程序使用一样的MFC。不然嘿嘿。。。另外本人非常讨厌使用动态链接地MFC库。

我们的需求是这样的,主程序需要能显示插件中的toolbar。toolbar的功能属于插件本身。toolbar的按钮是不是灰化由插件自己控制。toolbar的响应也由插件自己完成。最重要的是我们不对插件地开发使用MFC还是Win32做任何假设。

Step 1。 我们做一个类,对插件中的Toolbar对象做一下描述,这些描述应该包含:插件的HINSTANCE,ResourceID 和Toolbar的名字。 然后插件把这个类注册到主程序中。主程序根据这个Toolbar描述在需要的时候才去创建这个Toobar(CMFCToolbar)----比如用户的配置文件指定了需要显示这个Toolbar的时候。

Step 2. 做完第一步。Toolbar就可以动态加载显示了。接下来我们需要映射Toolbar的命令。我们可以这样做,在插件对象描述中,我们加入以下信息:Toolbar Command起始ID,和按钮个数,然后我们约定插件中的Command ID起始Number,在主程序的MainFrm中映射OnPlugubCommandRange OnUpdatgePlugubCommandRangeUI。然后在响应的函数中,根据ID来寻找所有插件Toolbar的信息。如果id在该toolbar的 [StartID , StarID+Command Number) 区间里,那么该命令就是属于整个Toolbar的,要响应?哈哈,不会还不知道吧?给Toolbar的对象描述加个Callback就可以了。插件设定这个Callback.....

Step 3. 以上两步看来是解决所有问题了....但是等等,插件一多,Toolbar的Command ID要是重复了怎么办?Command ID在编辑时候不连续怎么办? 我们有一个狠招,在注册Toolbar之前,我们动态修改在内存中Toolbar的Resource。Toolbar的Resource在内存中是这么定义的:

 struct CToolBarData
 {
  WORD wVersion;
  WORD wWidth;
  WORD wHeight;
  WORD wItemCount;
  WORD items[1];
 };


        items是个变长数组,有几个item,长度就是多少,保存的就是你每个Command ID。我们可以FindResource后锁定Reousrce然后把这个items里的内容改了就可以了。哪么我们怎么选择起始的Command ID呢?我们给主程序加个ID Manager,每次Toolbar创建时候,就申请ID。这样ID就永远不会重复了。修改完ID,我们就不能用你自己在资源文件中定义的ID了。怎么办呢?还不简单,把原先的ID保存起来啊。Callback响应的时候,做个映射就可以了。嘿嘿。

以下是修改Resource ID的代码

void ProcessToolbarID(int startID)
{
    m_startID = startID;
    struct CToolBarData
    {
        WORD wVersion;
        WORD wWidth;
        WORD wHeight;
        WORD wItemCount;
        WORD items[1];
    };
   HINSTANCE hOldDll = AfxGetResourceHandle();
    AfxSetResourceHandle(m_hDll);

    LPCTSTR lpszResourceName = MAKEINTRESOURCE( m_ResID );
    ENSURE(lpszResourceName != NULL);
   // determine location of the bitmap in resource fork:
    HINSTANCE hInst = AfxFindResourceHandle(lpszResourceName, RT_TOOLBAR);
    HRSRC hRsrc = ::FindResource(hInst, lpszResourceName, RT_TOOLBAR);
    if (hRsrc == NULL)
        goto EXIT_SET;

    HGLOBAL hGlobal = LoadResource(hInst, hRsrc);
    if (hGlobal == NULL)
        goto EXIT_SET;

    CToolBarData* pData = (CToolBarData*)LockResource(hGlobal);
    if (pData == NULL)
        goto EXIT_SET;
    ASSERT(pData->wVersion == 1);

    //开始分配Toolbar新的ID;
    m_nButton = pData->wItemCount;
    if(m_startID == -1)
    {
        m_startID = GetMedusaEditor()->GetUI()->AllocUIID( m_nButton );
    }
    m_OriginBtnIDs = new int[m_nButton];
    for(int i = 0 ;i < pData->wItemCount ; i ++)
    {
        //保存原始ID
        m_OriginBtnIDs[i] = pData->items[i];
        pData->items[i] = i + m_startID;
    }
    UnlockResource(hGlobal);
EXIT_SET: 
    FreeResource(hGlobal);
    AfxSetResourceHandle(hOldDll);
    return ;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值