关于GetActiveObject失败的灵异现象的解决

2024-04-29 14:48

本文主要是介绍关于GetActiveObject失败的灵异现象的解决,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

最近做一个WORD AUTOMATION的程序,封装成DLL来实现WORD的自动化。开始进行的很顺利,在中文系统下没有任何问题,可是当拿到俄文系统时,问题出现了。而且出现得很是灵异。现象是,当把程序做成EXE时,没有任何问题,封装成DLL时,GetActiveObject就取不到活动的WORD文档了。反复测试发现了非常非常灵异的情况,就是当打开两个以上的文档时,GetActiveObject就可用。这个问题困扰了我好几天,真是百思不解呀。GOOGLE,百度,CSDN,MSDN,国内外的资料翻了个遍,也没找到原因。受了几天的折磨,就在快要放弃的时候,突然峰回路转,在MS support网站上找到了原因。苍天呀,原来是被微软给玩了一把。不过也怪自己,这遍文章之前找资料的时候也曾经见到过,只是当时看的不是特别认真,以为自己遇到的问题不是一回事,结果在这个问题上浪费了很多的时间。

这个故事告诉我们,一定要坚持,更一定要认真~~~~~~

我的代码:

CLSID clsid;
HRESULT hr;
hr=::CLSIDFromProgID(L"Word.Application",&clsid);
if(FAILED(hr))
{
   AfxMessageBox(_T("NO OFFICE"));
   return;
}

IUnknown *pUnknown=NULL;
IDispatch *pDispatch=NULL;
_Application app=NULL;
Selection sel=NULL;

hr=::GetActiveObject(clsid,NULL,&pUnknown); //在俄文系统不可用
if(FAILED(hr))
{
   AfxMessageBox(_T("NO WORD"));
   return;
}

       下面是微软给出的原因:Although the Office application is running, it might not be registered in the Running Object Table (ROT). A running instance of an Office application must be registered in the ROT before it can be attached to using GetObject (Visual Basic) or GetActiveObject (Visual C++).

When an Office application starts, it does not immediately register its running objects. This optimizes the application's startup process. Instead of registering at startup, an Office application registers its running objects in the ROT once it loses focus. Therefore, if you attempt to use GetObject or GetActiveObject to attach to a running instance of an Office application before the application has lost focus, you might receive one of the errors above.

         简单的说就是,MS对OFFICE的启动进行了优化以提高OFFICE的启动速度(不过不知道为什么没有对中文OFFICE进行优化),即不是OFFICE一启动就在ROT表进行注册,而是在OFFICE失去一次焦点之后,才进行注册。这就是我遇到的为什么只有在打开两个以上的WORD文档时GetActiveObject才能取到。实际情况不是非要打开两个以上的文档,只要使打开的WORD文档失去一次焦点就可以了,即不让它激活,也就是WORD文档窗变成灰的,或是说让WORD不在最前面(我也不知道严格讲应该怎样表达),就相当于你打开一个WORD文档,然后用鼠标点一下其他的窗口。不知道这么说够不够通俗易懂。这样,OFFICE就会去ROT进行注册,你的GetActiveObject也就能取到了。就可以进行下面的工作了。呵呵。

       MS给出的解决方案:

Workaround for C++
If you are programming in C++, the following code sample demonstrates a similar workaround to that shown in the above Visual Basic sample. Notice that SetForegroundWindow is used to move focus away from Excel, allowing it to register its running objects.


//Store the handle of the currently active window...
HWND hwndCurrent = ::GetForegroundWindow();

//Launch Excel and wait until it is waiting for
//user input...
STARTUPINFO Start;
PROCESS_INFORMATION ProcInfo;
ZeroMemory(&Start,sizeof(STARTUPINFO));
Start.cb=sizeof(Start);
Start.dwFlags = STARTF_USESHOWWINDOW;
Start.wShowWindow = SW_SHOWMINIMIZED;

//Change the path to Excel as needed...
LPSTR pszExcelPath =
      "c:\\program files\\microsoft office\\office\\excel.exe";

::CreateProcess(NULL, pszExcelPath, 0, 0, 1,
       NORMAL_PRIORITY_CLASS, 0, NULL, &Start, &ProcInfo);

if((::WaitForInputIdle(ProcInfo.hProcess, 10000))==WAIT_TIMEOUT)
{
    ::MessageBox(NULL, "Timed out waiting for Excel.", NULL, 
                 MB_OK);
}

//Restore the active window to the foreground...
//  NOTE: If you comment out this line, the code will fail!
::SetForegroundWindow(hwndCurrent);

//Initialize COM library...
::CoInitialize(NULL);

//Attach to the running instance...
CLSID clsid;
CLSIDFromProgID(L"Excel.Application", &clsid); 
IUnknown *pUnk = NULL;
IDispatch *pDisp = NULL;

