如果用外嵌的方式(打开并控制一个WORD进程),也就是用下面的代码:
   _Application app;
   app.m_bAutoRelease=true;   COleVariant covTrue((short)TRUE),
               covFalse((short)FALSE),
               covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
   
   //打开一个word文档
   if (!app.CreateDispatch("Word.Application"))
      {
         AfxMessageBox("创建MS-WORD服务失败!");
         return ;
      }
    app.SetVisible(TRUE); 
    Documents docs(app.GetDocuments());
    _Document mydoc;    mydoc.AttachDispatch(docs.Open(COleVariant(savefile,VT_BSTR),covFalse, 
covFalse,   
                             covFalse,covOptional, covOptional,covFalse, 
covOptional, 
                             covOptional, covOptional,covOptional, 
covTrue)); // Close AttachDispatch(…)
    这样就可以成功的打开一个WORD文档文件,但是如果采用内嵌的方法(把WORD的Document嵌入到自己程序中),也就是用下面这样的代码:
   LPDISPATCH lpDisp; 
   lpDisp = m_pSelection->GetIDispatch();    Documents docs;
   _Application app; 
   _Document mydoc;
   
   mydoc.AttachDispatch(lpDisp);
   app.AttachDispatch(mydoc.GetApplication());  
   docs.AttachDispatch(app.GetDocuments());
  
   COleVariant covTrue((short)TRUE),
   covFalse((short)FALSE),
   covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);    mydoc.AttachDispatch(docs.Open(COleVariant(savefile, VT_BSTR), covFalse, covFalse, covFalse, covOptional, covOptional, covFalse, covOptional, covOptional, covOptional, covOptional, covTrue));
   这样的话,试图打开WORD文档的时候就会提示“Open方法或属性因这篇文档在另一应用程序中而无效”而失败。
   请问为什么会这样?除了改用外嵌的方式之外,有解决方法吗?因为外嵌的方式下不容易修改WORD界面的菜单和图标,所以不太希望采用外嵌的方式。

