在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 ; } 

你可能感兴趣的:(toolbar)