• 将Excel嵌入你的.Net程序-使用dsoFramer (转载)


     

       使用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就可以好好的控制了,最主要的是, 如果你想增加什么新的东西,出现什么问题就可以自己调试解决了。

    如果你要在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;
     }
    }

    版权说明

      如果标题未标有<转载、转>等字则属于作者原创,欢迎转载,其版权归作者和博客园共有。
      作      者:温景良
      文章出处:http://wenjl520.cnblogs.com/  或  http://www.cnblogs.com/

  • 相关阅读:
    记忆化搜索——luogu滑雪
    如何解决mysql stop fail的问题
    顶级工程师谈机遇、谈跳槽、谈选择
    向周鸿祎学习产品和产品推销方法
    几个概念:x86、x86-64和IA-32、IA-64
    split函数的实现
    谈谈c++中继承中的虚函数
    c++ 编译期与运行期
    读<<大数据时代>>的一些感想
    size_t与size_type的使用
  • 原文地址:https://www.cnblogs.com/wenjl520/p/1362459.html
Copyright © 2020-2023  润新知