解决方案 »

  1.   

    在实现OLE对象的包容时,仅仅需要实现5个接口,如果更加苛刻一些,甚至可以只实现3个,我摘录一段我写的东西如下:
    ========================================
    做为OLE包容必须实现的接口有3个,分别是IOleClientSite、IAdviseSink、IOleInPlaceSite,以下分别来介绍。(由于每一个接口都是从IUnknown继承,因此IUnknown的方法实现在介绍时略去)IOleClientSite接口用来为OLE对象提供一个启动时的“站点”接口,主要用来为OLE对象提供窗口位置、用户界面、资源、名字服务的信息,OLE对象在启动时需要查询和调用这个接口来安排自身事务。每一个OLE对象都需要对应有一个IOleClientSite接口,因此如果在应用程序中同时启动多个OLE对象,他们必须共享或者独立拥有一个IOleClientSite接口。IOleClientSite包含了方法SaveObject、GetMoniker、GetContainer、ShowObject、OnShowWindow、RequestNewObjectLayout(关于具体的说明读者可以参看MSDN,在此不一一讨论,下同)。其中仅仅有SaveObject方法比较重要,需要实现,其他方法均可简单返回(返回S_OK值)或者声明为未实现(返回E_NOTIMPL值)。IAdviseSink接口用来使得包容可以在OLE对象的数据改变、试图改变、文档改变时有机会响应。需要注意的是,IAdviseSink接口的方法被OLE对象调用时都是同步的,因此如果包容在响应这些调用时耗费过长的时间(例如大规模的计算),会造成用户界面“僵死”现象。IAdviseSink包含了方法OnDataChange、OnViewChange、OnRename、OnSave、OnClose。实现时按照需要实现,甚至全部可以简单返回。另外一点需要注意的是,OLE对象不会主动的获取包容的IAdviseSink接口,因此我们必须通过在创建OLE对象后,调用OLE对象IOleObject接口的Advise方法来向对象“注册”这个接口。IOleInPlaceSite接口从IOleWindow接口继承而来,用来在OLE包容和OLE对象之间维持一种互相联系,例如OLE对象可以从OLE包容获得上下文窗口位置的信息,OLE包容也可以在OLE对象实地激活时获得通知以做出相应的安排。IOleInPlaceSite包含了方法GetWindow、ContextSensitiveHelp(这两个方法是从IOleWindow继承而来)、IOleInPlaceSite、CanInPlaceActivate、OnInPlaceActivate OnUIActivate、GetWindowContext、Scroll、OnUIDeactivate、OnInPlaceDeactivate、DiscardUndoState、DeactivateAndUndo、OnPosRectChange。一般而言,比较重要的是:GetWindowContext,OLE对象可以在此获得OLE包容的一些设定信息,以作自身响应;GetWindow,OLE对象需要在这里获得母窗口句柄;OnUIActive、OnUIDeactive、OnInPlaceActive、OnInPlaceDeactive、DeactiveAndUndo,这些都是OLE对象在试图变化时的一些通知函数,OLE包容需要在这时为OLE对象安排好诸如菜单等等资源的协调,以及调用OLE对象做复合文档的永久化、回复等等,都是比较简单的实现。其他的接口函数均可按需要实现,否则简单返回即可。以上就是实现OLE包容必须实现的三个接口,而且不是所有的接口都必须完全实现,依靠现在这些知识我们已经可以自行实现一个简单的包容器了。但是这时还仅仅是最简单的实现,我们还不能安排OLE对象的实地激活,OLE对象的菜单工具条插入,我们还需要讨论两个接口来完善我们的OLE包容器。注意的一点,这并不是必须的,尤其是在实现某些轻量级的OLE包容时。第一个接口是IOleInPlaceFrame,这个接口是做为OLE包容器最高层框架窗口实现的一个接口,用来在框架窗口中合并OLE对象的菜单、工具条,显示OLE对象状态,并可以向OLE包容传递键盘消息,再由OLE包容向OLE对象传送,以实现某些热键。IOleInPlaceFrame同时继承了IOleInPlaceUIWindow接口,IOleInPlaceUIWindow接口又继承了IOleWindow接口,因此实际上我们在实现这个接口时需要实现4个接口的方法(包含IUnknown)。这些方法是:GetWindow、ContextSensitiveHelp、GetBorder、RequestBorderSpace、SetBorderSpace、 SetActiveObject、InsertMenus、SetMenu、RemoveMenus、SetStatusText、EnableModeless 、TranslateAccelerator(未包含IUnknown的三个方法)。实现时同样不比完全实现,按照需要实现就可以了,不实现的或者简单返回,或者返回未实现。在本文后面的例子中,选择实现了ContextSensitiveHelp(安排OLE对象显示右键菜单)、GetBorder(安排OLE对象获得母窗口的边界)、SetBorderSpace(安排OLE对象的边界)、SetActiveObject(为母窗口记录下激活的OLE对象)、InsertMenus(合并菜单)、SetMenu (设置菜单)、RemoveMenus(消除菜单)、TranslateAccelerator(向OLE对象传递热键)。第二个接口是IOleDocumentSite,这个接口是的OLE中的复合文档对象可以被实地激活,然后显示工具条,标尺之类的用户界面元素。这个接口仅有一个方法ActivateMe,但是却十分重要。ActiveMe接受一个参数IOleDocumentView *pView,这个参数是欲激活的OLE对象的接口,我们可以借此接口查询到OLE对象的IOleDocument接口,然后调用其方法CreateView建立起OLE对象自身的视图,接下来调用IOleDocumentView的方法SetInPlaceSite向OLE对象“注册”OLE包容的IOleInPlaceSite接口。接下来顺次调用IOleDocumentView的UIAcitve、SetRect、Show三个方法激活用户界面元素、安排好OLE视图位置、最后使之显示出来。
    |———————————————————|
    |          Leon Studio                 |
    |______________________________________|
      

  2.   

    谢谢lins(*无间行者*)的回复,可是我不明白你帖这段文章的用意?这可以解决我遇到的这个问题吗?
      

  3.   

    我也在考虑这个问题,还没答案,所以只能up,up,uup!