注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

水滴石穿

破浪是阵风!

 
 
 

日志

 
 

将Excel嵌入你的.Net程序2-使用dsoFramer  

2008-04-10 17:56:44|  分类: 软件开发技术资料 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

使用AxWebBrowser或者WebBrowser的方法将Office嵌入我们的.Net系统问题有几个,1是WebBrowser控件是一个比较重的控件,2是通过WebBrowser去控制Office如果出现问题没有办法进行调试与判断,也无法修改,3是Office对应的菜单没有办法控制。为此我们决定需求新的解决方案,使用微软提供的dsoFramer控件例子,这个例子使用VC++编写,本身是可以使用的,可以参见:

   http://support.microsoft.com/default.aspx?scid=kb;en-us;311765

在这里下载dsoFramer的源码

http://www.microsoft.com/downloads/details.aspx?familyid=CE2CA4FD-2169-4FAC-82AF-770AA9B60D77&displaylang=en

下面进行我们的改造过程

1.使用VisualStudio2005打开该VC工程,按系统提示进行转换

2.转换完成后,发现该控件缺少OLB文件,这个文件是控件的对象库,在引用该控件的时候要用到,编译该对象库需要mktyplib.exe但该工具在VS2005中已经不再提供,使用MIDL代替,但MIDL又不支持这种转换过来的工程,没想到第一步就遇到了挫折,为此想了很多办法,后来从 VS2003中找到旧的mktyplib.exe,拷入VS2005\common\tools\bin下面,呵呵可以了,(这个应该算VS2005的一个Bug吧)

3.编译好ocx,通过Regsvr32 注册到系统中

4.创建一个C#工程,引入刚才的ocx

5.发现该控件,自带了菜单,工具栏,并且我们基本不能控制该控件,晕倒

6.决定自己将它的菜单栏放到我们的.Net  Form上,发现不能将 C++的菜单直接放过来,C++的有太多的控制了,如果要重写这些控制,就要吐血了,并且发现新的MenuStrip控件根本就不是一个菜单,传入C++后,不认识。费了好大的劲,将Form的MainMenu给传了进去,呵呵,这下行了,看看运行的效果:

将Excel嵌入你的.Net程序2-使用dsoFramer - 王欢 - 水滴石穿

怎么样,感觉还不错吧,现在这个Excel就可以好好的控制了,最主要的是, 如果你想增加什么新的东西,出现什么问题就可以自己调试解决了。

如果你要在OCX中增加接口,你必须同时修改三个地方,一个是ODL,OCX的接口定义文件,并且按照规范,一个是你的控件实现的对应的.H文件,一个实现的.CPP文件,这些都简单了。

6.菜单出来了,发现不能控制,又再次晕倒,不知所措了

解决办法,是通过OVerride窗体的WndProc方法,将菜单的事件,除了你自己的菜单以外的,都给传到OCX中。

