关于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

相关文章

JAVA Calendar设置上个月时,日期不存在或错误提示问题及解决

《JAVACalendar设置上个月时,日期不存在或错误提示问题及解决》在使用Java的Calendar类设置上个月的日期时,如果遇到不存在的日期(如4月31日),默认会自动调整到下个月的相应日期(... 目录Java Calendar设置上个月时,日期不存在或错误提示java进行日期计算时如果出现不存在的

Nginx错误拦截转发 error_page的问题解决

《Nginx错误拦截转发error_page的问题解决》Nginx通过配置错误页面和请求处理机制,可以在请求失败时展示自定义错误页面,提升用户体验,下面就来介绍一下Nginx错误拦截转发error_... 目录1. 准备自定义错误页面2. 配置 Nginx 错误页面基础配置示例:3. 关键配置说明4. 生效

Java调用DeepSeek API的8个高频坑与解决方法

《Java调用DeepSeekAPI的8个高频坑与解决方法》现在大模型开发特别火,DeepSeek因为中文理解好、反应快、还便宜,不少Java开发者都用它,本文整理了最常踩的8个坑,希望对... 目录引言一、坑 1:Token 过期未处理,鉴权异常引发服务中断问题本质典型错误代码解决方案:实现 Token

springboot3.x使用@NacosValue无法获取配置信息的解决过程

《springboot3.x使用@NacosValue无法获取配置信息的解决过程》在SpringBoot3.x中升级Nacos依赖后,使用@NacosValue无法动态获取配置,通过引入SpringC... 目录一、python问题描述二、解决方案总结一、问题描述springboot从2android.x

解决idea启动项目报错java: OutOfMemoryError: insufficient memory

《解决idea启动项目报错java:OutOfMemoryError:insufficientmemory》:本文主要介绍解决idea启动项目报错java:OutOfMemoryError... 目录原因:解决:总结 原因:在Java中遇到OutOfMemoryError: insufficient me

maven异常Invalid bound statement(not found)的问题解决

《maven异常Invalidboundstatement(notfound)的问题解决》本文详细介绍了Maven项目中常见的Invalidboundstatement异常及其解决方案,文中通过... 目录Maven异常:Invalid bound statement (not found) 详解问题描述可

SpringBoot项目整合Netty启动失败的常见错误总结

《SpringBoot项目整合Netty启动失败的常见错误总结》本文总结了SpringBoot集成Netty时常见的8类问题及解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参... 目录一、端口冲突问题1. Tomcat与Netty端口冲突二、主线程被阻塞问题1. Netty启动阻

SpringBoot整合Kafka启动失败的常见错误问题总结(推荐)

《SpringBoot整合Kafka启动失败的常见错误问题总结(推荐)》本文总结了SpringBoot项目整合Kafka启动失败的常见错误,包括Kafka服务器连接问题、序列化配置错误、依赖配置问题、... 目录一、Kafka服务器连接问题1. Kafka服务器无法连接2. 开发环境与生产环境网络不通二、序

nacos服务无法注册到nacos服务中心问题及解决

《nacos服务无法注册到nacos服务中心问题及解决》本文详细描述了在Linux服务器上使用Tomcat启动Java程序时,服务无法注册到Nacos的排查过程,通过一系列排查步骤,发现问题出在Tom... 目录简介依赖异常情况排查断点调试原因解决NacosRegisterOnWar结果总结简介1、程序在

解决java.util.RandomAccessSubList cannot be cast to java.util.ArrayList错误的问题

《解决java.util.RandomAccessSubListcannotbecasttojava.util.ArrayList错误的问题》当你尝试将RandomAccessSubList... 目录Java.util.RandomAccessSubList cannot be cast to java.