for(int i=1;i<=5;i++) //try attaching for up to 5 attempts
{
   HRESULT hr = GetActiveObject(clsid, NULL, (IUnknown**)&pUnk);
   if(SUCCEEDED(hr))
   {
       hr = pUnk->QueryInterface(IID_IDispatch, (void **)&pDisp);
       break;
   }
   ::Sleep(1000);
}
       
if (!pDisp) {
    ::MessageBox(NULL, "Failed to find instance!!", "Error",
                 MB_ICONHAND);
}
else {
    ::MessageBox(NULL, "Got instance of Excel!", "Success", MB_OK);
}

//Release the no-longer-needed IUnknown...
if (pUnk)
    pUnk->Release();

//... Add your automation code for Excel here ...

//Release pDisp when no longer needed...
if (pDisp)
    pDisp->Release();

//Cleanup COM...
CoUninitialize();
具体原因就看下面吧:
http://support.microsoft.com/kb/238610/en-us/
 

 

这篇关于关于GetActiveObject失败的灵异现象的解决的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/946389

相关文章

springboot3.0+继续使用springboot2.0配置会显示 `无法自动装配,找不到对应的Bean`解决方法

在 Spring Boot 3.0 中,Spring 团队对自动配置机制进行了重大变更,特别是 spring.factories 文件。spring.factories 文件已被 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件所取代。在springboot3.0+继续使用spri

ChannelSftp.put后流不关闭? ChannelSftp.put资源被占用?图片删除失败、图片删除被占用

文章目录 一、问题描述二、问题原因及解决方法 一、问题描述 在一次项目需求中需要将原图片下载到本地后旋转90度再上传到服务器上。但是在这个过程中代码抛错了。 代码步骤及部分逻辑如下: 1.下载原文件 2.生成一个新文件 File newFile = new File("aa.jpg");3.图片旋转,并将旋转后的内容写入到新图片中4.图片上传到服务器中public v

子容器启动失败See section 8.2.2 2c of the Servlet specification for details. Consider using absolute orderi

子容器启动失败See section 8.2.2 2c of the Servlet specification for details. Consider using absolute ordering. 如果出现这种错误 找到项目的web.xml文件,然后在 <display-name>xxxxxxx</display-name> 标签下加一句代码,如下 <absolute-orde

git 问题解决笔记

最近办公电脑坏了送去返修 申请了一个备用机 然后忘记了coding.net的密码 重新改了密码 电脑修好之后发现自己本来的项目拉不了代码了 如下 remote: CODING 提示: Authentication failed. remote: 认证失败,请确认您输入了正确的账号密码。 fatal: Authentication failed 解决方案如下: 1.执行一下代码  git c

CogVLM 本地部署体验(问题解决)docker容器版

硬件要求(模型推理): INT4 : RTX30901,显存24GB,内存32GB,系统盘200GB INT4 : RTX40901或RTX3090*2,显存24GB,内存32GB,系统盘200GB 模型微调硬件要求更高。一般不建议个人用户环境使用 如果要运行官方web界面streamlit run composite_demo/main.py 显存需要40G以上,至少需两张RTX3090显卡。

myEclipse打开jsp 页面卡的解决方法

二、 要么采取一劳永逸的方法 Window -》 Preferences -》 General -》 Editors -》 File Associations,将默认打*.jsp的editor关联设置为MyEclipse JSP Editor 。

openGauss一主两备集群异常断电后不能正常启动的解决过程简记

背景 因异常断电后opengauss 5.0.0版本,一主两备集群启动失败。 报错不是主机,由于当时没有截图,查看日志后发现报错是: 定位过程 Day1 1. 尝试用另外两台机器启动每台机器 发现都报错自己不是主机,像极了唐僧被妖怪抓走后互相帅锅的猴子哥仨。 2.手动启动 于是向openGauss交流群里的大佬求助,@半夏提供了一个手动启动的命令。 gs_ctl start

关于用ajax 乱码的问题的解决;

后来整合 了一个项目; 前台jsp是gbk; 后台 java 也是gbk;  但是在    response.setContentType("text/html;charset=UTF-8");response.setCharacterEncoding("UTF-8");用于前台获取json 数据; 但是总是乱码;  后来在jsp 向 后台java 提交数据的时候用了 url : "saveSt

get 方式请求乱码以及用Jquery ajax 乱码问题的解决;

先说用jquery ajax 乱码问题 的解决:  jsp:     var planname=        encodeURIComponent($("#planname").val()); $.ajax({         type: 'post',         url: '/exam2/exportPlanExcelAction.action',

线上问题的解决思路

上周接了一个任务,处理线上的一个bug,看似简单的问题,如何快速的定位解决是很考验人的时刻。线上问题如下: 线上大部分的数据是没有问题的,只有这一组数据出现了问题,so,问题的关键就在于如何定位了,接下来便是深入基层,从页面开始查看调用了那个方法,之后进入业务端代码,真正的大戏开始了,如果是新手对业务和代码都不熟悉,这会是一个很煎熬的时刻(自己就是这样的……)。所以你就必须一