在OCX中增加一个接口方法:ExecuteMenuMessage,它直接调用OnMenuMessage,呵呵,这样就行了,代码如下:

        protected override void WndProc(ref Message m)

        {

            IntPtr  lWParam=IntPtr.Zero  ;

            switch (m.Msg)

            {

                case WindowsMessages.WM_INITMENU :

                case WindowsMessages.WM_ENTERIDLE:

                case WindowsMessages.WM_MENUSELECT:

                case WindowsMessages.WM_INITMENUPOPUP:

                case WindowsMessages.WM_COMMAND :                 

                    ExecuteMenuMessage(m.Msg, m.WParam, m.LParam);

                    //Console.Write(m.Msg.ToString("X"));

                    //Console.Write("    ");

                    //Console.Write(lWParam.ToString("X"));

                    //Console.Write("    ");

                    //Console.WriteLine(m.LParam.ToString("X"));

                    break;               

            }

       

             base.WndProc(ref m);      

        }

   现在菜单信息也传入了,哦,创建菜单的程序如下,酷吧:

   private void Form1_Load(object sender, EventArgs e)

        {

            //if (this.Menu == null)

            {

                this.Menu = new MainMenu();

                CreateFileMenu();

                IntPtr hMainMenu = this.Menu.Handle;

                this.axFramerControl1.MainFormMenu = hMainMenu;

                this.axFramerControl1.MainForm = this.Handle;

            }

        } 

       

     

        private void CreateFileMenu()

        {

            IntPtr pFileMenu = MenuHelper.CreatePopupMenu();

            MenuHelper.AppendMenu(pFileMenu, MenuFlags.MF_STRING, FrameMenuMessage.MNU_NEW, "新建(&N)...\tCtrl+N");

            MenuHelper.AppendMenu(pFileMenu, MenuFlags.MF_STRING, FrameMenuMessage.MNU_OPEN, "打开(&O)...\tCtrl+O");

            MenuHelper.AppendMenu(pFileMenu, MenuFlags.MF_STRING, FrameMenuMessage.MNU_CLOSE, "关闭(&C)");

            MenuHelper.AppendMenu(pFileMenu, MenuFlags.MF_SEPARATOR, 0, string.Empty);

            MenuHelper.AppendMenu(pFileMenu, MenuFlags.MF_STRING, FrameMenuMessage.MNU_SAVE, "保存(&S)\tCtrl+S");

            MenuHelper.AppendMenu(pFileMenu, MenuFlags.MF_STRING, FrameMenuMessage.MNU_SAVEAS, "另存为(&A)...");

            MenuHelper.AppendMenu(pFileMenu, MenuFlags.MF_SEPARATOR, 0, string.Empty);

            MenuHelper.AppendMenu(pFileMenu, MenuFlags.MF_STRING, FrameMenuMessage.MNU_PGSETUP, "页面设置(&U)...");

            MenuHelper.AppendMenu(pFileMenu, MenuFlags.MF_STRING, FrameMenuMessage.MNU_PRINTPV, "打印预览(&V)");

            MenuHelper.AppendMenu(pFileMenu, MenuFlags.MF_STRING, FrameMenuMessage.MNU_PRINT, "打印(&P)...");

            MenuHelper.AppendMenu(pFileMenu, MenuFlags.MF_SEPARATOR, 0, string.Empty);

            MenuHelper.AppendMenu(pFileMenu, MenuFlags.MF_STRING, FrameMenuMessage.MNU_PROPS, "属性(&I)");

            MenuHelper.AppendMenu(this.Menu.Handle, MenuFlags.MF_BYPOSITION | MenuFlags.MF_POPUP, (uint)pFileMenu.ToInt32() , "文件(&F)");

            MenuHelper.DrawMenuBar(this.Handle);

        }

7.当关闭Excel后会怎么样,靠,菜单还在,并且每个都报错,肯定报错,OLE已经卸载了,只好跑去修改OCX控件中docObject的ClearMergeMenu,让它清除掉Excel的菜单,明白原理就简单了。

////////////////////////////////////////////////////////////////////////

// CDsoDocObject::ClearMergedMenu (protected)

//

//  Frees the merged menu set by host.

//

STDMETHODIMP_(void) CDsoDocObject::ClearMergedMenu()

 if (m_hMenuMerged)

 {

        int cbMenuCnt = GetMenuItemCount(m_hMenuMerged);

  int iMainMenuCnt=0;

  if(this->m_hMenuMainForm)

   iMainMenuCnt=GetMenuItemCount(m_hMenuMainForm);

  for (int i = cbMenuCnt-1; i >0; --i)

  {

   if(this->m_hMenuMainForm)

   {

    RemoveMenu(m_hMenuMainForm,--iMainMenuCnt,MF_BYPOSITION);

   }

   RemoveMenu(m_hMenuMerged, i, MF_BYPOSITION);

  }

  if(m_hwndMainForm)

   DrawMenuBar(m_hwndMainForm);

  DestroyMenu(m_hMenuMerged);

  m_hMenuMerged = NULL;

 }

}

 

还有一些遗留问题:

   1.菜单合并时候,可以指定位置,这样有利于我们控制,这个暂时没做。

   2.文件菜单中,当Excel卸载后,文件菜单的部分不能自动置为灰色的,这里还没搞清楚是什么原因

  评论这张
 
阅读(635)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017